文章目录
定时器编程实战2:通用定时器PWM输出
硬件设计
本实验用到的硬件资源有:
1) 5V直流电机
2)L298N电机驱动模块
3) 定时器 TIM9
TIM9_CH1 可以通过 PA2 输出 PWM,TIM9_CH2 可以通过 PA3 输出 PWM,利用两个PWM控制电机不同速度的正反转。
4)硬件连接方式:
通用定时器输出PWM原理
假设为递增计数模式
ARR:自动重装载寄存器的值
CCRx:捕获/比较寄存器x的值
当CNT < CCRx,GPIO输出0
当CNT >= CCRx,GPIO输出1
CubeMX配置
定时器时钟源频率和上篇一样的配置方法。
在 Pinout->TIM9 配置项中,配置 Channel1 的值为 PWM generation CH1,Channel1 的值为 PWM generation CH1,然后勾选 Internal Clock。如下图
在弹出的界面中点击 Parameter Settings 选项卡,Counter Settings 配置栏下面的四个选项就是用来配置定时器的预分频系数,自动装载值,计数模式以及时钟分频因子。在界面的 PWM Generation Channel1和2 配置栏配置 PWM 模式,比较值,极性等参数,如下图
这里没有使用到中断,所以我们不需要使能中断和配置 NVIC,进行完上面的操作之后,接下来我们便是生成工程代码。
通用定时器PWM输出实验配置步骤
1.配置定时器基础工作参数
这里的代码为CubeMX配置。
//tim.c文件
TIM_HandleTypeDef htim9; //在tim.h文件中定义为extren类型
void MX_TIM9_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0}; //时钟源配置结构体
TIM_OC_InitTypeDef sConfigOC = {0}; //输出比较配置结构体
htim9.Instance = TIM9;
htim9.Init.Prescaler = 959; //PSC分频系数
htim9.Init.CounterMode = TIM_COUNTERMODE_UP; //加法计数模式
htim9.Init.Period = 4999; //ARR自动装载值
htim9.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //时钟分频系数
htim9.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动预装载
if (HAL_TIM_Base_Init(&htim9) != HAL_OK) //定时器基础初始化
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;· //内部时钟源
if (HAL_TIM_ConfigClockSource(&htim9, &sClockSourceConfig) != HAL_OK) //定时器时钟源配置
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim9) != HAL_OK) //定时器PWM初始化
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1; //输出比较模式PWM1
sConfigOC.Pulse = 0; //比较值
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; //输出极性高
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; //快速模式关
if (HAL_TIM_PWM_ConfigChannel(&htim9, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) //定时器PWM配置通道1
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim9, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) //定时器PWM配置通道2
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim9);
}
2.定时器PWM输出MSP初始化
这里的代码为CubeMX配置。
//tim.c
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM9)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM9 GPIO Configuration
PA2 ------> TIM9_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; //PA2为PWM通道1,PA3为通道2
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM9;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
3.使能输出并启动计数器
//tim.c
void MX_TIM9_Init(void)
{
/* MX CODE BEGIN */
//。。。。。。。。。
/* MX CODE BEGIN */
/* USER CODE BEGIN */
//PWM通道使能
HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_1);
/* USER CODE END */
}
4.应用层:main.c
//main.c
int main(void)
{
/* USER CODE BEGIN */
uint8_t dir = 1; //方向
uint8_t duty = 2000; //占空比
/* USER CODE END */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM9_Init();
while (1)
{
/* USER CODE BEGIN */
HAL_Delay(10);
if(dir) duty += 10;
else duty -= 10;
if(duty >= 4000) dir = 0;
if(duty == 0) dir = 1;
if(dir)
{
HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_1); //使能PWM通道1
__HAL_TIM_SET_COMPARE(&htim9, TIM_CHANNEL_1, duty); //设置通道1的比较值(占空比)
HAL_TIM_PWM_Stop(&htim9, TIM_CHANNEL_2); //失能PWM通道2
}
else
{
HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_2);
__HAL_TIM_SET_COMPARE(&htim9, TIM_CHANNEL_2, duty);
HAL_TIM_PWM_Stop(&htim9, TIM_CHANNEL_1);
}
/* USER CODE END */
}
}