深入了解STM32定时器原理,掌握脉宽调制pwm生成方法。
一. 使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
二. 接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。
三. 再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。
STM32定时器
STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6),如下图所示:
高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。
定时器工作原理
- PWM
PWM对电脉冲宽度调制,是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
- 机转速的控制
占空比可以实现对电机转速的调节,占空比是高电平在一个周期之中的比值,高电平的所占的比值越大,占空比就越大,对于直流电机来讲,电机输出端引脚是高电平电机就可以转动,当输出端高电平时,电机会转动,但是是一点一点的提速,在高电平突然转向低电平时,电机由于电感有防止电流突变的作用是不会停止的,会保持这原有的转速,以此往复,电机的转速就是周期内输出的平均电压值,所以实质上我们调速是将电机处于一种,似停非停,似全速转动又非全速转动的状态,那么在一个周期的平均速度就是我们占空比调出来的速度了。
一.建立工程模板
在文件夹中复制好需要用到的官方固件库在工程目录下
user文件夹
core文件夹
stm文件夹
设置好project target
在group里面添加我们需要的文件
将工程中引用到的所有头文件的路径都包含进来
PWM即脉冲宽度调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。STM32的定时器除了TIM6与7,其他都可以用来产生PWM输出。
本次实验利用TIM2的CH2产生一路PWM输出要使STM32的通用定时器TIMx产生PWM输出,除了使用寄存器,还需要用到捕获/比较模式寄存器,捕获/比较使能寄存器,捕获/比较寄存器。
- LED周期性亮灭
代码:
在PWM.h处
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
#endif
在PWM.c处
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
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 = 100 - 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);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
最后,在main.c处输入
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init();
while (1)
{
PWM_SetCompare1(0);
Delay_ms(2000);
PWM_SetCompare1(100);
Delay_ms(2000);
}
}
然后进行烧录
- 波形观察
可以看到实际高电平为1.4s左右
- PWM呼吸灯
将上一问中的main.c中代码改成
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init();
while (1)
{
for(i=0;i<=100;i++)
{
PWM_SetCompare1(i);
Delay_ms(10);
}
for(i=0;i<=100;i++)
{
PWM_SetCompare1(100-i);
Delay_ms(10);
}
}
}
然后生成hex文件后再进行烧录
呼吸灯
- 波形
配置debug
将输出的波形图缩小可以观察到高低电平即占空比在不断变化,占空比越大,呼吸灯越亮。
- 总结
通过这次实验我深入理解了PWM的工作原理,通过调整脉冲的宽度,可以实现LED灯在一定范围内的连续亮度变化。在实现基本的呼吸灯效果后,我有思考如何进一步优化和拓展如改变呼吸灯变化速度,相信在未来的学习中我能够解决这些疑问。