(hal库)定时器1输出多路脉冲宽度可变的PWM控制电机(中断方式)
分为以下步骤
/***************************************************************************/
1、stm32cubeMX配置项目参数
2、使用sw4stm32软件编写代码
3、验证
4、总结
/***************************************************************************/
1、stm32cubeMX配置项目参数
stm32cubeMX项目的基本配置请看我的文章,下面只给出定时器1的相关配置。
定时器1的相关配置如下:
这里我是开了2路PWM通道。(一个高级定时器可以开4路通道)
关于预分频数和自动重装值计算我在下方讲述
(图一)
(图二)
以上配置好后,由于我们是用中断的方式去产生PWM脉冲,我们需要在图一中的选项中打开更新中断。如下图所示
预分频数和自动重装值的计算
因为我设置的单片机的hclk频率为72MHz。
假设我要产生频率为500Hz的 PWM脉冲,计数1000产生一个中断。这时我们已经确定了2个值(1个是PWM频率:500Hz,1个是自动重装初值:1000),根据如下公式可得预分频数为144。
所以在图一中定时器配置为:自动重装初值:1000-1:预分频数为144-1
至于为什么要减一,因为它们都是从0开始计数的。
各位想要配置想要的PWM频率可以按照下图公式配置相关参数。
2、使用sw4stm32软件编写代码
我们将生成好的项目导入sw4stm32软件中,**这里我打算输出PWM控制led,实现呼吸灯的效果。 **
在main.c文件中,我们在用户可编辑区域定义pwm占空比变量
uint16_t pwm_val=0; //占空比
uint8_t key = 0;//led灯翻转值
在用户可编辑区域重写定时器1的中断回调函数。这个函数是定时器每次计数达到自动重装初值(999)时,就会产生“更新中断”,然后进入中断回调函数,也就是这个函数中,我们可以在这个函数中编写自己的代码逻辑。
/* USER CODE BEGIN 4 */
//在非阻塞模式下经过一段时间的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if (htim->Instance == TIM1){//判断当前定时器是否为定时器1
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,pwm_val);//设置第一路PWM脉冲宽度
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,(1000-pwm_val));//设置第二路PWM脉冲宽度
/****************
以下是呼吸灯的逻辑代码,由暗变亮时间为2s,然后由亮变暗时间为2s
*****************/
if(pwm_val == 1000)
{
key = 1;
}
if(pwm_val == 0)
{
key = 0;
}
if(key == 0)
{
pwm_val++;
}
else if (key == 1){
pwm_val--;
}
}
}
/* USER CODE END 4 */
3、验证
验证当然是成功的啦,这里由于懒也没把图片放上去。之后我也用示波器看了2路的PWM波形。都是是正常。没有什么异常。
4、总结
该项目只是生成多路相同频率,不同占空比的PWM脉冲。不过对于目前较多驱动来说是足够了,一个高级定时器可以产生4路可变的PWM脉冲,还是很省定时器资源了。
PWM的关键在于回调函数的重写,在里面书写自己的逻辑代码。
理论上来说,定时器在PWM模式下,每次计数都会与你设置的值相比较,当计数值等于你设置的值时,这时单片机会产生一个“捕捉比较中断”。我们应该在这个“捕捉比较中断”中更新我的占空比值(设置的值),这才是比较严谨的逻辑。而不是在每次计数达到自动重装初值后产生的“更新中断”中写。所以我这个算是不够严谨。
但是我一想,无论什么时候更新占空比值,都是给下一个PWM周期的。所以我就在“更新中断”里去写自己的逻辑代码了。
如果要打开“捕捉比较中断”,需要在stm32cubeMX中勾选这个捕获比较中断选项。
最后,如有写错或者各种想法,请说出来,我将及时改正。多多交流。