1.输入捕获介绍:
- STM32除了基本定时器(定时器6和定时器7)之外,其他的都具有输入捕获功能;
- 输入捕获可以对输入的信号的上升沿、下降沿或双边沿进行捕获,通常用于测量输入信号的脉宽、测量PWM输入信号的频率及占空比;
- 首先将捕获到t1信号之后将CNT的值进行清零,清零之后并且下一次捕获是下降沿,将捕获极性设置为下降沿捕获;到达t2时,就会发生捕获事件,得到此时的CNT的值,将t2的值记为CCRx2,将(t2-t1)*T(计数频率的周期)=溢出时间;当在t1到t2时间内,可能高电平时间脉冲比较长,有可能定时器会产生溢出,如果溢出就会产生溢出中断,在溢出中断中用变量累计溢出的次数N,N*ARR=溢出次数;溢出次数*一次的值=N次溢出累计的时间;(N*ARR+CRRx2)=t1到t2的时间。
2.输入捕获库函数配置步骤:
定时器相关库函数在stm32f10x_tim.c和stm32f10x_tim.h文件中;
- 使能定时器及端口时钟,并设置引脚模式等:RCC_APB1PeriphClockCmd()和GPIO_Init();
- 初始化定时器参数,包含自动重装载值,分频系数,计数方式等:void TIM_TimeBaseInit();
- 设置通用定时器的输入捕获参数,开启输入捕获功能;void TIM_ICInit()、TIM_OC1PolarityConfig();
- 开启捕获和定时器溢出(更新中断):void TIM_ITConfig();
- 设置定时器中断优先级,使能定时器中断通道;
- 编写定时器中断服务函数;
- 使能定时器:void TIM_Cmd();
3.输入捕获实验:
实现功能:实验定时器TIM5的CH1检测输入信号高电平脉冲,将检测的高电平脉冲时间通过printf函数打印出来,同时让LED0指示灯不断闪烁表示系统正常运行。
(1)原理图:
(2)主函数:
#include "delay.h"
#include "led.h"
#include "usart1.h"
#include "input.h"
int main(){
u8 i=0;
u32 indata=0; //累计整个从上升沿到下降沿的次数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置分组
delay_init(); //延时初始化
LED_Init();
usart1_Init(9600); //串口通信初始化
TIM5_CH1_Input_Init(0xffff,72-1); //输入捕获->定时器3通道1初始化
while(1){
if((TIM5_CH1_CAPTURE_STA&0x80)) //判断捕获是否完成->这里表示完成
{
indata=TIM5_CH1_CAPTURE_STA&0x3f; //得到溢出次数
indata*=0xffff; //将所有溢出次数换算成计数的次数
indata+=TIM5_CH1_CAPTURE_VAL;
printf("高电平持续时间:%d us\r\n",indata);
TIM5_CH1_CAPTURE_VAL=0; //开启下一次捕获
}
i++;
if(i%20==0)
{
LED0=!LED0;
}
delay_ms(20);
}
}
(3)头文件:
#ifndef __INPUT_H
#define __INPUT_H
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
extern u8 TIM5_CH1_CAPTURE_STA;
extern u16 TIM5_CH1_CAPTURE_VAL;
void TIM5_CH1_Input_Init(u16 arr,u16 psc); //输入捕获->定时器5通道1初始化
#endif
(4)输入捕获功能函数:
#include "stm32f10x.h"
#include "input.h"
/*
功能:输入捕获->定时器5通道1初始化
变量:arr:自动重装载值 psc:预分频系数
返回值:
*/
void TIM5_CH1_Input_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//1.使能定时器和端口时钟,并设置引脚模式;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能端口时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //使能定时器时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD; //输入下拉
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0; //PA0
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//2.定时器初始化
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //1分频
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //计数模式->向上计数
TIM_TimeBaseInitStruct.TIM_Period=arr; //自动重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler=psc; //预分频系数
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);
//3.设置通用定时器的输入捕获,开启输入捕获功能
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1; //设置为通道1
TIM_ICInitStruct.TIM_ICFilter=0x00; //滤波器长度->不使用滤波
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //捕获极性->上升沿捕获
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //1分频
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //映射->直接映射
TIM_ICInit(TIM5,&TIM_ICInitStruct);
//4.开启捕获和定时器溢出中断
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
//5.设置定时器中断优先级,使能定时器中断通道
NVIC_InitStruct.NVIC_IRQChannel=TIM5_IRQn; //设置中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; //子优先级
NVIC_Init(&NVIC_InitStruct);
//6.使能定时器
TIM_Cmd(TIM5,ENABLE);
}
/*
功能:中断服务函数
变量:无
返回值:无
注意:
如果捕获到了上升沿再到下一次捕获到下降沿就完成了一次捕获,让TIM5_CH1_CAPTURE_STA最高位 置1,
如果捕获到上升沿让TIM5_CH1_CAPTURE_STA的次高位 置1,
将TIM5_CH1_CAPTURE_STA剩下的6位,累计溢出次数;
*/
u8 TIM5_CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM5_CH1_CAPTURE_VAL=0; //输入状态值
void TIM5_IRQHandler(void)
{
/*注意:处理完第一次捕获成功的数据之后,才能处理下一次捕获的数据*/
if((TIM5_CH1_CAPTURE_STA&0x80)==0) // TIM5_CH1_CAPTURE_STA的最高位为0时->未捕获完成
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)) //溢出中断
{
if((TIM5_CH1_CAPTURE_STA&0x40)) //已经捕获到上升沿
{
if((TIM5_CH1_CAPTURE_STA&0x3f)==0x3f) //判断当STA后六位全为1时,累计次数已满
{
TIM5_CH1_CAPTURE_STA|=0x80; //将TIM5_CH1_CAPTURE_STA最高位设置为1,表示捕获成功
TIM5_CH1_CAPTURE_VAL=0xffff; //将TIM5_CH1_CAPTURE_VAL设置为最大;
}
else //当STA后六位不全为1时,说明还没有累计完
{
TIM5_CH1_CAPTURE_STA++;
}
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC1)) //捕获中断
{
if((TIM5_CH1_CAPTURE_STA&0x40)) //当STA次高位为1时,说明捕获到上升沿
{
TIM5_CH1_CAPTURE_STA|=0x80; //设置STA最高位为1;表示捕获成功
TIM5_CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5); //将定时器5通道1的比较值赋值给VAL
TIM_OC1PolarityConfig(TIM5,TIM_OCPolarity_High); //设置捕获极性为上升沿捕获->为下一次捕获做准备
}
else //当STA的次高位不为1时,则没有捕获到上升沿
{
TIM5_CH1_CAPTURE_STA=0;
TIM5_CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0); //清零计数器的值
TIM5_CH1_CAPTURE_STA|=0x40; //第一次捕获到上升沿时,将STA的次高位设置为1
TIM_OC1PolarityConfig(TIM5,TIM_OCPolarity_Low); //设置捕获极性为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update|TIM_IT_CC1); //清除定时器标志位
}
(6)实验结果: