[应用相关] STM32定时器PWM和SG90舵机

[复制链接]
1046|30
Xiashiqi 发表于 2025-9-4 22:01 | 显示全部楼层 |阅读模式
1:通用PWM原理

PWM, 英文名Pulse width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。PWM的功能有很多种,比如控制呼吸灯、控制直流电机或者舵机等驱动原件等等,是单片机的一个十分重要的功能。

PWM模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx CCRx寄存器确定占空比的信号。其框图如下图所示:

7657068b92e7331ef9.jpg


横坐标是时间变量,纵坐标是CNT计数值,CNT计数值随着时间的推进会不断经历从0到ARR,清零复位再到ARR的这一过程。这之中还有一个数值是CCRX即比较值,通过比较值和输出配置可以使之输出高低电平逻辑,.这样就产生了PWM波形。通过调节ARR的值可以调节PWM的周期,调节CCRX的值大小可以调节PWM占空比。

自我理解(ARR用来控制周期和频率,CCRx(寄存器值也是比较值)用来确定占空比)

2:PWM的功能要使用通用定时器或者高级定时器

3:PWM模式

PWM模式一 (TIM_OCMode_PWM1)
工作特性:
向上计数模式:

CNT < CCRx:通道输出有效电平

CNT ≥ CCRx:通道输出无效电平

向下计数模式:

CNT > CCRx:通道输出无效电平

CNT ≤ CCRx:通道输出有效电平

PWM模式二 (TIM_OCMode_PWM2)
工作特性:
向上计数模式:

CNT < CCRx:通道输出无效电平

CNT ≥ CCRx:通道输出有效电平

向下计数模式:

CNT > CCRx:通道输出有效电平

CNT ≤ CCRx:通道输出无效电平

关键区别对比

7477768b92e6cebc4d.png


在向上计数模式中:PWM模式1和模式2的定义和区别,可以简单理解为:PWM模式1的情况下,当前值小于比较值为有效电平;PWM模式2的情况下,当前值大于比较值为有效电平。有效电平为高为低需要配置

4:定时器PWM库函数的配置

这是 STM32 定时器输出比较(Output Compare)功能的配置结构体,用于设置 PWM 输出特性。下面逐项解释每个成员:

1. TIM_OCMode (输出比较模式)



uint16_t TIM_OCMode;
功能:设置定时器的输出比较工作模式

可选值:

TIM_OCMode_Timing:定时模式(仅触发中断/DMA)

TIM_OCMode_Active:匹配时设置有效电平

TIM_OCMode_Inactive:匹配时设置无效电平

TIM_OCMode_Toggle:匹配时电平翻转

TIM_OCMode_PWM1:PWM 模式 1(常用)

TIM_OCMode_PWM2:PWM 模式 2

示例:TIM_OCMode_PWM1

2. TIM_OutputState (主通道输出状态)



uint16_t TIM_OutputState;
功能:使能/禁用主输出通道(如 TIMx_CH1)

可选值:

TIM_OutputState_Enable:使能输出

TIM_OutputState_Disable:禁用输出

示例:TIM_OutputState_Enable

3. TIM_OutputNState (互补通道输出状态)



uint16_t TIM_OutputNState;
功能:使能/禁用互补输出通道(如 TIMx_CH1N)

特殊说明:仅高级定时器 TIM1/TIM8 有效

可选值:

TIM_OutputNState_Enable:使能互补输出

TIM_OutputNState_Disable:禁用互补输出

示例:TIM_OutputNState_Disable

4. TIM_Pulse (脉冲宽度值)



uint16_t TIM_Pulse;
功能:设置捕获/比较寄存器的值(CCRx)

范围:0x0000 - 0xFFFF(0-65535)

作用:决定 PWM 占空比

计算:占空比 = TIM_Pulse / (TIM_Period + 1)

示例:1500(1.5ms 脉宽)

5. TIM_OCPolarity (主通道输出极性)



uint16_t TIM_OCPolarity;
功能:设置主通道输出极性

可选值:

TIM_OCPolarity_High:高电平有效

TIM_OCPolarity_Low:低电平有效

示例:TIM_OCPolarity_High(舵机常用)

6. TIM_OCNPolarity (互补通道输出极性)



uint16_t TIM_OCNPolarity;
功能:设置互补通道输出极性

特殊说明:仅高级定时器 TIM1/TIM8 有效

可选值:

TIM_OCNPolarity_High:高电平有效

TIM_OCNPolarity_Low:低电平有效

示例:TIM_OCNPolarity_Low

7. TIM_OCIdleState (主通道空闲状态)



uint16_t TIM_OCIdleState;
功能:定时器空闲时(未启动)主通道的输出电平

特殊说明:仅高级定时器 TIM1/TIM8 有效

可选值:

TIM_OCIdleState_Set:输出高电平

TIM_OCIdleState_Reset:输出低电平

