【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
所谓的pwm,其实就是方波。我们都知道,对于一个电机来说,如果插上正负极的话,那么电机就会全速运转。但是,有的时候我们希望对速度进行控制,那么这个时候pwm就派上用场了。pwm的基本原理比较简单,它就是按照频率,把信号拆分成一段一段的输出。在每一段信号当中,有的时候输出为1,有的时候输出为0,如果1的比例越大,那说明现在上位机希望进行加速处理;反之1的比例越小,就说明这个时候希望的操作,是对电机进行减速处理。实际操作中,一般mcu和电机之间有一个驱动器,我们通过pwm控制驱动器,就可以实现对电机的控制了。
因为没有电机,所以这次我们希望用pwm实现一个呼吸灯的效果。所谓的呼吸灯,就是一开始led越来越亮,接着就是越来越暗,周而复始。因为手边h750开发板上led灯损坏,这一次就用了stm32f103c8t6做了代替测试,基本原理是一样的。
1、硬件搭建
之前的led连接的是pc13,我们这里是利用tim对pa0进行控制的。所以,我们所要做的就是把pa0和pc13短接在一起就好了。
2、初始化pwm
目前stm32系列的mcu都是通过tim定时器来实现pwm输出的,pwm从哪个gpio输出,这个也是要通过芯片手册提前设计好的。大部分代码内容都是差不多的,大家可以把重点放在pin脚、周期设定、分频等重要参数的设置上。
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 200 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
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; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
3、设置空占比
空占比,也就是有效信号占单个周期信号的比例,这个数值非常重要。大家使用的时候需要注意下。
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
4、实现呼吸灯效果
正如之前所示,呼吸灯就是一个pwm空占比从低到高、再从高到底的一个过程。做好了这一点,基本上就实现了呼吸灯的效果。
while (1)
{
for (i = 0; i <= 200; i++)
{
PWM_SetCompare1(i);
Delay_ms(10);
}
for (i = 0; i <= 200; i++)
{
PWM_SetCompare1(200 - i);
Delay_ms(10);
}
}
5、TIM定时器的另有一个用法-编码器
在stm32 mcu上面一般有两种定时器。一种是系统定时器systick,一般用作系统中断使用,类似于给rtos做1ms中断使用;还有一种就是tim。tim有普通定时器和高精度定时器。不过用的比较多的场景,就是用tim定时器实现pwm输出,以及实现电机编码器的读取。
有了电机编码器相当于就有了一个反馈信号,我们通过这个编码器就可以算出电机的当前速度。借助于这个反馈量,就可以提示我们下一步是提高pwm空占比,还是降低pwm空占比,这样才能达到最终的控制速度。
6、测试和验证
因为暂时手上没有示波器,所以只能通过led灯的明暗程度,来粗略判断下当前pwm是不是真的有效果。这一点和之前ad/da测试有点像,当时也是只能定性地去分析驱动设置有没有发生作用。如果要真正地看输出信号是否准确,归根到底还是要通过示波器等精密一点的设备去进行连接和判断。
注:
实验过程中发生一个有趣的现象,那就是用st-link v2烧入低功耗程序之后,st-link v2就没有办法烧录了,一直提示“internal command error”。但是长按reset又可以识别mcu,有点奇怪。直到boot和3.3v用短接帽短接后,重新st-link v2连接才能烧入。