适用于学习了TIM输出比较(PWM)跟GPIO输入(按键)的新手作为练习的综合项目!
一、PWM的概念
PWM(Pulse Width Modulation,脉冲宽度调制)是一种常用的技术,用于通过调节电信号的脉冲宽度(即脉冲的持续时间)来控制模拟系统的电源。在数字电子系统中,由于只能输出固定的高(通常为 Vcc)或低(通常为 GND)电平,PWM 提供了一种有效的方法来模拟模拟信号。
1.原理
PWM 信号是一种方波,其基本特征是频率和占空比。频率决定了脉冲重复的速度,而占空比是指在一个脉冲周期内,信号为高电平的时间占整个周期的比例。
2.CRR
在 PWM 生成中,CRR 通常用于设置 PWM 的占空比。定时器的总周期由其自身的计数器决定,而 CRR 决定了在这个周期内何时切换输出状态。例如,如果定时器在达到其最大计数值时重置,并且 CRR 设置为这个最大值的一部分,那么输出信号将在计数器值达到 CRR 时切换,从而产生 PWM 信号。
举例
假设一个定时器的计数范围是 0 到 1000(即它的 ARR,自动重载寄存器,设置为 1000)。如果您将 CRR 设置为 500,那么在定时器计数到 500 时会发生一些预设动作(例如,在 PWM 应用中,输出信号可能会从高变低)。这将产生一个 50% 占空比的 PWM 信号。
3.占空比
占空比是 PWM 最重要的特征之一。例如,如果一个 PWM 信号的周期为 10ms,而高电平持续 2ms,则占空比为 20%。调节占空比可以改变平均电压,这是 PWM 控制的基础。
4.应用
电机控制:通过调节占空比,可以精确控制电机的速度。
LED 亮度调节:通过改变驱动 LED 的 PWM 信号的占空比,可以调节 LED 的亮度。
模拟信号生成:通过改变 PWM 信号的平均电压,可以模拟出模拟信号。
电源管理:在开关电源中,PWM 用于控制电源的输出电压。
5.优点
高效率:在高或低电平时,电路中的能量损失较小。
控制精度高:可以非常精确地控制能量输出。
实现简单:在数字电子中易于实现,广泛用于微控制器和其他电子设备。
总而言之,PWM 是一种在数字控制环境中实现有效模拟控制的重要技术,广泛应用于各种电子和电气系统中。
二、PWM常用的函数
1.HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);//使能PWM
2.__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,5000);//修改pulse(CRR)
3.__HAL_TIM_SET_AUTORELOAD(&htim3,10000-1);//修改arr
注:主函数里修改高级定时器的ARR会出现没有效果,需要在cubemx中使能ARR预装载寄存器
4.__HAL_TIM_SET_PRESCALER(&htim3, 50-1);//修改psc
三、配置STM32cubeMX
将TIM2的时钟源设置为内部时钟,选择 “PWM Generation CH4”。将PSC设为80,ARR设为20000,CRR(pulse)设为500。
"PWM Generation CH4"指的是配置定时器(Timer)的第 4 通道(Channel 4)用于产生脉冲宽度调制(PWM)信号。
溢出频率=80M/80/20000=50HZ
溢出时间为1/50=0.02s=20ms
所以就产生了一个周期为20ms的方波,因为ARR设置为20000,所以在一个周期为20ms的时间内计数20000
20000对应20ms,CCR设为500即对应的就是0.5ms,所以高电平在一个周期内持续的时长为0.5ms,占空比=CRR/ARR=500/20000=2.5%。
根据 SG90舵机对应的控制关系(见四、SG90舵机),CCR为500时,转动的角度为0°
设置CCR为500的目的就是让转动的角度初始化为0°
四、SG90舵机
SG90 舵机是一种广泛使用的小型伺服电机,它因其成本效益高、体积小巧以及简单的控制方式而受到业余爱好者和教育领域的青睐。以下是 SG90 舵机的基本介绍:
1.基本特性
尺寸和重量:大约 23mm x 12.2mm x 29mm,重量大约 9 克。
电源要求:通常工作在 4.8V 至 6V 的电压范围内。
转动范围:提供大约 180 度的转动范围。
力矩:在 4.8V 至 6V 的电压下,力矩大约在 1.2 - 1.6 kg·cm。
控制方式:使用标准的脉宽调制(PWM)信号进行控制。
2.接线介绍
SG90 舵机通常有三根线:
橙色/黄色线:控制线(PWM信号线)。这根线连接到微控制器(如 Arduino)的数字输出引脚,用于传输控制信号。
红色线:电源线(正极)。这根线连接到电源的正极,通常是 4.8V 至 6V。本项目中是接5V槽口就可以了
棕色/黑色线:接地线(负极)。这根线连接到电源的负极和微控制器的接地。
3.SG90舵机对应的控制关系
高电平宽度——角度——CRR——占空比
五、代码实现
实现效果:每按一次按键B1, 舵机就会旋转30°,直至旋转到180°。大于180°就会重新从零开始。
1.在/* USER CODE BEGIN 0 /与/ USER CODE END 0 */之间增加如下代码
void Servo_SetAngle(float Angle)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_4,Angle / 180 * 2000 + 500);
}
int KeyNum=0;
上述代码是用来设置旋转的角度
0° 对应的是 CRR 500
…
…
…
180°对应的是 CRR 2500
所以根据二元一次方程可求得CRR=(Angle / 180) * 2000 + 500
__HAL_TIM_SetCompare();这个函数就是用来设置CRR(pluse)的
2.在key.c中添加如下代码
int Key_GetNum(void)
{
uint8_t KeyNum=0;
if (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==RESET)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==RESET);
HAL_Delay(20);
KeyNum = 1;
}
if (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==RESET)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==RESET);
HAL_Delay(20);
KeyNum = 2;
}
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==RESET)//B3按下为低电平
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==RESET);
HAL_Delay(20);
KeyNum = 3;
}
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==RESET)//B4按下为低电平
{
HAL_Delay(20);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==RESET);
HAL_Delay(20);
KeyNum = 4;
}
return KeyNum;
}
3.在key.h中添加如下代码;
int Key_GetNum(void);
4.在main.c中的int main(void)函数添加如下代码
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
uint8_t Angle=0;
char angle[50];
5.在while(1)中添加如下代码
KeyNum=Key_GetNum();
if(KeyNum==1)
{
Angle+=30;
if (Angle > 180)
{
Angle = 0;
}
Servo_SetAngle(Angle);
sprintf(angle,"angle:%d",Angle);
LCD_DisplayStringLine(Line5,(uint8_t*)angle);
}
六、遇到的问题
1.如果转动的角度大于180度,则重新回到0度后,在屏幕上显示的是“angle:080”,而正确的显示应该是“angle:0”,这是什么原因呢?
经过查阅资料跟测试我得到了答案
LCD 显示函数的行为:LCD_DisplayStringLine ()这个函数不会自动清除之前显示的内容。如果新的字符串比之前的短,它只会覆盖相应的字符数,而不是整行。
解决方案:
方法 1 - 清除 LCD 行: 在每次调用 LCD_DisplayStringLine 之前,先发送一个空字符串或足够长的空格字符串来清除之前的内容。
LCD_DisplayStringLine(Line5, (uint8_t*)" "); // 清除旧内容
KeyNum=Key_GetNum();
if(KeyNum==1)
{
Angle+=30;
if (Angle > 180)
{
Angle = 0;
}
Servo_SetAngle(Angle);
LCD_DisplayStringLine(Line5, (uint8_t*)" "); // 清除旧内容
sprintf(angle,"angle:%d",Angle);
LCD_DisplayStringLine(Line5,(uint8_t*)angle);
}
方法 2 - 清屏(清除整页): 在每次调用 LCD_DisplayStringLine 之前,使用这行代码:
LCD_Clear(Black); //清屏
方法 3 - 填充空格: 修改 sprintf 使用固定宽度并右对齐,保证生成的字符串总是具有相同的长度。
sprintf(angle, “%3d”, Angle); // 右对齐,总宽度为3
KeyNum=Key_GetNum();
if(KeyNum==1)
{
Angle+=30;
if (Angle > 180)
{
Angle = 0;
}
Servo_SetAngle(Angle);
// LCD_DisplayStringLine(Line5, (uint8_t*)" "); // 清除旧内容
sprintf(angle, "angle:%3d", Angle); // 右对齐,总宽度为3
LCD_DisplayStringLine(Line5,(uint8_t*)angle);
}
2.如果写从第六个字符开始显示的话,则
LCD_DisplayStringLine(Line5,(uint8_t*)angle+6);
3.将电源线插在3v3槽口中,为什么PWM波无法控制SG90舵机的驱动呢?
SG90 舵机通常需要 4.8V 至 6V 的电压才能正常工作。3.3V 的电压不足以激活舵机的内部电路,导致无法正常响应 PWM 信号。文章来源:https://www.toymoban.com/news/detail-810723.html
解决方案:
将电源线插到5V的槽口就行了文章来源地址https://www.toymoban.com/news/detail-810723.html
到了这里,关于蓝桥杯STM32 G431 hal库开发速成——按键+PWM综合案例——按键控制PWM驱动舵机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!