第六章第四节 PWM驱动LED呼吸灯 PWM驱动舵机 PWM驱动直流电机
1. PWM 驱动 LED 呼吸灯
① Keil 中常见的英文注释
Specifies the output polarity.
This parameter can be a value of @ref TIM_Output_Compare_Polarity
- 整句翻译:指定输出极性。此参数可以是 @ref TIM_Output_Compare_Polarity 中定义的一个值。
- Specifies :动词,意为 “指定;规定;明确说明” ,在这里表示对 “输出极性” 进行设定操作。
- the output polarity :名词短语,“输出极性” ,指的是 PWM(脉冲宽度调制)等信号输出时的电平极性相关属性,比如是高电平有效还是低电平有效。
- This parameter :“此参数;这个参数” ,指代用于设置输出极性的参数
② 核心原理:利用PWM 极性驱动,通过占空比变化控制 LED 亮度渐变,模拟呼吸效果。高电平点亮、低电平熄灭,占空比越高(高电平占比大 ),LED 越亮;占空比越低,LED 越暗 。
③ 函数:
(1) 用结构体初始化输出比较单元:
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
- TIM_OC1Init ()、TIM_OC2Init ()、TIM_OC3Init ()、TIM_OC4Init () 这四个函数为同类型通道初始化函数,核心功能与参数结构完全一致,仅操作的定时器通道不同(对应通道 1-4)。
(2) 单独更改 CCR 寄存器值的函数:
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
- 作用:直接修改定时器
TIMx
的通道 1~4 对应的比较寄存器(CCR)值,控制 PWM 占空比或比较触发时机。
④ PWM.c 模块
(1) 有效电平 = "正在充电" 的状态:
- 当充电器正在给手机供电时(比如线里有电流),就像 PWM 的 "有效电平"—— 这是有实际作用的状态。
- 在代码里,我们需要指定 "有效电平是高电平还是低电平",就像规定 "有电流 = 正在充电" 还是 "没电流 = 正在充电"。
(2) 无效电平 = "停止充电" 的状态:
- 当充电器停止供电时(比如线里没电流),就像 PWM 的 "无效电平"—— 这是不发挥作用的状态。
- 它和有效电平总是相反的:如果有效是 "有电流",无效就是 "没电流"。
(3) 极性 = 定义 "什么是有效"
- 极性就像充电的 "判断标准":
- 选
TIM_OCPolarity_High
(高电平有效):相当于规定 "线里有电流 = 正在充电(有效)" - 选
TIM_OCPolarity_Low
(低电平有效):相当于规定 "线里没电流 = 正在充电(有效)"
- 选
(4) PWM 输出比较配置
TIM_OCInitTypeDef TIM_OCInitStructure;
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;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OCStructInit
:给输出比较结构体赋默认值,方便后续只修改需要的参数,避免未初始化成员出问题 。TIM_OCMode
:输出比较模式,TIM_OCMode_PWM1
是 PWM 模式 1。工作逻辑:当定时器计数值小于TIM_Pulse
时,输出有效电平(由TIM_OCPolarity
决定);计数值大于等于TIM_Pulse
时,输出无效电平 。TIM_OCPolarity
:输出极性,TIM_OCPolarity_High
表示有效电平为高电平,即满足计数值条件时,引脚输出高电平,反之低电平 。TIM_OutputState
:输出使能,TIM_OutputState_Enable
开启输出比较功能,让定时器能通过引脚输出电平变化 。TIM_Pulse
:比较值(对应 CCR 寄存器值),决定 PWM 占空比。初始设为 0,意味着占空比为 0%(计数值小于 0 不成立,一直输出无效电平 ),后续可通过PWM_SetCompare1
函数修改 。
2. PWM 驱动舵机
① Servo.c 模块:
#include "stm32f10x.h"
#include "PWM.h" // 依赖 PWM.c 的功能// 舵机初始化:直接调用 PWM_Init() 复用底层配置
void Servo_Init(void)
{PWM_Init();
}// 设置舵机角度:将角度转换为 PWM 占空比
void Servo_SetAngle(float Angle)
{// 角度 → 占空比映射:// 0° → 500(对应 0.5ms 高电平),180° → 2500(对应 2.5ms 高电平)// 公式:Compare = Angle/180 * 2000 + 500 PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
(1) 角度映射逻辑
- 舵机控制要求:
0.5ms
高电平 → 0°,2.5ms
高电平 → 180°(不同舵机可能有差异,需校准) - 占空比计算:
- 总有效范围:
2500 - 500 = 2000
(对应 180° 角度差) - 公式推导:
Compare = 500 + (Angle / 180) * 2000
- 总有效范围:
② main.c 模块
int main(void)
{// 初始化 OLED 显示屏,执行完后 OLED 可以开始工作,比如显示内容OLED_Init(); // 初始化舵机,让舵机进入可控制状态,准备接收角度控制指令Servo_Init(); // 初始化按键,配置好按键相关的硬件,让程序能正确读取按键状态Key_Init(); // 在 OLED 第 1 行第 1 列的位置显示字符串 “Angle:”,用于提示后面显示的是角度值OLED_ShowString(1, 1, "Angle:"); while (1) // 无限循环,程序会一直执行循环里的内容{// 读取按键编号,Key_GetNum 函数会检测按键状态,返回对应的按键值(比如按下哪个按键)KeyNum = Key_GetNum(); if (KeyNum == 1) // 判断是否是按键 1 被按下{Angle += 30; // 按键 1 按下一次,角度增加 30 度if (Angle > 180) // 因为舵机通常最大角度是 180 度,超过后让角度回到 0 度,实现循环{Angle = 0; }}// 根据 Angle 变量的值设置舵机转动到对应的角度,Servo_SetAngle 函数内部会处理舵机控制的时序等Servo_SetAngle(Angle); // 在 OLED 第 1 行第 7 列的位置显示 Angle 变量的值,显示 3 位数字(比如 000、030、180 等)OLED_ShowNum(1, 7, Angle, 3); }
}
(1) 简单总结程序流程:
- 先初始化 OLED、舵机、按键这些外设,让它们能正常工作。
- 在 OLED 上显示角度提示文字。
- 进入无限循环,不断检测按键状态:
- 若按键 1 按下,角度增加 30 度,超过 180 度就重置为 0 度。
- 然后根据当前角度值控制舵机转动,同时在 OLED 上显示实时的角度数值 。
3. PWM 驱动直流电机
void Motor_SetSpeed(int8_t Speed)
{// 1. 控制电机方向(正转/反转)if (Speed >= 0) {// Speed ≥ 0 → 正转:PA4 高电平,PA5 低电平GPIO_SetBits(GPIOA, GPIO_Pin_4); // PA4 = 1GPIO_ResetBits(GPIOA, GPIO_Pin_5); // PA5 = 0} else {// Speed < 0 → 反转:PA4 低电平,PA5 高电平GPIO_ResetBits(GPIOA, GPIO_Pin_4); // PA4 = 0GPIO_SetBits(GPIOA, GPIO_Pin_5); // PA5 = 1}// 2. 控制电机转速(PWM 占空比)PWM_SetCompare3( Speed >= 0 ? Speed : -Speed ); /* - Speed 是负数时,取绝对值(-Speed),保证占空比为正。- PWM_SetCompare3(xxx):修改定时器的比较寄存器(CCR),直接改变 PWM 占空比 → 电机转速变化。*/
}
① 关键参数解析:
(1) int8_t Speed
:速度控制参数
- 数据类型:
int8_t
(有符号 8 位整数),取值范围为 - 128 至 127 - 符号意义:正号表示正转,负号表示反转
- 绝对值意义:代表 PWM 占空比的大小,决定电机转速(值越大转速越快)
(2) 电机转速控制部分:
// 控制电机转速(PWM占空比)
PWM_SetCompare3( Speed >= 0 ? Speed : -Speed );
- 使用三元运算符获取 Speed 的绝对值(确保占空比为非负数)
- 通过
PWM_SetCompare3()
函数设置定时器的比较寄存器值 - 比较寄存器的值直接决定 PWM 信号的占空比:
- 占空比 = (比较值 / 自动重装载值) × 100%
- 占空比越高,电机获得的平均电压越高,转速越快