【TIM/PWM】驱动舵机

用TIM函数配置PWM输出比较模块的函数
TIM_OCxInit();//OC就是Output Compare输出比较
TIM_OCStructInit();//初始化输出比较单元,给输出比较结构体赋一个默认值
TIM_SetCompare1();//单独更改CCR寄存器值的函数,在运行的时候更改占空比
(下面是一些小功能和运行时更改参数的函数)
TIM_ForcedOCxConfig();//配置强制输出模式,在运行中需要暂停输出波形并且强制输出高或低电平
(没啥用,因为强制输出高电平==设置100%占空比,强制输出低电平==设置0%占空比)
TIM_OCxPreloadConfig();//配置CCR寄存器的预装功能(影子寄存器——写入值不会立即生效,而是在更新事件后再生效)
TIM_CtrlPWMOutputs();//仅高级定时器使用,其输出PWM时,需要调用这个函数使能主输出,否则PWM不能正常输出

初始化PWM时从左至右参考该图流程
驱动舵机的关键
  • PWM 频率:  Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM周期对应计数器的一个溢出更新周期——PWM频率等于计数器的更新频率
  • PWM 占空比:  Duty = CCR / (ARR + 1)
  • PWM 分辨率:  Reso = 1 / (ARR + 1)
由图可知周期为20ms,时钟频率为72MHz(默认),分别可以解得PSC、ARR的值及其对应舵机输出轴转角
//PWM频率为【1/20ms=50Hz】
//此处PSC和ARR的值并不固定,可参考设置为【PSC+1】为72,【ARR+1】为20K
  • 重点:此处的CCR不与占空比有关,纯粹就是对舵机ms的表示,例如CCR=500时代表0.5ms,CCR=1000时代表1ms

1、完成驱动文件导入操作和编写驱动程序基本代码(参考之前文章)
//将【PWM】配置文件放在【Hardware】文件夹里
2、在PWM.c中初始化函数 PWM _Init
void PWM_Init(void)
{
//第一步:开启时钟(注意使用APB1的开启时钟函数,因为TIM2是APB1总线的外设)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    
    
//第二步:选择时基单元的时钟(在stm32f10x_tim.h文件中查找函数)
    TIM_InternalClockConfig(TIM2);//这里选择为内部时钟
//时基单元就由内部时钟驱动了
    
    
//第三步:配置时基单元(在stm32f10x_tim.h文件中查找函数)
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//指定时钟分频
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//指定计数器模式(此处选择向上计数)
    TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;//指定要在下一次更新事件时加载到ARR自动重新加载寄存器中的周期值  ARR取值[0,65535]
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;//指定用于划分TIM时钟的预分频器值    PSC取值[0,65535]
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//指定重复计数器的值(高级定时器才用得上,本项目给0)
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//初始化时基单元
//第四步:初始化输出比较单元(通道)【引脚定义表】
//使用PA1口对应第一个输出比较通道
    TIM_OCInitTypeDef TIM_OCInitStructure;
    
//为了避免出现不确定因素,PWM需要先把结构体成员完整配置一遍默认初始值,再根据需要更改个别地方
    TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值
    
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较的模式
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//设置输出比较的极性
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能
    TIM_OCInitStructure.TIM_Pulse = 0;//设置CCR的值
    TIM_OC2Init(TIM2,&TIM_OCInitStructure);
//到此通道初始化完成,可以在TIM2的OC2通道上输出PWM波形
//波形需要借用GPIO口进行输出
//TIM2的OC2的通道借用了PA1【引脚定义表】
//第五步:初始化GPIO口
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
//不需要打开中断和配置NVIC
    
//第六步:启动定时器(在stm32f10x_tim.h文件中查找函数)
    TIM_Cmd(TIM2,ENABLE);
    
//至此PWM波形就能通过PA1输出了
//通过PWM的频率、占空比、分辨率计算公式可以得到ARR、PSC、CCR值
//当PSC=72-1    ARR=20000-1    CCR=1500时
//现象为舵机转到0°位置
}
3、在PWM.c中编写更改CCR函数 PWM_SetCompare2
//在运行过程中更改CCR值(改变占空比)CCR在初始化时为0
void PWM_SetCompare2(uint16_t Compare)//单独更改通道1的CCR值
{
    TIM_SetCompare2(TIM2,Compare);
}
//TIM_SetCompare函数设置的是CCR的值,不代表直接设置占空比,占空比是由【CCR】和【ARR+1】共同决定的
4、在PWM.h中声明初始化函数 PWM _In it更改CCR 函数 PWM_SetCompare2
void PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);
5、在主程序main.c中 #includ "PWM .h "
#include "PWM.h"
6、在主循环之前先初始化PWM
7、在主循环中编写程序主体
int main(void)
{
    PWM_Init();
    OLED_Init();
    
    PWM_SetCompare2(1500);//舵机转到0°
    while(1)
    {
    }
}
实现功能:上电后舵机转到0°

