文章目录
- 一、TIM输入捕获
- 输入捕获简介
- 频率测量
- 二、通用定时器的输入捕获通道
- 通用定时器框图
- 通道的输出部分
- 三、主从触发模式
- 主模式
- 从模式
- 四、输入捕获基本结构
- 五、PWMI基本结构
- 六、输入捕获模式测频率
- 电路设计
- 关键代码
- 七、PWMI模式测频率占空比
- 电路设计
- 关键代码
- 八、定时器库函数(tim.h)
一、TIM输入捕获
输入捕获简介
- IC(Input Capture)输入捕获
- 输入捕获模式下,
当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中
,可用于测量PWM波形的频率、占空比、脉冲间隔(频率)、电平持续时间(占空比)等参数 - 每个高级定时器和通用定时器都拥有4个输入捕获通道
- 可配置为
PWMI模式,同时测量频率和占空比
- 可配合主从触发模式,实现硬件全自动测量
对于同一个定时器,由于其通道引脚是共用的,输入捕获和输出比较只能使用其中一个
- 输入捕获的功能和外部中断类似,但是在外部中断中,引脚出现指定电平跳变的时候是向CPU申请中断,而输入捕获是将CNT锁存在CCR中,而不是进行比较
频率测量
-
测频法:在闸门时间T内【一般是1s】,对上升沿计次【一个上升沿就是一个周期】,得到N,则频率【适合高频】
-
测周法(利用周期的倒数是频率):两个上升沿内,以标准频率fc计次【通过已知频率求】,得到N ,则频率【适合低频】
-
中界频率:测频法与测周法误差相等的频率点【设N相同求解】,大于中界频率选测频法,小于中界频率选测周法。因为N越大,+1/1误差对频率的影响越小
二、通用定时器的输入捕获通道
通用定时器框图
- CH1/2/3三个引脚接到异或门,只要有一个引脚电平翻转就触发一次电平翻转。该设计是为三相无刷电机服务,三个霍尔传感器检测转子的位置
- TI1左边是数据选择器,可以选择是异或通道输出还是各个通道各自输出
- 输入滤波器和边沿检测器:有两套滤波和边沿检测,分别输出TI1FP1和TI2FP2
- IC1和IC2旁边的数据选择器负责交换连接:1. 灵活切换后续输入捕获电路的输入。2. 一个引脚的输入映射到两个捕获单元,也就是PWMI模式,两个通道同时对一个引脚捕获,测量占空比和频率
- 预分频器:每来一个上升沿,将CNT存在CCR中,用于计数计时(内部时钟源可以计算时间)同时还可以触发捕获中断
通道的输出部分
- 从TI1F_ED通道或TI1FP1通道到从模式:有硬件电路可以自动完成CNT清零,
- IC1PS通道:手动完成CNT清零
IC1F寄存器:
- 滤波器:采样频率越低,采样个数N越大,滤波效果越好
三、主从触发模式
主模式
- 将定时器内部信号映射到TRGO引脚
- 接收其他外设信号或自身外设的信号,用于控制自身定时器的运行
- 主模式选择
从模式
-
如图所示,通道3和4没有触发源可以选择,但可以通过触发捕获中断,在中断函数中手动清零CNT,容易消耗软件资源,不断进入中断
-
触发源选择
-
从模式选择
-
TIM输入捕获采用从模式:触发源选择TI1FP1,从模式中选择Reset
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//选择输入触发源TRGI TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//选择从模式
四、输入捕获基本结构
-
从模式只有通道1和通道2,通道3和4只能通过在捕获中断函数里面清除CNT的值
-
采用测周法,需要知道标准频率fc和计次N,fc就等于CNT的驱动时钟即预分频的值
-
每次捕获完成都需要将CNT的值清零
,可以用主从触发模式完成
设置为输入捕获通道需要配置成浮空输入
五、PWMI基本结构
-
CCR2捕获并不会触发CNT清零,此时高电平的计数值存放在CCR2里面
-
CCR2/CCR1=占空比
-
函数
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//该函数只需要传入一个通道即可,会默认将另一个通道取反配置
六、输入捕获模式测频率
电路设计
- PA0通过输出比较电路输出PWM波,PA6为输入捕获通道
关键代码
IC.c
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &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 = 65536 - 1; //ARR,设定数值大防止溢出
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC,计数器自增频率=fc=72MHZ/(PSC+1)
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//输入捕获通道
TIM_ICInitStructure.TIM_ICFilter = 0xF;//滤波器
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//极性选择
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//预分频
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//直连还是交叉连接
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//主模式触发源
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//从模式配置为RESET
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
//TIM_GetCapture1/2/3/4()获取输入捕获模式下CCR寄存器的值
}
- 由于输出比较通道使用TIM2,而捕获/比较寄存器是不能共用的,所以输入捕获通道采用TIM3
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, 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);
}
//调节PWM占空比,当ARR为100-1时,CCR就是占空比
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
//调节PWM频率,由于频率收到ARR和PSC影响,修改ARR还会影响到占空比,此处只修改PSC的值
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
//第三个参数指定预分频器的重装模式:可以选立即生效和更新事件后生效
}
main.c
修改预分频,观察输入捕获测量的频率
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void)
{
OLED_Init();
PWM_Init();
IC_Init();
OLED_ShowString(1, 1, "Freq:00000Hz");
PWM_SetPrescaler(720 - 1); //Freq = 72M / (PSC + 1) / 100
PWM_SetCompare1(50); //Duty = CCR / 100
while (1)
{
OLED_ShowNum(1, 6, IC_GetFreq(), 5);
}
}
七、PWMI模式测频率占空比
电路设计
- PA0通过输出比较电路输出PWM波,PA6为输入捕获通道
关键代码
IC.c
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &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 = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//快速配置两个通道
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
//获取占空比=CCR2/CCR1
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}
八、定时器库函数(tim.h)
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//输入捕获通道初始化,四个通道占用一个函数,在结构体中可以选定通道
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//快速配置两个通道,用于PWMI模式
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);//结构体初始化
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择输入触发源TRGI
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);//选择输出触发源TRGO
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);//选择从模式
//分别配置通道的分频器
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);
//分别读取四个通道的CCR值
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);