一、输入捕获介绍

 在定时器中断实验章节中我们介绍了通用定时器具有多种功能,输入捕获就是其中一种。STM32F1 除了基本定时器 TIM6 和 TIM7,其他定时器都具有输入捕获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。
  输入捕获的工作原理比较简单,在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。下面我们以输入捕获测量脉宽为例,通过一个简图来介绍输入捕获的工作原理,如图 所示:

  从上图可以看出,t1-t2 时间就是我们需要测量的高电平时间,假如定时器工作在向上计数模式,测量方法是:首先设置定时器通道 x 为上升沿捕获,这样在 t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x 为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。根据定时器的计数频率,我们就可以算出 t1-t2 的时间,从而得到高电平脉宽。在 t1-t2 时间内可能会出现 N 次定时器溢出,因此我们还需要对定时器溢出进行处理,防止因高电平时间过长发生溢出导致测量数据不准。CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。

二、输入捕获配置步骤

(1)使能定时器及端口时钟,并设置引脚复用器映射和引脚模式等

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;

(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等

  TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

(3)设置通用定时器的输入捕获参数,开启输入捕获功能

  TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

(4)开启捕获和定时器溢出(更新)中断

  TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

(5)设置定时器中断优先级,使能定时器中断通道 NVIC初始化库函数是

  NVIC_Init()

(6)使能定时器

 TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

(7)编写定时器中断服务函数

  void TIM5_IRQHandle()

三、代码举例

所要实现的功能是:使用TIM5的CH1检测输入信号高电平脉宽, 将检测的高电平脉宽时间通过printf函数打印出来,同时让D1指示灯不 断闪烁表示系统正常运行。(使用普中stm32f103开发板)

 1 #ifndef _input_H
2 #define _input_H
3
4 #include "system.h"
5
6 extern u8 TIM5_CH1_CAPTURE_STA; //输入捕获的状态
7 extern u16 TIM5_CH1_CAPTURE_VAL;//输入捕获值
8
9
10 void TIM5_CH1_Input_Init(u16 arr,u16 psc);
11
12 #endif

(原子开发板资料)

bit7位置1时表示成功捕获完一次高电平(按键按下直到抬起整个过程结束);代码58、66、79

bit6位置1时表示获得高电平的标志位,(表示按键已经按下)代码62、77、87

bit0~5位表示高电平时间是定时器溢出的次数(即在按键按下时定时器溢出几次)

如果溢出次数超过了6位所能表示的范围时怎么办?

  代码64—68解决办法

就是在TIM5_CH1_CAPTURE_STA==0x3f 时将 TIM5_CH1_CAPTURE_STA变量强制bit7置1(即强制捕获完成去执行主函数代码27以后的代码段,然后重新进行下一次的捕获)   TIM5_CH1_CAPTURE_STA|=0x80;

 1 #include "input.h"
2
3 u8 TIM5_CH1_CAPTURE_STA; //输入捕获状态
4 u16 TIM5_CH1_CAPTURE_VAL;//输入捕获值
5
6 /*******************************************************************************
7 * 函 数 名 : TIM5_CH1_Input_Init
8 * 函数功能 : TIM5_CH1输入捕获初始化函数
9 * 输 入 : arr:自动重装载值
10 psc:预分频系数
11 * 输 出 : 无
12 *******************************************************************************/
13 void TIM5_CH1_Input_Init(u16 arr,u16 psc)
14 {
15 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
16 TIM_ICInitTypeDef TIM_ICInitStructure;
17 NVIC_InitTypeDef NVIC_InitStructure;
18 GPIO_InitTypeDef GPIO_InitStructure;
19
20 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
21 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5时钟
22
23 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//管脚设置
24 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD; //设置下拉输入模式
25 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
26
27 TIM_TimeBaseInitStructure.TIM_Period=arr; //自动装载值
28 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
29 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
30 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
31 TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
32
33 TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1
34 TIM_ICInitStructure.TIM_ICFilter=0x00; //滤波
35 TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
36 TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
37 TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
38 TIM_ICInit(TIM5,&TIM_ICInitStructure);
39 TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
40
41 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//中断通道
42 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
43 NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级
44 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
45 NVIC_Init(&NVIC_InitStructure);
46
47 TIM_Cmd(TIM5,ENABLE); //使能定时器
48 }
49
50 /*******************************************************************************
51 * 函 数 名 : TIM5_IRQHandler
52 * 函数功能 : TIM5中断函数
53 * 输 入 : 无
54 * 输 出 : 无
55 *******************************************************************************/
56 void TIM5_IRQHandler(void)
57 {
58 if((TIM5_CH1_CAPTURE_STA&0x80)==0) //还未成功捕获
59 {
60 if(TIM_GetITStatus(TIM5,TIM_IT_Update)) //发生更新中断
61 {
62 if(TIM5_CH1_CAPTURE_STA&0X40)//捕获到了高电平
63 {
64 if((TIM5_CH1_CAPTURE_STA&0x3f)==0x3f) //高电平时间太长
65 {
66 TIM5_CH1_CAPTURE_STA|=0x80; //标志一次捕获成功
67 TIM5_CH1_CAPTURE_VAL=0xffff;
68 }
69 else
70 {
71 TIM5_CH1_CAPTURE_STA++;
72 }
73 }
74 }
75 if(TIM_GetITStatus(TIM5,TIM_IT_CC1)) //发生捕获中断
76 {
77 if(TIM5_CH1_CAPTURE_STA&0X40)//捕获到了高电平
78 {
79 TIM5_CH1_CAPTURE_STA|=0x80; //成功捕获一次高电平
80 TIM5_CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
81 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置上升沿捕获
82 }
83 else
84 {
85 TIM5_CH1_CAPTURE_STA=0;
86 TIM5_CH1_CAPTURE_VAL=0;
87 TIM5_CH1_CAPTURE_STA|=0x40; //捕获到高电平标志
88 TIM_Cmd(TIM5,DISABLE);
89 TIM_SetCounter(TIM5,0); //定时器初值为0
90 TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置下降沿捕获
91 TIM_Cmd(TIM5,ENABLE);
92 }
93 }
94 }
95 TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);
96 }
 1 #include "system.h"
2 #include "SysTick.h"
3 #include "led.h"
4 #include "usart.h"
5 #include "input.h"
6
7
8 /*******************************************************************************
9 * 函 数 名 : main
10 * 函数功能 : 主函数
11 * 输 入 : 无
12 * 输 出 : 无
13 *******************************************************************************/
14 int main()
15 {
16 u8 i=0;
17 u32 indata=0;
18
19 SysTick_Init(72);
20 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
21 LED_Init();
22 USART1_Init(9600);
23 TIM5_CH1_Input_Init(0xffff,71); //以1M频率计数
24
25 while(1)
26 {
27 if(TIM5_CH1_CAPTURE_STA&0x80) //成功捕获
28 {
29 indata=TIM5_CH1_CAPTURE_STA&0x3f;
30 indata*=0xffff; //溢出次数乘以一次的计数次数时间 us
31 indata+=TIM5_CH1_CAPTURE_VAL;//加上高电平捕获的时间
32 printf("高电平持续时间:%d us\r\n",indata); //总的高电平时间
33 TIM5_CH1_CAPTURE_STA=0; //开始下一次捕获
34 }
35
36 i++;
37 if(i%20==0)
38 {
39 led1=!led1;
40 }
41 delay_ms(10);
42 }
43 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

(stm32f103学习总结)—输入捕获模式的更多相关文章

  1. STM32输入捕获模式设置并用DMA接收数据

    参考: STM32的PWM输入模式设置并用DMA接收数据 Input capture mode The input stage samples the corresponding TIx input ...

  2. stm32寄存器版学习笔记06 输入捕获(ETR脉冲计数)

    STM32外部脉冲ETR引脚:TIM1-->PA12;TIMER2-->PA0:TIMER3-->PD2;TIMER4-->PE0… 1.TIM2 PA0计数 配置步骤 ①开启 ...

  3. 基于STM32F103和Cube的输入捕获例程

    1.开发环境 (1)Cube5.24 (2)Keil5 (3)STM32F103 2.Cube配置 Cube配置很简单,只要打开TIM4通道1的引脚,设置为输入捕获模式,在配置是高或低电平沿触发 TI ...

  4. stm32 输入捕获学习(一)

    输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能.STM32 的输入捕获,简单地说就是通过检测 TIMx_CHx 上的边沿信 ...

  5. STM32使用定时器实现输入捕获

    输入捕获简介输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能. STM32的输入捕获,简单地说就是通过检测TIMx_CHx上的边沿信 ...

  6. [pwm]PWM的输入捕捉模式

    对于stm32来说,输入捕捉模式有两种: 普通输入捕捉模式:经常用来测量脉冲宽度和频率,例如测量脉冲宽度,TIM5_CH1来捕获高电平脉宽,首先先设置输入捕获为上升沿触发,然后记录下发生上升沿时TIM ...

  7. STM32之定时器输入捕获

    1.输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能.STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿 ...

  8. [置顶] STM32 输入捕获的脉冲宽度及频率计算

    输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能.以下是对脉冲宽度及频率的计算. 1.脉冲宽度 如下图所示,采集该高电平脉冲 ...

  9. STM32 输入捕获的脉冲宽度及频率计算

    输入捕获模式可以用来测量脉冲宽度或者测量频率.STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能.以下是对脉冲宽度及频率的计算. 1.脉冲宽度 如下图所示,采集该高电平脉冲 ...

随机推荐

  1. Java课程设计---Eclipse基本环境配置

    1.设置eclipse编码 2.设置提示

  2. Anaconda 下 Jupyter 更改默认启动路径方法(转)

    https://www.cnblogs.com/awakenedy/p/9075712.html

  3. JZ-011-二进制中 1 的个数

    二进制中 1 的个数 题目描述 输入一个整数,输出该数32位二进制表示中1的个数.其中负数用补码表示. 题目链接: 二进制中 1 的个数 代码 /** * 标题:二进制中 1 的个数 * 题目描述 * ...

  4. Android 应用框架层 SQLite 源码分析

    概述   Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDat ...

  5. React学习小结(一)

    一.React的发展 facebook在构建instagram网站的时候遇见两个问题: 1.数据绑定的时候,大量操作真实dom,性能成本太高 2.网站的数据流向太混乱,不好控制 于是facebook起 ...

  6. typora 使用Markdown语法编辑文本

    MarkDown语法 标题 一级标题# 二级标题## ============= 三级标题### 四级标题 依此类推 Markdown 段落格式 Markdown 段落没有特殊的格式,直接编写文字,段 ...

  7. Python 递归函数返回值为 None 的解决办法

    在使用 Python 开发的过程中,避免不了会用到递归函数.但递归函数的返回值有时会出现意想不到的情况. 下面来举一个例子: >>> def fun(i): ... i += 1 . ...

  8. CF678F题解

    首先题意中的有撤销操作,直接李超树肯定不行,题目允许离线,所以考虑线段树分治 所以问题就变成了求一次函数最大值 这不是李超树板子吗??? 然后可以对每个节点都建立动态开点李超树,查询的时候直接从叶子节 ...

  9. php——新闻项目改写

    主要思路:遵守java开发规范,保持接口一致性 如何保持接口的一致性: (1).url的一致性:使用@RequestingMapping注解 (2).参数的一致性: 使用@ReuqestParam注解 ...

  10. 7月2日 Django注册页面的form组件

    forms.py里注册页面的form组件 # Create your views here. class RegForm(forms.Form): username = forms.CharField ...