我是靠谱客的博主 大方小伙,这篇文章主要介绍嵌入式单片机基础篇(九)之通用定时器(三)输入捕获stm32F1输入捕获详解,现在分享给大家,希望可以做个参考。

stm32F1输入捕获详解

1、问题:什么叫输入捕获
回答:举个例子,比如一个信号由低电平变成高电平时,cpu保存定时器的值,信号再由高电平变成低电平时,cpu又保存一次定时器的值,那么通过这两次定时器的值就可以计算出脉冲宽度
问:可否具体?
答:简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
2、输入捕获框图
在这里插入图片描述

3、输入捕获相关寄存器
需要用到的寄存器有:TIMx_ARR、TIMx_PSC、TIMx_CCMR1、TIMx_CCER、TIMx_DIER、TIMx_CR1、TIMx_CCR1
(1)捕获/比较模式寄存器 1:TIMx_CCMR1
在这里插入图片描述

TIMx_CCMR1 是对 2 个通道的配置,低八位[7:0]用于捕获/比较通道 1 的控制,而高八位[15:8]则用于捕获/比较通道 2 的控制,因为 TIMx 还有 CCMR2 这个寄存器,所以可以知道CCMR2 是用来控制通道 3 和通道 4
在这里插入图片描述
IC1S[1:0]=01,也就是配置 IC1 映射在 TI1 上,即 CC1 对应 TIMx_CH1。
输入捕获 1 预分频器 IC1PSC[1:0],如果是 1 次边沿就触发 1 次捕获,选择 00 。
输入捕获 1 滤波器 IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。其中,fCK_INT是定时器的输入频率(TIMxCLK),一般为 72Mhz,而 fDTS 则是根据 TIMx_CR1 的 CKD[1:0]的设置来确定的,如果 CKD[1:0]设置为 00,那么 fDTS = fCK_INT,N 值就是滤波长度。
如果IC1F[3:0]=0000,只要采集到上升沿,就触发捕获。
如果IC1F[3:0]=0011,捕获到上升沿的时候,以fCK_INT的频率,连续采样8次通道 1 的电平,如果都是高电平,则说明却是一个有效的触发,就会触发输入捕获中断(如果开启了的话)。
(2)捕获/比较使能寄存器:TIMx_CCER
Bit 1 CC1P: Capture/Compare 1 output polarity
CC1 channel configured as output:
0: OC1 active high.
1: OC1 active low.
CC1 channel configured as input:
This bit selects whether IC1 or IC1 is used for trigger or capture operations.
0: non-inverted: capture is done on a rising edge of IC1. When used as external trigger, IC1
is non-inverted.
1: inverted: capture is done on a falling edge of IC1. When used as external trigger, IC1 is
inverted.
Bit 0 CC1E: Capture/Compare 1 output enable
CC1 channel configured as output:
0: Off - OC1 is not active.
1: On - OC1 signal is output on the corresponding output pin.
CC1 channel configured as input:
This bit determines if a capture of the counter value can actually be done into the input
capture/compare register 1 (TIMx_CCR1) or not.
0: Capture disabled.
1: Capture enabled.
(3)DMA/中断使能寄存器:TIMx_DIER
如果需要用到中断来处理捕获数据,必须开启通道 1 的捕获比较中断,即 CC1IE 设置为 1。
(4)捕获/比较寄存器 1:TIMx_CCR1
该寄存器用来存储捕获发生时,TIMx_CNT
的值,我们从 TIMx_CCR1 就可以读出通道 1 捕获发生时刻的 TIMx_CNT 值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度。
4、相关函数
(1)输入捕获通道初始化函数:
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

typedef struct
{
  uint16_t TIM_Channel; //捕获通道1-4   
  uint16_t TIM_ICPolarity; //捕获极性
  uint16_t TIM_ICSelection; //映射关系
  uint16_t TIM_ICPrescaler; //分频系数
  uint16_t TIM_ICFilter;  //滤波器
} TIM_ICInitTypeDef;

TIM_ICInitTypeDef TIM5_ICInitStructure;
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);

(2)通道极性设置独立函数:
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
(3)获取通道捕获值
uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx);
5、输入捕获的一般配置步骤:
① 初始化定时器和通道对应IO的时钟。
② 初始化IO口,模式为输入:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
③初始化定时器ARR,PSC
TIM_TimeBaseInit();
④初始化输入捕获通道
TIM_ICInit();
⑤如果要开启捕获中断,
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断和捕获中断
NVIC_Init();
⑥使能定时器:TIM_Cmd();TIM_Cmd(TIM5,ENABLE ); //使能定时器 5
⑦编写中断服务函数:TIMx_IRQHandler();
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中断和捕获标志位
6、程序
(1)timer.c

//定时器 5 通道 1 输入捕获配置
TIM_ICInitTypeDef TIM5_ICInitStructure;
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //①使能 TIM5 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIOA 时钟
//初始化 GPIOA.0 ①
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 设置 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入 
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.0
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
//②初始化 TIM5 参数
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器 
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //初始化 TIMx
//③初始化 TIM5 输入捕获通道 1
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure); //初始化 TIM5 输入捕获通道 1
//⑤初始化 NVIC 中断优先级分组
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM3 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化 NVIC
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//④允许更新中断捕获中断
TIM_Cmd(TIM5,ENABLE ); //⑥使能定时器 5 }
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态 
u16 TIM5CH1_CAPTURE_VAL;//输入捕获值
//⑤定时器 5 中断服务程序
void TIM5_IRQHandler(void)
{ 
if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{ 
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{if(TIM5CH1_CAPTURE_STA&0X40) //已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
} }
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获 1 发生捕获事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{ 
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置为下降沿捕获
} 
} 
}
 TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}

(2)main 函数

extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态 
extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
u32 temp=0; 
delay_init(); //延时函数初始化 
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2
uart_init(115200); //串口初始化波特率为 115200
LED_Init(); //LED 端口初始化
TIM3_PWM_Init(899,0); //不分频。PWM 频率=72000/(899+1)=80Khz
TIM5_Cap_Init(0XFFFF,72-1); //以 1Mhz 的频率计数
 while(1)
{
delay_ms(10);
TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);
if(TIM_GetCapture2(TIM3)==300)
TIM_SetCompare2(TIM3,0);
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp*=65536;//溢出时间总和
temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间
printf("HIGH:%d usrn",temp); //打印总的高点平时间
TIM5CH1_CAPTURE_STA=0; //开启下一次捕获
} } }

7、完整程序包
来源于网络的输入捕获实验

最后

以上就是大方小伙最近收集整理的关于嵌入式单片机基础篇(九)之通用定时器(三)输入捕获stm32F1输入捕获详解的全部内容,更多相关嵌入式单片机基础篇(九)之通用定时器(三)输入捕获stm32F1输入捕获详解内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(118)

评论列表共有 0 条评论

立即
投稿
返回
顶部