蓝桥杯STM32 G431 HAL库开发速成:按键PWM综合案例-按键控制PWM驱动舵机

适用于学习了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 信号。

解决方案:
将电源线插到5V的槽口就行了

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯STM32 G431 HAL库开发速成:按键PWM综合案例-按键控制PWM驱动舵机

发表评论