一、概述
IC(Input Capture)输入捕获
- 输入捕获模式下,当通道输入引脚出现指定电平跳变(上升沿或下降沿)时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
- 每个高级定时器和通用定时器都拥有4个输入捕获通道
- 可配置为PWMI(PWM输入)模式,同时测量频率和占空比
- 可配合主从触发模式,实现硬件全自动测量
以下为输入捕获的框图,左边一共有4路输入通道,对于同一个定时器输入捕获与输出比较只能使用其中一个。这个异或门的输入接在了通道1,2,3端口,异或门执行逻辑是:当三个输入引脚的任何一个有电平翻转时,输出引脚就产生电平翻转,之后输出通过数据选择器,到达输入捕获通道1。当数据寄存器不选择异或门时,就没有用,设计这个异或门,其实还是为三相无刷电机服务的。
然后来到输入滤波器和边沿检测器,滤波器是滤除噪声的不会改变频率,边沿检测器是检测是上升沿还是下降沿。
接着,有两套电路,第一套是TI1FP1。第二套是TI1FP2,输入给通道2。这样交叉的目的之一是可以把一个引脚的输入,同时映射到两个捕获单元,这也是PWMI模式的经典结构,让第一个通道测量频率,第二个通道测量占空比。
接着,预分频器对输入频率进行分频。分频之后的触发信号就可以触发捕获电路进行工作,每来一个触发信号,CNT的值就会向CCR(捕获寄存器)进行转运一次。转运的同时会发生一个捕获事件,这个事件会在状态寄存器置标志位,同时也可以产生中断。
二、频率测量
有测频法、测周法,大于中界频率用测频法,小于则用测周法,所以这个测频法适合测频率高的,测周法适合测频率低的。
三、输入捕获结构
如下图:经过滤波器滤波后,一路TI1FP1可以通向触发从模式控制器,这个从模式里面,就有电路,可以自动完成CNT的清零。滤波器中ICF[3:0]值越大滤波越好。另一路走通道1作为输入捕获。
当TI1FP1信号出现上升沿时,会将CNT的值向CCR中转运。同时,TI1FP1也作为触发源选择的触发信号,当出现上升沿时使CNT的值变为初始值(这里时硬件自动控制)。肯定是将CNT的值向CCR中转运在前,CNT的值变为初始值在后。
1、主从触发模式
主模式:可以将定时器内部的信号,映射到TRGO引脚,用于触发别的外设。
从模式:是被动的,就是接收其他外设或者自身外设的一些信号用于控制自身定时器的运行。
触发源选择:就是用来触发从模式的。
2、输入捕获基本结构
3、PWMI基本结构
四、测PWM占空比和频率代码
接线图:
- 用TIM2_CH1通道先生成PWM波形代码
PWM.c:
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//1.配置时钟,用那个外设
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//2.内部时钟配置
TIM_InternalClockConfig(TIM2);
//3.配置时基单元
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //滤波频率
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //计数方式,向上
TIM_TimeBaseInitStruct.TIM_Period=100-1; //自动重装载寄存器ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=0; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
//4.输出比较初始化
TIM_OCStructInit(&TIM_OCInitStructure); //要给结构体赋一个初始值,否则有可能出现错误
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //输出模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High ; //CC1P输出极性,这里的High指的是REF有效电平为高电平输出
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse=0; //用来设置CCR
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
//5.启动定时器
TIM_Cmd(TIM2,ENABLE);
}
//设置CCR
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2,Compare);
}
//设置预分频器
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);
}
PWM.h:
#ifndef _PWM_H
#define _PWM_H
void PWM_SetCompare1(uint16_t Compare);
void PWM_Init(void);
void PWM_SetPrescaler(uint16_t Prescaler);
#endif
- 测量PWM的频率和占空比的代码
利用测周法测PWM占空比和频率,利用TIM3_CH1输入捕获通道进行捕获A6引脚输入的信号。
IC.c:
#include "stm32f10x.h" // Device header
//测周法测PWM占空比和频率
void IC_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
//1.配置时钟,用那个外设
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//2.内部时钟配置
TIM_InternalClockConfig(TIM3);
//3.配置时基单元
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //滤波频率
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //计数方式,向上
TIM_TimeBaseInitStruct.TIM_Period=65535-1; //自动重装载寄存器ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//4.初始化捕获单元
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_PWMIConfig(TIM3,&TIM_ICInitStruct);
//5.触发源选择TI1FP1
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//6.配置TRGI中从模式
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//7.启动定时器
TIM_Cmd(TIM3,ENABLE);
}
//测频率
uint32_t IC_GetFreq(void)
{
return 1000000/(TIM_GetCapture1(TIM3)+1);
}
//测占空比
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3)+1)*100 /(TIM_GetCapture1(TIM3)+1);
}
IC.h:
#ifndef _LC_H
#define _LC_H
void IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);
#endif
main.c:
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "delay.h"
#include "PWM.h"
#include "lC.h"
uint16_t i;
int main(void)
{
OLED_Init();
PWM_Init();
IC_Init();
OLED_ShowString(1,1,"Freq:00000Hz");
OLED_ShowString(2,1,"Duty:00%");
PWM_SetPrescaler(3600-1); //频率Freq=72M/(PSC+1)/100
PWM_SetCompare1(80); //CCR/100 占空比
while(1)
{
OLED_ShowNum(1,6,IC_GetFreq(),5);
OLED_ShowNum(2,6,IC_GetDuty(),2);
}
}