用STM32定时器测量信号频率——测频法和测周法[原创cnblogs.com/helesheng]







- 1 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
- 2 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
- 3 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能porta
- 4 //PA1-> TIM2_CH2外部时钟输入
- 5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PA1
- 6 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- 7 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //10M时钟速度
- 8 GPIO_Init(GPIOA, &GPIO_InitStructure);
使能相关定时器和GPIO时钟,配置GPIO
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
- //!!!!!定时器3,用于产生标准时长的对外部脉冲计数的窗口,从而计算外部脉冲的频率!!!!!//
- TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000
- TIM_TimeBaseStructure.TIM_Prescaler =(psc-1); //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
- TIM_ITConfig( //使能或者失能指定的TIM中断
- TIM3, //TIM3
- TIM_IT_Update, //数值溢出更新中断
- ENABLE //使能
- );
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM2更新中断
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级3级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
- NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
- TIM_SetCounter(TIM3,0);
- TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
3)配置用于对外部被测脉冲进行计数的TIM2的时基单元和中断
配置用于对外部被测脉冲计数的TIM2


- 1 unsigned char i=0;
- 2 unsigned int frq[10];//连续存取10次的测频法得到的频率
- 3 unsigned int pul_num;//标准时间内的脉冲数量
- 4 unsigned int cnt;//读取当前计数值
- 5 unsigned int last_cnt=0;//上一次的计数值
- 6 void TIM3_IRQHandler(void) //TIM3中断,达到定时时间
- 7 {
- 8 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
- 9 {
- 10 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx的中断待处理位:TIM 中断源
- 11 cnt = TIM_GetCounter(TIM2);//读取定时器2对外部脉冲的计数结果
- 12 if(cnt >= last_cnt)//如果发生过溢出,当前计数结果就有可能比上次的计数结果还小
- 13 pul_num = (unsigned int)(top_watch<<16)+ (unsigned int)(cnt - last_cnt);
- 14 else
- 15 pul_num = (unsigned int)((top_watch-1)<<16) + (unsigned int)(65536 + cnt - last_cnt);
- 16 last_cnt = cnt;//将当前计数结果复制到上次的复制结果寄存,方便下次计算
- 17 frq[i] = pul_num * 100;//由于定时器3是1/100秒溢出一次,所以频率时脉冲个数的100倍
- 18 i++;
- 19 if(i == 10)
- 20 i=0;
- 21 top_watch=0;
- 22 }
- 23 }
TIM3的中断服务程序
- TIM_TIxExternalClockConfig(TIM2,TIM_TIxExternalCLK1Source_TI2,TIM_ICPolarity_Rising,0);
- TIM_SelectInputTrigger(TIM2,TIM_TS_ETRF);
根据图2所示的测周法原理,需要在被测信号周期(Tx2)内对STM32内部的最高频率72MHz(为获得最高测量精度和分辨率)的时钟进行计数。最简单的方式将被测信号作为外部中断源,并在外部中断服务程序中读取定时器中的计数值,但这样做会使中断入口时间也计算在Tx2以内。因此实现测周法的最佳方案,是使用STM32通用定时器或高级定时器的捕获功能(Input Capture)。STM32的输入捕获电路框图如图4所示,它能在定时器的某个通道TIMx_CHy发生指定脉冲边沿的时刻及时地将此时的计数器计数值锁存在“捕获/比较寄存器”中,从而有效地避免了上面提到的方法中进入中断时延造成的计时误差。
配置GPIO
- TIM_TimeBaseStructure.TIM_Period = 65535; //设定计数器溢出值(自动重装值)
- TIM_TimeBaseStructure.TIM_Prescaler = 0; //预分频器
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割因子
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
- TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
- //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基单元
3)配置输入捕获器


- 1 TIM_ICInitTypeDef TIM5_ICInitStructure; //定义输入捕获器初始化结构体
- 2 对初始化结构体TIM5_ICInitStructure中的参数赋值,例如如下代码:
- 3 TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入捕获通道为TIM5_CH1
- 4 TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
- 5 TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
- 6 TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入捕获脉冲分频,不分频
- 7 TIM5_ICInitStructure.TIM_ICFilter = 0x00;//配置输入滤波器 不滤波
- 8 TIM_ICInit(TIM5, &TIM5_ICInitStructure);
配置输入捕获器


- 1 TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
使能定时器中断


- 1 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5中断
- 2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
- 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
- 4 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
- 5 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
配置向量中断控制器NVIC


- 1 TIM_Cmd(TIM5, ENABLE); //使能TIM5
使能定时器


