一、输出比较简介
OC(Output Compare)输出比较
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。
CCR(捕获/比较寄存器)这里输入捕获和输出比较是共用的,当使用输入捕获时,就是捕获寄存器;当使用输出比较时,就是比较寄存器。在输出比较这里,这部分电路会比较CNT和CCR的值,CNT计数器值自增,CCR是我们给定的一个值,当CNT的值大于,小于或者等于CCR时,输出会被置1,置0,反复下去,就形成了一个电平不断跳变的PWM波形了。这就是输出比较的基本功能了。
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
死区生成和互补输出主要用来驱动三相无刷电机。
二、PWM简介
PWM(Pulse Width Modulation)脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM参数:
频率 = 1 / TS
占空比 = TON / TS(高电平时间/整个周期时间)
分辨率 = 占空比变化步距
三、输出比较通道
当CNT>CCR1或者CNT=CCR1时,就会传给输出模式控制器一个信号,输出模式控制器就会改变它输出的oc1ref的高低电平。通过极性选择电路,写0电平不翻转,写1电平翻转,最后通过输出使能电路oc1通道输出。
输出模式控制器的具体工作方式:
我们主要使用PWM模式1和PWM模式2,频率和占空比都可调。一般我们使用向上计数,PWM模式1向上计数模式产生一个PWM波形的过程:
配置好时基单元后,CNT计时器就开始不断自增运行了,然后我们给定一个CCR的值。如上图右上角部分,黄线是ARR(自动重装器)的值,红线是CCR的值,蓝线是CNT,下面的绿线是预设输出。
当CNT<CCR时,置高电平;当CNT>=CCR时,置低电平。当CNT=ARR时,清0继续自增。由上图可以知道,占空比的值是根据CCR的值来调控的,CCR越大,高电平时间越长,占空比越大。这样持续下去就形成了电平不断跳变的PWM信号,再通过极性选择和输出使能,最终通过GPIO输出。
PWM参数计算:
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM频率等于CNT计数更新频率,因为PWM的周期等于CNT计数周期。
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
四、pwm驱动呼吸灯
步骤:
1.开启时钟,开启定时器时钟和GPIO时钟。
2.初始化时基单元。初始化ARR和PSC的值。
3.初始化GPIO,PWM要通过GPIO输出,配置GPIO。
4.初始化输出比较模块。选择通道,初始化输出比较结构体。
5.启动定时器。启动后就开始输出PWM波形了。
驱动呼吸灯demo:
pwm.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure; //输出比较结构体
GPIO_InitTypeDef GPIO_InitStructure;
//1.开启时钟,选择内部时钟,TIM2是APB1总线的外设
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//配置GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //选择复用推挽输出,将引脚控制权交给片上外设,控制PWM输出。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//2.初始化时基单元
TIM_InternalClockConfig(TIM2); //选择内部时钟驱动TIM2的时基单元
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; //选择时钟分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式选择
//定时时间的公式:CK_CNT_OV = CK_PSC / (PSC + 1) / (ARR + 1),定时1s,也就是1HZ;
//预分频器和计数器有一个数的偏差,因此要减1,PSC和ARR的取值0~65535;
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_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 = 50; //配置CCR寄存器的值 CCR
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
//5.启动定时器
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 "Buzzer.h"
#include "Key.h"
#include "Light_Seror.h"
#include "OLED.h"
#include "PWM.h"
int main(void)
{
uint16_t i;
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);
}
}
}
注:内容来自博主 【江科大自化协】。本文做学习笔记用。