OC(Output Compare) 输出比较
输出比较可以通过比较CNT(计数器)与CCR捕获/比较寄存器值的关系,来对输出电平进行置1,置0或翻转的操作,用于输出一定频率和占空比的PWM波形
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
当CNT>CCR,
重要函数:
初始化输出比较模块
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_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);
#include "PWM.h"
//第一步,RCC开启时钟,把TIM外设和GPIO外设打开
//第二步,配置时基单元(PSC,ARR,CNT)
//第三步,配置输出比较单元,里面包括(CCR,输出比较模式,极性选择,输出使能)
//第四步,PWM对应GPIO,初始化配置对复用推挽输出
//第五步,运行控制
void PWM_Init()
{
//第一步,RCC开启时钟,把TIM外设和GPIO外设打开
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//第二步,配置时基单元(PSC,ARR,CNT)
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=100-1;
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
//第三步,配置输出比较单元,里面包括(CCR,输出比较模式,极性选择,输出使能)
TIM_OCInitTypeDef TIM_OCInitStruct;
//初始化
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=50;
TIM_OC3Init(TIM2,&TIM_OCInitStruct);
//第四步,PWM对应GPIO,初始化配置对复用推挽输出
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStruct);
//第五步,运行控制
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetComparel(uint16_t Compare)
{
TIM_SetCompare3(TIM2,Compare);
}
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);
}
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT输入捕获模式下,当通道输入引脚出现指定电平跳变下,当前CNT的值将被所存到CCR种中,可用于测量PWM波形的频率,占空比,脉冲间隔,电平持续时间等参数
每个高级定时器和通用定时器都有4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配置主从触发模式,实现硬件全自动测量
测周法:测量时间的方法,实际上是用一个定时器计次,使用一个已知标准频率fc的计次时钟来驱动计数器,从一个上升沿开始计数,一直计到下一个上升沿,记一个数的时间是1/fc,N个数是N/fc
取个倒数为频率fc/N
PWMI模式:第一个捕获通道,使用上升沿触发,用来捕获周期
第二个通道,使用下降沿触发,用来捕获占空比
一个通道灵活切换两个引脚,和两个通道同时捕获一个引脚
#include "IC.h"
//第一步 RCC开启时钟,把GPIO和TIM时钟打开
//第二步 GPIO初始化,把GPIO设置成输入模式(上拉,浮空)
//第三步,配置时基单元,让CNT计数器在内部时钟自增运行
//第四步,配置输入捕获单元
//第五步,选择从模式触发源
//第六步,选择从模式 Reset操作
//第七步,调用TIM_Cmd函数,开启定时器
void IC_Init()
{
//第一步 RCC开启时钟,把GPIO和TIM时钟打开
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//第三步,配置时基单元,让CNT计数器在内部时钟自增运行
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65536-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1; //PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//第二步 GPIO初始化,把GPIO设置成输入模式(上拉,浮空)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStruct);
//第四步,配置输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter=0xf;
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1 ;
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, & TIM_ICInitStruct);
//第五步,选择从模式触发源
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//第六步,选择从模式 Reset操作
TIM_SelectSlaveMode( TIM3, TIM_SlaveMode_Reset);//CNT自动清0
TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreg()
{
return 1000000/ TIM_GetCapture1(TIM3);
}
测频率占空比
#include "IC.h"
//第一步 RCC开启时钟,把GPIO和TIM时钟打开
//第二步 GPIO初始化,把GPIO设置成输入模式(上拉,浮空)
//第三步,配置时基单元,让CNT计数器在内部时钟自增运行
//第四步,配置输入捕获单元
//第五步,选择从模式触发源
//第六步,选择从模式 Reset操作
//第七步,调用TIM_Cmd函数,开启定时器
void IC_Init()
{
//第一步 RCC开启时钟,把GPIO和TIM时钟打开
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//第三步,配置时基单元,让CNT计数器在内部时钟自增运行
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65536-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1; //PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//第二步 GPIO初始化,把GPIO设置成输入模式(上拉,浮空)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStruct);
//第四步,配置输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter=0xf;
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1 ;
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, & TIM_ICInitStruct);
//第二通道(方法一)
// TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;
// TIM_ICInitStruct.TIM_ICFilter=0xf;
// TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;
// TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1 ;
// TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_IndirectTI;
第二通道(方法二)
TIM_PWMIConfig(TIM3, &TIM_ICInitStruct);
TIM_ICInit(TIM3, & TIM_ICInitStruct);
//第五步,选择从模式触发源
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//第六步,选择从模式 Reset操作
TIM_SelectSlaveMode( TIM3, TIM_SlaveMode_Reset);//CNT自动清0
TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreg()
{
return 1000000/ TIM_GetCapture1(TIM3);}
uint32_t IC_getDuty()
{
return (TIM_GetCapture2(TIM3)+1)*100/ TIM_GetCapture1(TIM3);
}