最终目标
一、编写函数,功能为舵机设置角度,参数为0°—180°,可以更直观的调整调度
  • 建立舵机模块完成驱动文件导入操作和编写驱动程序基本代码
//将【Servo】配置文件放在【Hardware】文件夹里
2、在Servo.c中初始化函数 Servo _Init
void Servo_Init(void)
{
    PWM_Init();//将其PWM底层初始化
}
3、在Servo.c中编写更改CCR函数 Servo_SetAngle
/*Angle参数计算
Angle=0°        CRR=500
Angle=180°        CRR=2500
通过一次函数可以得到Angle关系式为:SetAngle=Angle/180*2000+500
也就是用函数设置舵机角度为0°时,给CCR赋值500
                        为180°时,给CCR赋值2500
*/
void Servo_SetAngle(float Angle)
{
    PWM_SetCompare2(Angle/180*2000+500);
}
4、在Servo.h中声明初始化函数 Servo _Init和更改CCR函数 Servo_SetAngle
void Servo_Init(void);
void Servo_SetAngle(float Angle);
5、在主程序main.c中 #includ "Servo .h "(比之前用PWM更加直观,知道用的是什么外设)
#include "Servo.h"
//设置角度全部变量float Angle
float Angle;
6、在主循环之前先初始化Servo
  • 添加按键模块
1)在主程序main.c中 #includ "Key .h "
2)设置键码全局变量 uint8_t KeyNum;
3)初始化按键模块 Key_Init();
7、在主循环中编写程序主体
uint8_t KeyNum;
float Angle;
int main(void)
{
    Servo_Init();
    OLED_Init();
    Key_Init();
    OLED_ShowString(1,1,"Angle:");
    
    while(1)
    {
        KeyNum = Key_GetNum();
        if(KeyNum == 1)
        {
            Angle += 30;
        }
            if(Angle > 180)
            {
                Angle = 0;
            }
            Servo_SetAngle(Angle);
            OLED_ShowNum(1,7,Angle,3);
    }
}
实现功能:上电后OLED显示Angle:000,每按下一次按键角度加30,加到180时返回0角度

### 如何使用PWM信号控制舵机 PWM(Pulse Width Modulation,脉冲宽度调制)是一种常见的技术手段,用于通过改变占空比来调节设备的工作状态。对于舵机而言,其工作原理依赖于接收特定频率和占空比的PWM信号以调整旋转角度。 #### 舵机角度PWM周期关系 舵机通常接受标准的PWM信号作为输入,该信号具有固定的频率(通常是50Hz),而不同的占空比对应着不同的舵机位置。具体来说,舵机的转动范围一般为0°到180°,对应的PWM高电平持续时间为1ms至2ms不等[^2]。例如: - **1ms 高电平时间** 对应 0°; - **1.5ms 高电平时间** 对应 90°(中间位置); - **2ms 高电平时间** 对应 180°。 这种映射关系可以通过软件计得出并设置相应的PWM参数。 #### 初始化PWM模块 为了在STM32微控制器上生成适合舵机使用的PWM波形,需完成如下配置过程: 1. **定时器初始化** 使用TIMx外设生成PWM输出信号。以下是基于HAL库的一个简单示例代码片段: ```c void MX_TIM2_Init(void) { TIM_HandleTypeDef htim2; __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 83; // 设置预分频器值 (假设系统时钟为84MHz, 则计数频率=1MHz) htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 19999; // 自动重装载寄存器ARR设定最大计数值(即周期T=20ms),满足50Hz需求 HAL_TIM_PWM_Init(&htim2); TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 1500; // 默认初始占空比对应中心位置(1.5ms) sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); } ``` 2. **GPIO端口分配** 将指定的GPIO引脚配置成复用功能模式以便连接到上述定时器通道。例如PA0绑定至TIM2_CH1。 3. **动态更新占空比** 当需要更改舵机目标角度θ时,重新计匹配的新比较值CMP,并利用API接口修改之: ```c uint16_t SetServoAngle(float angle){ float pulse_width_ms = ((angle / 180.0) * 1.0 + 1.0)*1000; // 计所需脉宽(ms) return (uint16_t)(pulse_width_ms*1000/(20)); // 转化为相对比例形式 } void UpdateDutyCycle(TIM_HandleTypeDef *htim,uint32_t Channel,float Angle){ uint16_t cmp_val = SetServoAngle(Angle); __HAL_TIM_SET_COMPARE(htim,Channel,cmp_val); } ``` 以上步骤展示了如何构建基本框架从而实现单片机对伺服马达的有效操控[^1]. #### 多路PWM扩展应用 当面对多个独立运作的舵机组件时,则可以考虑采用多通道或者级联方式进一步拓展硬件资源利用率;同时注意避免相互干扰以及合理规划供电线路等问题[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值