目录
1. 深入了解STM32定时器原理,掌握脉宽调制pwm生成方法。
1. 深入了解STM32定时器原理,掌握脉宽调制pwm生成方法。
(1)STM32定时器原理
STM32定时器(Timer)是一种用于生成精确时间延时和执行周期性任务的外设。在STM32微控制器中,定时器通常由一组定时器单元组成,每个定时器单元都有自己的计数器和控制寄存器。这些定时器可以配置成多种模式,例如定时器模式、输入捕获模式、输出比较模式等。
原理概述
-
计数器:定时器内部有一个计数器,它会不断地自增直到达到预设的值,然后重新开始计数。计数器的增长速率由时钟源决定,可以是内部时钟源(如HSI、LSI)或者外部时钟源(如HSE、HCLK)。
-
时钟源:定时器的计数器工作时需要一个时钟源。STM32微控制器提供了多种时钟源供选择,可以通过寄存器配置选择。时钟源的选择影响了定时器的精度和范围。
-
预分频器:定时器还可以配置一个预分频器,用于减小时钟源的频率,从而降低计数器增长的速率。这个预分频器可以通过设置寄存器来配置,允许定时器适应不同的应用需求。
-
模式配置:STM32定时器可以配置成多种模式,包括计数模式、定时器模式、PWM输出模式等。每种模式有不同的应用场景和功能。
STM32定时器的常见模式
-
计数模式:定时器的计数器简单地递增直到达到最大值,然后重新从零开始计数。这种模式通常用于测量时间间隔或者生成延时。
-
定时器模式:在这种模式下,定时器的计数器到达预设值后会产生一个中断或者触发一个输出。这种模式常用于产生精确的定时事件。
-
输入捕获模式:定时器可以捕获外部信号的边沿,并记录捕获时的计数器值。这种模式常用于测量外部信号的脉冲宽度或者频率。
-
输出比较模式:定时器可以将计数器的值与预设的比较值进行比较,并在匹配时触发中断或者改变输出状态。这种模式常用于生成PWM信号或者控制外部设备。
使用步骤
-
时钟使能:首先需要启用定时器所需要的时钟源,通常需要配置相应的时钟控制寄存器。
-
寄存器配置:根据需要选择定时器、配置预分频器、选择工作模式以及设置相关参数。
-
中断配置:如果需要定时器中断,需要配置中断使能和相应的中断优先级。
-
启动定时器:配置完成后,启动定时器开始计数。
-
处理中断(可选):如果使用了定时器中断,需要编写中断处理函数来处理定时器触发的中断事件。
-
定时器应用:根据具体应用需求,在定时器中断或者定时器到期时执行相应的操作。
定时器的主要功能:
(2)脉宽调制pwm生成方法。
PWM(Pulse Width Modulation,脉冲宽度调制)是一种利用脉冲宽度即占空比实现对模拟信号进行控制的技术,即是对模拟信号电平进行数字表示的方法。
广泛应用于电力电子技术中,比如PWM控制技术在逆变电路中的应用; PWM还应用于直流电机调速,如变频空调的交直流变频调速,除实现调速外,还具有节能等特性。
周期为10ms(频率为100Hz) 的PWM波形:
STM32的定时器除了TIM6和TIM7,其他定时器都可以用来产生PWM输出; 高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出; 通用定时器能同时产生多达4路的PWM输出; STM32中每个定时器有4个输入通道:TIMx_CH1~TIMx_CH4; 每个通道对应1个捕获/比较寄存器TIMx_CRRx,将寄存器值和计数器值相比较,通过比较结果输出高低电平,从而得到PWM信号; 脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。
PWM标准外设库输出配置步骤:
2. 实验
(1)LED亮灭
使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮灭。
代码
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);
}
}
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);//放入Init函数中
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
测试效果
(2)呼吸灯
采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整占空比变化到一个满意效果;使用Keil虚拟示波器,观察 PWM输出波形。
代码
main.c文件
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i; //定义for循环的变量
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
PWM_Init(); //PWM初始化
while (1)
{
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(i); //依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮
Delay_ms(10); //延时10ms
}
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(100 - i); //依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗
Delay_ms(10); //延时10ms
}
}
}
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); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,重映射必须先开启AFIO的时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //将JTAG引脚失能,作为普通GPIO引脚使用
/*GPIO初始化*/
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); //将PA0引脚初始化为复用推挽输出
//受外设控制的引脚,均需要配置为复用模式
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
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_TimeBaseInit,配置TIM2的时基单元
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值
//则最好执行此函数,给结构体所有成员都赋一个默认值
//避免结构体初值不确定的问题
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
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_OC1Init,配置TIM2的输出比较通道1
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
测试效果
3.总结
深入了解STM32定时器原理,掌握脉宽调制pwm生成方法,使用hal库制作定时器完成了led灯的亮灭与呼吸灯实验.