一、定时器PWM配置函数
1. HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
功能:
启动定时器的PWM输出功能。
参数:
htim:定时器句柄指针
Channel:PWM输出通道(TIM_CHANNEL_1~4)
特点:
启动指定通道的PWM信号输出
需要预先配置定时器为PWM模式
计数器开始运行,产生PWM波形
可以单独启动每个通道
2. __HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE)
功能:
设置定时器通道的比较值(捕获/比较寄存器CCR)。
参数:
__HANDLE__:定时器句柄
__CHANNEL__:定时器通道
__COMPARE__:比较值
特点:
这是一个宏定义,直接操作CCR寄存器
用于动态调整PWM占空比
立即生效,无需停止PWM输出
比较值应小于等于自动重装载值(ARR)
二、舵机控制实验
1. 按键原理图

2. 实验现象
通过两个按键控制舵机的转动角度:按下PA0按键时舵机角度增加(脉冲宽度增加500us),按下PC13按键时舵机角度减小(脉冲宽度减少500us)。舵机的控制脉冲宽度在500us到2500us范围内变化,每次按键按下后PWM输出立即更新,并有300ms延时和按键释放检测防止误触发。通过改变TIM3通道3的PWM比较值来精确控制舵机的位置。
3. 示例代码
GPIO初始化
/**
* @brief GPIO初始化函数
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO配置结构体
// 使能GPIO端口时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); // 使能GPIOC时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); // 使能GPIOD时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
// 配置PC13为输入引脚(角度减小按键)
GPIO_InitStruct.Pin = GPIO_PIN_13; // 引脚13
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC13
// 配置PA0为输入引脚(角度增加按键)
GPIO_InitStruct.Pin = GPIO_PIN_0; // 引脚0
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化PA0
}
TIM初始化
/**
* @brief TIM3定时器初始化函数(PWM模式)
*/
void MX_TIM3_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0}; // 主模式配置结构体
TIM_OC_InitTypeDef sConfigOC = {0}; // 输出比较配置结构体
// 定时器基础配置
htim3.Instance = TIM3; // 定时器实例TIM3
htim3.Init.Prescaler = 72-1; // 预分频值71(72分频)
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim3.Init.Period = 20000-1; // 自动重装载值19999(20ms周期)
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频(不分频)
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; // 使能自动重装载预装载
// 初始化定时器PWM模式
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 配置主模式
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; // 主模式触发输出复位
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主从模式
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 配置PWM通道参数
sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
sConfigOC.Pulse = 0; // 初始脉冲宽度为0
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 输出极性高
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 禁用快速模式
// 配置PWM通道3
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 定时器MSP后初始化(通常用于GPIO配置)
HAL_TIM_MspPostInit(&htim3);
}
主函数
// 舵机控制参数定义
#define sg_step 500 // 舵机角度步进值(单位:微秒)
#define sg_min 500 // 舵机最小脉冲宽度(0.5ms)
#define sg_max 2500 // 舵机最大脉冲宽度(2.5ms)
uint16_t sg = 500; // 当前舵机脉冲宽度值
// 系统时钟配置函数声明
void SystemClock_Config(void);
/**
* @brief 应用程序主函数
* @retval int
*/
int main(void)
{
// HAL库初始化
HAL_Init();
// 系统时钟配置
SystemClock_Config();
// 初始化所有配置的外设
MX_GPIO_Init(); // GPIO初始化
MX_TIM3_Init(); // TIM3定时器初始化(PWM模式)
// 启动TIM3通道3的PWM输出
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
// 主循环
while (1)
{
// 检测PA0按键(角度增加)
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
{
// 检查是否超出最大角度限制
if(sg + sg_step <= sg_max)
{
sg += sg_step; // 增加脉冲宽度
}
// 更新PWM比较值(改变舵机角度)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, sg);
HAL_Delay(300); // 延时防抖
// 等待按键释放
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);
}
// 检测PC13按键(角度减小)
if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
{
// 检查是否超出最小角度限制
if(sg - sg_step >= sg_min)
{
sg -= sg_step; // 减小脉冲宽度
}
// 更新PWM比较值(改变舵机角度)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, sg);
HAL_Delay(300); // 延时防抖
// 等待按键释放
while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET);
}
}
}
三、呼吸灯实验
1. LED原理图

2. 实验现象
TIM2定时器的三个PWM通道(2、3、4)同时控制三路LED,通过变量aaa从0到1000循环递增递减,每5毫秒改变一次PWM占空比。LED亮度会平滑地从最暗逐渐增强到最亮,然后再逐渐减弱到最暗,形成同步的呼吸灯效果。
3.示例代码
GPIO初始化
/**
* @brief GPIO初始化函数
*/
void MX_GPIO_Init(void)
{
// 使能GPIO端口时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); // 使能GPIOC时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); // 使能GPIOD时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
}
TIM初始化
/**
* @brief TIM2定时器初始化函数(PWM模式)
*/
void MX_TIM2_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {0}; // 主模式配置结构体
TIM_OC_InitTypeDef sConfigOC = {0}; // 输出比较配置结构体
// 定时器基础配置
htim2.Instance = TIM2; // 定时器实例TIM2
htim2.Init.Prescaler = 72-1; // 预分频值71(72分频)
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
htim2.Init.Period = 1000-1; // 自动重装载值999(PWM周期)
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频(不分频)
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重装载预装载
// 初始化定时器PWM模式
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 配置主模式
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; // 主模式触发输出复位
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主从模式
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 配置PWM通道参数
sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
sConfigOC.Pulse = 0; // 初始脉冲宽度为0
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; // 输出极性低(低电平有效)
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 禁用快速模式
// 配置PWM通道2
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 配置PWM通道3(使用相同参数)
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 配置PWM通道4(使用相同参数)
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler(); // 错误处理
}
// 定时器MSP后初始化(用于GPIO引脚配置)
HAL_TIM_MspPostInit(&htim2);
}
主函数
uint32_t aaa = 0; // PWM占空比控制变量(0-1000范围)
int8_t bbb = 10; // 占空比变化步进值(正负控制增减方向)
// 系统时钟配置函数声明
void SystemClock_Config(void);
/**
* @brief 应用程序主函数
* @retval int
*/
int main(void)
{
// HAL库初始化
HAL_Init();
// 系统时钟配置
SystemClock_Config();
// 初始化所有配置的外设
MX_GPIO_Init(); // GPIO初始化
MX_TIM2_Init(); // TIM2定时器初始化(PWM模式)
// 启动TIM2的三个PWM输出通道
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); // 启动通道2
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); // 启动通道3
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); // 启动通道4
// 主循环
while (1)
{
// 同时设置三个PWM通道的比较值(同步控制三个LED亮度)
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, aaa);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, aaa);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, aaa);
// 更新占空比变量
aaa += bbb;
// 边界检查:达到最大值时改为递减
if(aaa >= 1000)
{
bbb = -10; // 改变方向为递减
}
// 边界检查:达到最小值时改为递增
if(aaa <= 0)
{
bbb = 10; // 改变方向为递增
}
// 延时5ms控制呼吸速度
HAL_Delay(5);
}
}