- 1 unsigned short i=0;
- 2 unsigned int pul_width[10];//脉冲周期
- 3 unsigned int pul_frq[10];//对应的脉冲频率
- 4 unsigned short ov_num;//定时器溢出的次数,用于记录之前溢出的次数
- 5 unsigned short last_cap_val=0,cur_cap_val;//当前捕获到的数值和上一次捕获到的数值
- 6 //定时器5中断服务程序(可以能由捕获或定时器溢出)
- 7 void TIM5_IRQHandler(void)
- 8 {
- 9 if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
- 10 //为了增加测量频率的动态范围,定时器溢出次数也要计算,相当于增加了定时器的位数
- 11 ov_num++ ;//溢出次数加一
- 12 if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
- 13 {
- 14 cur_cap_val = TIM_GetCapture1(TIM5);//读取当前捕获发生时的定时器数值
- 15 if(cur_cap_val >= last_cap_val)//如果发生过溢出,当前捕获结果就有可能比上次的捕获结果还小
- 16 pul_width[i] = (unsigned int)(ov_num<<16)+ (unsigned int)(cur_cap_val - last_cap_val);
- 17 else
- 18 pul_width[i] = (unsigned int)((ov_num-1)<<16) + (unsigned int)(65536 + cur_cap_val - last_cap_val);
- 19 pul_frq[i] = 72000000 /(float)pul_width[i] + 0.5;
- 20 //折算为频率,加0.5是为了防止强制类型转换带来的舍弃误差
- 21 last_cap_val = cur_cap_val;/将当前捕获结果复制到上次的捕获结果寄存,方便下次计算
- 22 ov_num = 0;
- 23 i++;
- 24 if(i == 10)
- 25 i = 0;
- 26 }
- 27 TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
- 28 }
编写定时器中断服务程序(含寄出和捕获的操作)
用STM32定时器测量信号频率——测频法和测周法[原创cnblogs.com/helesheng]的更多相关文章
- STM32定时器时间的计算方法
本文出自:https://wenku.baidu.com/view/e3bdfb7601f69e31433294c4.htmlSTM32定时器时间的计算方法STM32中的定时器有很多用法:(一)系统时 ...
- STM32定时器学习---基本定时器
STM32F1系列的产品,除了互联网产品外,工作8个,3种定时器,其中一种就是基本定时器.那么STM32单片机的基本定时器如何操作以及编程呢? 下面我们就来详细的了解一下 STM32F1系列的产品,除 ...
- STM32定时器触发ADC多通道连续采样,DMA缓存结果
STM32的ADC使用非常灵活,采样触发方面:既支持软件触发,定时器或其他硬件电路自动触发,也支持转换完成后自动触发下一通道/轮转换.转换结果存储方面:既支持软件读取和转存,也支持DMA自动存储转换结 ...
- stm32定时器中断类型分析
一直在用的stm32定时器的中断都是TIM_IT_Update更新中断,也没问为什么,直到碰到有人使用TIM_IT_CC1中断,才想到这定时器的中断类型究竟有什么区别,都怪当时学习stm32的时候不够 ...
- STM32 定时器用于外部脉冲计数
STM32 定时器用于外部脉冲计数 第一步,设置GPIO GPIO_InitTypeDef GPIO_InitStructure; /* PA0,PA12-> 左右脉冲输入 */GPIO_Ini ...
- STM32 定时器用于外部脉冲计数(转)
源:STM32 定时器用于外部脉冲计数 STM32 定时器(一)——定时器时间的计算 STM32的定时器是灰常NB的,也是灰常让人头晕的(当然是对于白菜来说的). STM32中的定时器有很多用法: ( ...
- stm32定时器输出移相PWM(非主从模式)
背景:由于项目需要,需要stm32输出任意相角度的PWM 前提知识: 1.stm32定时器的Tim,一般有多个OC.具体差别根据型号来定. 2.定时器的使能,理论上是多个通道同时使能 3.TIM_OC ...
- STM32定时器的预装载寄存器与影子寄存器之间的关系【转】
首先转载: STM32定时器的预装载寄存器与影子寄存器之间的关系 本文的说明依据STM32参考手册(RM0008)第10版:英文:http://www.st.com/stonline/produc ...
- 给初学者的STM32(Cortex-M3)中断原理及编程方法介绍 [原创www.cnblogs.com/helesheng]
本人编著的<基于STM32的嵌入式系统原理及应用>(ISBN:9787030697974)刚刚在科学出版社出版.这本书花费了半年以上的时间,凝聚了笔者作为高校教师和嵌入式工程师的一些经验, ...
随机推荐
- spring处理静态资源方式
1. <mvc:default-servlet-handler/>default-servlet-handler在SpringMVC上下文定义一个org.springframework.w ...
- Javascript的运行效率是原生代码的20%-30%
所以jser们,写代码更仔细些吧. http://www.cnblogs.com/codemood/p/3213459.html
- TCP/IP模型简介和/etc/hosts文件说明
软件=协议的实现. IP决定了主机的位置.端口号决定了进程的位置. 两台主机上的通讯实际是两台主机上两个具体进程的通讯. TCP/IP模型分四层: TCP/IP模型:应用层---传输层----网络层- ...
- rbd的增量备份和恢复
前言 快照的功能一般是基于时间点做一个标记,然后在某些需要的时候,将状态恢复到标记的那个点,这个有一个前提是底层的东西没用破坏,举个简单的例子,Vmware 里面对虚拟机做了一个快照,然后做了一些系统 ...
- MySQL 四种隔离级别详解,看完吊打面试官
转发链接:https://zhuanlan.zhihu.com/p/76743929 什么是事务 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就 ...
- 实验吧[WEB]——程序逻辑问题
拿到题 通过查看网页源代码发现index.txt 通过index.txt我们获得了后端的源代码 我们可以通过我画出来的这两个重要的信息得知 第一个sql查询语句没有任何过滤说明存在SQL注入漏洞. 第 ...
- 实验吧[WEB]——what a fuck!这是什么鬼东西?
解题链接:http://ctf5.shiyanbar.com/DUTCTF/1.html 原题链接:http://www.shiyanbar.com/ctf/56 解题必看: 的jother编码定义: ...
- 云计算之路-出海记:建一个免费仓库 Amazon RDS for SQL Server
上周由于园子后院起火,不得不调兵回去救火,出海记暂时停更,这周继续更新,"出海记"记录的是我们在 AWS 上建设博客园海外站的历程. 在这一记中记录的是我们基于 AWS 免费套餐( ...
- 精尽MyBatis源码分析 - SQL执行过程(二)之 StatementHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 数据丢失如何恢复?EasyRecovery帮你快速实现
在日常使用电脑时,我们经常会遇到误删文件的情况,若文件还未被彻底删除,我们还可以通过电脑中的回收站将其恢复,但若是回收站都被清空的话,想要恢复文件就变得比较困难了,而EasyRecovery可以很好的 ...