示例:TIM_OCIdleState_Reset

8. TIM_OCNIdleState (互补通道空闲状态)



uint16_t TIM_OCNIdleState;
功能:定时器空闲时互补通道的输出电平

特殊说明:仅高级定时器 TIM1/TIM8 有效

可选值:

TIM_OCNIdleState_Set:输出高电平

TIM_OCNIdleState_Reset:输出低电平

示例:TIM_OCNIdleState_Set

相关函数说明
1. 设置比较值函数



void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare2);
功能:动态改变 PWM 占空比

参数:

TIMx:定时器名称(如 TIM3)

Compare2:写入 CCR2 寄存器的值

使用场景:舵机角度控制、LED 调光

示例:TIM_SetCompare2(TIM3, 1500);

2. 使能输出比较预装载



void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
功能:启用/禁用 CCR2 寄存器的预装载

参数:

TIM_OCPreload_Enable:启用预装载(推荐)

TIM_OCPreload_Disable:禁用预装载

作用:避免 PWM 波形出现毛刺

示例:TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

3. 使能自动重装载预装载



void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
功能:启用/禁用 ARR 寄存器的预装载

作用:同步更新周期和占空比

示例:TIM_ARRPreloadConfig(TIM3, ENABLE);

配置示例(舵机控制)
c

TIM_OCInitTypeDef oc;
oc.TIM_OCMode = TIM_OCMode_PWM1;          // PWM模式1
oc.TIM_OutputState = TIM_OutputState_Enable; // 使能主通道
oc.TIM_Pulse = 1500;                      // 1.5ms脉宽
oc.TIM_OCPolarity = TIM_OCPolarity_High;  // 高电平有效

TIM_OC2Init(TIM3, &oc);                   // 初始化通道2
TIM_OC2PreloadConfig(TIM3, ENABLE);       // 使能预装载
TIM_ARRPreloadConfig(TIM3, ENABLE);       // 使能ARR预装载
TIM_Cmd(TIM3, ENABLE);                    // 启动定时器


PWM周期固定不变,不需要ARR预装载

如果您需要动态改变PWM周期(不仅仅是占空比),就需要启用ARR预装载:




关键提示:通用定时器(TIM2-TIM5)只需关注 TIM_OCMode, TIM_OutputState, TIM_Pulse, TIM_OCPolarity 四个成员。高级定时器(TIM1/TIM8)才需要配置互补通道相关参数。

一般我们在写舵机函数我们会设置比较值函数用来动态改变 PWM 占空比所以 TIM_Pulse可以先不配置。

SG90舵机
一、SG90舵机工作原理核心
PWM信号控制:舵机通过20ms周期(50Hz)的PWM脉冲宽度确定角度

脉冲宽度与角度关系:

0.5ms脉冲 → 0°

1.5ms脉冲 → 90°

2.5ms脉冲 → 180°

闭环控制系统:内部电位器实时反馈位置,电机驱动系统自动修正角度误差

脉冲宽度计算(极性为低时的反向逻辑):

5502268b92d87d543e.png


注意:代码使用TIM_OCPolarity_Low(低有效),实际脉冲宽度 = 周期时间 - (比较值 × 计数时间)

三、舵机引脚连接

3734468b92d769e9ed.png


四、控制方法详解
硬件连接要求:

必须使用外部5V电源(STM32的5V引脚电流不足)

外部电源GND必须与STM32共地

信号线直接连接PB5(已配置为TIM3_CH2输出)

角度控制调用:




SG90_Run(90);  // 转动到90°位置
脉冲精度调整:

修改TIM_SetCompare2()参数可微调角度

公式:比较值 = 200 - (期望脉冲宽度 / 0.1ms)

例:1.5ms脉冲 → 200 - 15 = 185

控制舵机配置步骤

·使能定时器和相关IO时钟
初始化IO为复用模式
· 初始化定时器
· 初始化输出比较参数                                                                                                                       
·使能预装载寄存器                                                                                                                              
·使能定时器
·改变比较值CCRx,达到不同的占空比效果

sg90.c

#include "stm32f10x.h"
#include "sg90.h"

