一、简介
本例使用STM32F103ZET6,cubeIDE配置产生PWM方波驱动舵机。实现按键的短按单次转动,长按连续转动效果。
常见舵机为三线式舵机:黄色信号输入线;红色电源输入正极;棕色电源输入负极。
常见角度有0-90°、0-180°、0-360°。
舵机通过获取输入的PWM信号线中脉宽即占空比的不同而旋转对应的角度,如果每次发送相同的脉冲,只有在第一次旋转对应角度,后续脉冲不会再使舵机旋转,除非脉宽较上次有变化。舵机驱动脉冲通常周期为20ms,即50Hz。可变化的脉宽长度为0.5 ~ 2.5ms之间,可旋转角度不同与脉宽的对应关系不一定相同。以180°舵机为例,以下为脉宽与旋转角度的对应关系:
脉宽(ms) | 占空比 (%) | 角度(°) |
---|---|---|
0.5 | 2.5 | 0 |
1 | 5 | 45 |
1.5 | 7.5 | 90 |
2 | 10 | 135 |
2.5 | 12.5 | 180 |
二、库函数配置
生成code之前记得在 project manager / code generator / generated files中勾选第一个选项,为每个外设初始化时生成独立的.c/.h文件。
时钟树配置:
定时器配置:
定时器配置和标准库配置相同,名称有些许变更。此时配置的频率为50Hz:
T
(
H
z
)
=
T
I
M
c
l
k
/
((
p
s
c
+
1
)(
a
r
r
+
1
))
.
T(Hz) = TIMclk/((psc+1)(arr+1)).
T(Hz)=TIMclk/((psc+1)(arr+1)).
PWM输出模式:
PWM mode 1: 在向上计数时,当CNT<CCRx时通道x为有效电平,当CNT>CCRx时通道x为无效电平; 在向下计数时,当CNT>CCRx时通道x为无效电平,当CNT<CCRx时通道x为有效电平;
PWM mode 2: 在向上计数时,当CNT<CCRx时通道x为无效电平,当CNT>CCRx时通道x为有效电平; 在向下计数时,当CNT>CCRx时通道x为有效电平,当CNT<CCRx时通道x为无效电平;
三、功能实现
按键短按及长按实现函数使用自锁区分,具体的define中的时长根据实际测试变更。
#define Key_Delay_Time 1000
#define Key_Long_Time 60000
#define Key_Long_Time2 1000
uint8_t KeyNum = 0;
void Key0_Scan(void)
{
static uint8_t Key_Lock_Flag = 0;
static uint16_t Key_Cnt = 0;
static uint16_t Key_Cnt2 = 0;
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 1)//按键0没有按下
{
Key_Lock_Flag = 0;//清零自锁标志
Key_Cnt = 0;//清零计数标志
}
else if(Key_Lock_Flag == 0)
{
Key_Cnt ++;//累计按键消抖延时次数
if(Key_Cnt > Key_Delay_Time)
{
Key_Cnt = 0;//清零计数变量
Key_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
else if(Key_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
{
Key_Cnt ++;//连按超过一定时限,进入连按
}
else
{
Key_Cnt2 ++;//连击时间间隔计数
if(Key_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
{
Key_Cnt2 = 0;//连击时间间隔计数器清零
KeyNum = 2;//与单击相同实现连续单击效果
}
}
}
对KeyNum 进行解析,长按连续每次转动 180 ° / (( 2.5 m s − 0.5 m s ) ∗ ( 50 / 0.5 m s )) = 0.9 ° 180°/((2.5ms-0.5ms)*(50/0.5ms))= 0.9° 180°/((2.5ms−0.5ms)∗(50/0.5ms))=0.9°短按单次转动 5*0.9°。
uint8_t Servo(void)
{
static uint8_t width = 50;
switch(KeyNum)
{
case 1 : width = width + 5;
KeyNum = 0 ;
break;
case 2 : width ++ ;
KeyNum = 0 ;
break;
case 3 : width = width - 5;
KeyNum = 0 ;
break;
case 4 : width -- ;
KeyNum = 0 ;
break;
default: width = width ;
}
if(width > 250)
width = 250;
if(width < 50)
width = 50;
return width;
}
0°时信号波形:
90°时信号波形:
180°时信号波形: