速通蓝桥杯嵌入式省一教程:(六)PWM输出

定时器除了用于最基本的定时器计时中断以外,还可以用于输出PWM(Pulse Width Modulation)波,即脉冲宽度调制波形,也就是频率与占空比均可改变的矩形波。下面我们就使用PA1端口生成PWM波。

在Cube中,首先需要将PA1设置成定时器的通道,在这里我们选择TIM2的CH2(CHANNEL2)(注:CH后带N的意思是输出与不带N的波形反相):

速通蓝桥杯嵌入式省一教程:(六)PWM输出_第1张图片

接着,我们要到定时器中进行设置:

速通蓝桥杯嵌入式省一教程:(六)PWM输出_第2张图片

将定时器的时钟频率设置为80MHz后,这样设置得到的定时器频率(计算公式见第三节)为80,000,000/(100*200)=4kHz,而所得PWM波的频率与定时器频率一致,为4kHz。因此,我们可以通过改变时钟频率、Prescaler(分频系数)、Counter Period(计数周期,也叫AutoReload重装载值)来改变PWM波的频率。而PWM波的占空比为Pulse(也叫Compare比较值)/(Counter Period+1)(AutoReload重装载值),故通过改变比较值重装载值就可以改变PWM波的占空比为方便计算,我们通常将重装载值设置为100-1(或200-1),这样比较值(或Pulse)的值(或除以2)即为PWM波的占空比。

完成在Cube中的设置之后,在程序的初始化部分只需要开启PWM波的输出:

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);    //开启TIM2的CH2输出PWM

这样就可以在PA1通道输出频率为4kHz、占空比为10%的PWM波啦!

HAL_TIM_PWM_Start函数的声明如下:

/**
  * @brief  Starts the PWM signal generation.
  * @param  htim TIM handle
  * @param  Channel TIM Channels to be enabled
  *          This parameter can be one of the following values:
  *            @arg TIM_CHANNEL_1: TIM Channel 1 selected
  *            @arg TIM_CHANNEL_2: TIM Channel 2 selected
  *            @arg TIM_CHANNEL_3: TIM Channel 3 selected
  *            @arg TIM_CHANNEL_4: TIM Channel 4 selected
  *            @arg TIM_CHANNEL_5: TIM Channel 5 selected
  *            @arg TIM_CHANNEL_6: TIM Channel 6 selected
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);

若想要在后续改变输出PWM波的频率与占空比,需要用到这两个宏定义:

pa1_autoreload = 100-1;

__HAL_TIM_SetAutoreload(&htim2, pa1_autoreload);
//修改重装载值为100-1,此时频率为80,000,000/(100*100)=8kHz

__HAL_TIM_SetCompare(&htim2, (pa1_autoreload+1)*0.1);
//因为重装载值改变,若要保持占空比不变,需要同步修改比较值,此时占空比仍为10%

这样就能得到频率为8kHz,占空比为10%的PWM波了。

下面我们以第十四届省赛题为例,总结本节所讲内容:

速通蓝桥杯嵌入式省一教程:(六)PWM输出_第3张图片

把要求简化为固定占空比为50%,根据第五节:交互系统的内容,当在数据界面按下B2时,进行高低频模式的切换。考虑到题目要求在5s内均匀升高或降低频率,而我们是通过改变重装载值的方式来改变频率的,因此频率与我们需要改变的量成反比关系,要求频率均匀变化,重装载值必然不能均匀变化。为尽可能增加精度,预分频系数应该设置得尽量小,使得在频率相同时,重装载值能够尽量大,这样在改变频率时能够改变的重装载值就能分得越精细。因此我们将预分频系数设为1,通过计算可得当频率为4kHz时,重装载值为20000;当频率为8kHz时,重装载值为10000

为满足题目要求在5s内切换到目标频率,步进值小于200Hz的要求,我们选择每100ms改变100Hz:

int pa1_frq = 4000;
double pa1_duty = 0.5;
int pa1_autoreload = 20000;

void change_frq(void)
{
    if (pa1_frq == 4000)
    {
        while (pa1_frq < 8000)
        {
            pa1_frq += 100;
            pa1_autoreload = 80000000/pa1_frq;                          //公式计算重装载值
            __HAL_TIM_SetAutoreload(&htim2, pa1_autoreload);            //改变频率
            __HAL_TIM_SetCompare(&htim2, int(pa1_autoreload*pa1_duty)); //保持占空比不变
            LED_Toggle(LD2);
            HAL_Delay(100);                                             //每100ms改变一次
        }
    }

    else if (pa1_frq == 8000)
    {
        while (pa1_frq > 4000)
        {
            pa1_frq -= 100;
            pa1_autoreload = 80000000/pa1_frq;                          //公式计算重装载值
            __HAL_TIM_SetAutoreload(&htim2, pa1_autoreload);            //改变频率
            __HAL_TIM_SetCompare(&htim2, int(pa1_autoreload*pa1_duty)); //保持占空比不变
            LED_Toggle(LD2);
            HAL_Delay(100);                                             //每100ms改变一次
        }
    }
}

将函数change_frq封装到task库中,并在上一节内容中已经写好的key_pro函数中调用此函数,即可完成按键改变高低频模式的要求。

你可能感兴趣的:(蓝桥杯嵌入式,蓝桥杯,嵌入式硬件,单片机,stm32)