void SG90_Init(void)
{
        GPIO_InitTypeDef GPIO_Initstruct;
        TIM_TimeBaseInitTypeDef TIM_Initstruct;
        TIM_OCInitTypeDef TIM_OCInitstruct;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
       
        GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//部分重映射
       
        GPIO_Initstruct.GPIO_Pin=GPIO_Pin_5;
        GPIO_Initstruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_Initstruct.GPIO_Speed=GPIO_Speed_10MHz;
        GPIO_Init(GPIOB,&GPIO_Initstruct);
       
       
        TIM_Initstruct.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_Initstruct.TIM_CounterMode=TIM_CounterMode_Up;
        TIM_Initstruct.TIM_Period=200-1;
        TIM_Initstruct.TIM_Prescaler=7200-1;
        TIM_Initstruct.TIM_RepetitionCounter=0;
        TIM_TimeBaseInit( TIM3, &TIM_Initstruct);
//        TIM_Cmd( TIM3, ENABLE);//放早了
       
       
       
        TIM_OCInitstruct.TIM_OCMode=TIM_OCMode_PWM1;
        TIM_OCInitstruct.TIM_OCPolarity=TIM_OCPolarity_Low;
        TIM_OCInitstruct.TIM_OutputState=TIM_OutputState_Enable;//关注N
        TIM_OC2Init(TIM3,&TIM_OCInitstruct);
        TIM_OC2PreloadConfig( TIM3,  TIM_OCPreload_Enable);//
        TIM_Cmd( TIM3, ENABLE);
       
       
       


}

void SG90_Run(uint16_t angle)
{
        switch(angle)
        {
                case 180: TIM_SetCompare2( TIM3, 175);break;
                case 135: TIM_SetCompare2( TIM3, 180);break;
                case 90 : TIM_SetCompare2( TIM3, 185);break;
                case 45 : TIM_SetCompare2( TIM3, 190);break;
                case 0  : TIM_SetCompare2( TIM3, 195);break;
       
       
       
        }





}




sg90.h

#ifndef SG90_H_
#define SG90_H_


void SG90_Init(void);
void SG90_Run(uint16_t angle);


#endif






main.c

#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "Bear.h"
#include "key.h"
#include "relay.h"
#include "shake.h"
#include "wireless.h"
#include "exti_key.h"
#include "usart.h"
#include "stdio.h"
#include "Tim.h"
#include "sg90.h"

void delay(uint16_t time)//延时1ms  软件延时粗延时
{
        uint16_t i=0;
        while(time --)
        {
                i=12000;
                while(i --);
        }
       
}


int  main()
{

        SG90_Init();

   while(1)
         {

                SG90_Run(135);
                 delay (1000);
                 SG90_Run(0);
                 delay (1000);
                 
         }
                 
               
}




关键区别总结

3263268b92d32a1f21.png


————————————————
版权声明:本文为CSDN博主「Do vis824」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2402_88972815/article/details/149549448

bestwell 发表于 2025-9-21 12:29 | 显示全部楼层
PWM 信号线远离大电流回路              
sdlls 发表于 2025-9-21 12:57 | 显示全部楼层
STM32控制SG90舵机的核心是​​生成符合要求的PWM信号​​
uytyu 发表于 2025-9-21 13:15 | 显示全部楼层
舵机使用5V独立供电,并检查PWM信号频率和脉宽是否正确。
sdCAD 发表于 2025-9-21 14:52 | 显示全部楼层
可通过​​线性插值​​实现渐变              
bartonalfred 发表于 2025-9-21 15:19 | 显示全部楼层
可选双向 TVS 用于静电防护。
maqianqu 发表于 2025-9-21 15:50 | 显示全部楼层
超出范围可能失控或损坏舵机              
hudi008 发表于 2025-9-21 16:33 | 显示全部楼层
舵机剧烈抖动无法定位              
mickit 发表于 2025-9-21 17:56 | 显示全部楼层
使用单个定时器控制多个舵机,可通过​​动态修改比较值​​实现
jtracy3 发表于 2025-9-21 19:04 | 显示全部楼层
在舵机电源输入端串联二极管(如1N4007),防止反接损坏电路。
mmbs 发表于 2025-9-21 19:53 | 显示全部楼层
SG90舵机通常使用50Hz的PWM信号,即每20毫秒一个周期。
hilahope 发表于 2025-9-21 20:29 | 显示全部楼层
SG90舵机需要频率为50Hz 的PWM信号。
adolphcocker 发表于 2025-9-21 20:49 | 显示全部楼层
防止反向电动势击穿电路。              
cashrwood 发表于 2025-9-21 21:13 | 显示全部楼层
避免 PWM 频率抖动              
ingramward 发表于 2025-9-21 21:46 | 显示全部楼层
舵机角度变化时,若PWM占空比突变会导致抖动。
jkl21 发表于 2025-9-21 22:26 | 显示全部楼层
信号隔离与保护              
bestwell 发表于 2025-9-22 12:52 | 显示全部楼层
SG90舵机的角度控制通过改变PWM信号的占空比实现。
jtracy3 发表于 2025-9-22 13:40 | 显示全部楼层
PWM信号线远离噪声源,必要时使用屏蔽线。
nomomy 发表于 2025-9-22 14:46 | 显示全部楼层
信号走线尽量短于 20cm,避免干扰。
qiufengsd 发表于 2025-9-22 15:14 | 显示全部楼层
舵机启动时的电流冲击可能导致 STM32 供电电压跌落,需在 STM32 电源端加 100μF 电容稳压,或分离供电。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

85

主题

250

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部