OC (Output Compare) 输出比较,可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形;每个高级定时器和通用定时器都拥有4个输出比较通道,高级定时器的前3个通道额外拥有死区生成和互补输出的功能。
捕获/比较寄存器是输入捕获喝输出比较公用的
在输出比较中,电路会比较CNT和CCR的值,CNT计数自增,CCR为给定值,两个值比较后输出PWM波形至对应TIMx_CHx口
PWM (Pulse Width Modulation)脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM参数: 频率=1/Ts 占空比 = ToN/Ts 分辨率 =占空比变化步距
当CNT>CCR或者CNT=CCR1时,输出模式控制器会改变它输出OC1REF的高低电平,随后REF信号可前往主模式控制器,映射至TRGO的输出;也可往下走,至极性选择寄存器,可选择是否进行电平翻转;接着通过输出使能电路到达OC1引脚
输出模式控制器:
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
配置步骤:
1、RCC开启始终,将需要使用的TIM外设和GPIO外设时钟打开
2、配置时基单元,包括时钟源选择
3、配置输出比较单元,包括CCR值、输出比较模式、极性选择、输出使能等
4、配置GPIO,将PWM对应的GPIO口初始化为复用推挽输出模式
5、运行控制,启动计数器,即可输出PWM
相关库函数:
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
TIM_OC1Init:用于配置输出比较单元,参数:选择定时器,结构体
TIM_OCStructInit:用于给输出比较结构体赋一个默认值
TIM_CtrlPWMOutputs:仅限高级定时器输出PWM时使能使用,不用则PWM无法正常输出
TIM_ForcedOC1Config:用于配置强制输出模式,在运行中暂停输出波形且强制输出高或低电平时使用
TIM_OC1PreloadConfig:用于配置预装载寄存器(影子寄存器)
TIM_OC1FastConfig:用于配置快速使能
TIM_ClearOC1Ref:用于在外部事件是清除REF信号
TIM_OC1PolarityConfig:用于单独设置输出比较极性
TIM_OC1NPolarityConfig:用于单独设置输出比较极性,高级通道里互补通道的配置
TIM_OC4PolarityConfig:OC4无互补通道,故无OC4N的函数
TIM_CCxCmd:用于单独修改输出使能参数
TIM_CCxNCmd:用于单独修改输出使能参数
TIM_SelectOCxM:用于选择输出比较模式
TIM_SetCompare1:用于单独更改CCR寄存器值的函数
代码实现(呼吸灯):
//PWM初始化代码如下
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//使用正点原子精英板,需要对TIM3进行重映射
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3); //这句不写也没有影响,默认使用内部时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 99;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7199;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //用于给结构体中的所有变量赋初始值
//避免使用高级定时器时因为部分变量未赋值而报错
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//TIM_OCInitStructure.TIM_Pulse = 50;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
TIM_Cmd(TIM3, ENABLE);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM3, Compare);
}
//main.c代码如下
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
#include "PWM.h"
int main(void)
{
//LED_Init();
KEY_Init();
delay_init();
OLED_Init();
PWM_Init();
int i;
while(1)
{
for(i=0; i<100; i++)
{
PWM_SetCompare2(i);
delay_ms(10);
}
for(i=0; i<100; i++)
{
PWM_SetCompare2(100-i);
delay_ms(10);
}
}
}
其中TIM3使用了复用功能重映像,根据操作手册如下,需选择部分重映射