1、需求

最近做的一个项目,其中有一个传感器输出是pwm波形,频率代表速度,频率越高速度越快。不同的占空比代表不同的故障类型。占空比10%~90%,频率范围20hz ~1khz。

基于以上的需求,单片机要实现两个功能:
1、测量频率
2、测量占空比
这怎么玩呢?从没搞过啊。

2、需求分析

经过查找资料以及参考正点原子的教程,发现单片机的定时器的输入捕获功能能够实现该功能。

2.1分析


如上图所示,测量占空比和测量频率实际上就是测量波形的长度。
对于占空比,就是测量T2与T1时刻的差值
对于频率,就是测量T3与T1时刻的差值
仔细分析下就这么简单。那么具体怎么实现呢。

2.2 输入捕获模式


上图为输入捕获模式的示意图,具体工作如下:
1、将定时器设置为向上计数模式
2、将定时器通道x设置为上升沿捕获
3、在t1时刻通道x捕获到了上升沿,此时计数值为CCRx1,将定时器cnt清0,相当于将t1时刻置位为0时刻
4、在t1时刻要将定时器捕获模式设置为下降沿捕获
4、在t2时刻捕获到了一个下降沿,此时的定时器计数值为CCRx2,假如t1到t2时刻经过的时间比较长,那么定时器肯定会出现计数值溢出重载,假设溢出了n次。
5、假设定时器的频率为1Mhz,定时器计数值为1000,相当于计数器每增加一次,时间过去了1us。最终
t2-t1=(CCRx2+n*1000)*1 us

以上这个简单的例子可以实现测量pwm的高电平长度,要测量整个pwm波形长度,就需要在上述的t2时刻将定时器捕获模式设置为上升沿,在t3时刻捕获到上升沿,此时的计数值记为CCrx3。此时定时器溢出次数记为n1则
t3-t1=(CCRx3+n1*1000)*1us

通过以上分析便可实现测量pwm波形的占空比以及频率。可以满足上述的需求。

3.代码实现

笔者使用的gd32f3x,与f1基本差不多,只是部分库函数有区别。根据以上的分析,代码中需要有两个中断。
1、定时器溢出中断
2、定时器捕获中断

3.1定时器初始化

void timer2_config(void)
{rcu_periph_clock_enable(RCU_GPIOA);rcu_periph_clock_enable(RCU_AF);gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);/* TIMER0 configuration: generate PWM signals with different duty cycles:TIMER0CLK = SystemCoreClock / 108 = 1MHz */timer_parameter_struct timer_initpara;rcu_periph_clock_enable(RCU_TIMER2);timer_deinit(TIMER2);/* TIMER0 configuration */timer_initpara.prescaler         = 120-1;timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;timer_initpara.counterdirection  = TIMER_COUNTER_UP;timer_initpara.period            = 65535;   //寄存器为16位timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;timer_initpara.repetitioncounter = 0;timer_init(TIMER2,&timer_initpara);timer_icintpara.icpolarity = TIMER_IC_POLARITY_RISING;timer_icintpara.icselection = TIMER_IC_SELECTION_DIRECTTI;timer_icintpara.icprescaler = TIMER_IC_PSC_DIV1;timer_icintpara.icfilter = 0;timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_UP|TIMER_INT_FLAG_CH0);timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icintpara);timer_interrupt_enable(TIMER2,TIMER_INT_UP|TIMER_INT_CH0);nvic_irq_enable(TIMER2_IRQn, 13,0); //中断优先级设置为最低/* auto-reload preload enable */timer_auto_reload_shadow_enable(TIMER2);timer_enable(TIMER2);}

gd32f3x运行的频率最大为120M,上述代码将定时器定时基准设置为1us,定时器计数值设置为最大0xffff(65535),注意timer的计数寄存器长度为16位,最大只能是65535.千万不要将其当做32位,在正点原子的例程中,是将其设置为0xffffff,但实际测试,根本不行的。这一点要注意。
相当于最大定时时长为65.5ms,如果不溢出的话最小测量的频率为15hz。

3.2定时器中断代码

uint16_t over_time = 0;  //记录定时器溢出次数
uint16_t over_timer1 = 0;   //记录t2时刻定时器溢出次数
uint16_t over_timer2 = 0;   //记录t3时刻定时器溢出次数
uint32_t capture_value1 = 0;  //记录t2时刻计数值
uint32_t capture_value2 = 0;  //记录t3时刻计数值
uint8_t capture_state1 = 0;  //状态切换void TIMER2_IRQHandler(void)
{if(timer_interrupt_flag_get(TIMER2,TIMER_INT_FLAG_UP)==SET){over_time++;timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_UP);}if(timer_interrupt_flag_get(TIMER2,TIMER_INT_CH0)==SET){switch(capture_state1){case 0 :  // 捕获到上升沿 清零定时器capture_value1 = 0;  //清0 捕获capture_value2 = 0;  //清0 捕获over_time = 0;over_time1 = 0;over_time2 = 0;timer_disable(TIMER2);timer_counter_value_config(TIMER2,0);   //清0计时器 timer_icintpara.icpolarity = TIMER_IC_POLARITY_FALLING;  //设置为下降沿timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icintpara);timer_enable(TIMER2);capture_state1 = 1;break;case 1 :  //捕获到下降沿over_time1  = over_time ;capture_value1 = timer_channel_capture_value_register_read(TIMER2,TIMER_CH_0);timer_icintpara.icpolarity = TIMER_IC_POLARITY_RISING;  //设置为上升沿降沿timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icintpara);   capture_state1 = 2;break;case 2 :  //捕获到升上沿over_time2  = over_time ;capture_value2 = timer_channel_capture_value_register_read(TIMER2,TIMER_CH_0);   capture_state1 = 3;break;          case 3:     //空状态       break;          }       timer_interrupt_flag_clear(TIMER2,TIMER_INT_CH0);}}

定时器中断函数也比较好理解,设置为4个状态,
0:捕获到第一个上升沿,对应t1,将定时器清零,同时设置为下降沿捕获,状态设置为1
1:捕获到第一个下降沿,对应t2,获取捕获到下降沿时刻时定时器的计数值。然后再设置为上升沿捕获,状态设置为2
2:捕获到第二个上升沿,对应t3,获取捕获到上升沿时刻时定时器的计数值,状态设置为3
3:空状态,主要为了配合主循环中的运行函数,等下面看到主循环代码,就可以知道这个3状态的重要性。

以上就是定时器中断函数的初步分析,也比较简单。

3.3主函数代码

uint32_t duty_cycle,frquency;while(1){if(capture_state1 == 3){duty_cycle = (capture_value1+over_time1*65536)*100/(capture_value2+over_time2*65536);frquency = 1000000/(capture_value2+over_time2*65536);printf("overtime:%d time1:%d time2:%d DutyCycle:%d rate:%d \r\n",over_time1,capture_value1,capture_value2,duty_cycle,frquency);over_time = 0;over_time1 = 0;over_time2 = 0;capture_value1 = 0;capture_value2 = 0;capture_state1 = 0;}     delay(10);}

在主函数中,通过判断当前的状态来计算占空比和频率,如果去掉状态3,只用状态2判断,那么当在中断函数状态1中,将状态设置为2后,退出中断函数,此时主函数发现状态为2便进行了占空比和频率的计算,而此时的capture_value2是0。相当于在T3时刻之前,主函数得到了运行。造成计算错误的问题,这里当时排查了好久,才发现是这个问题,所以最终加上了空状态3,确保主函数运行是在T3时刻之后,所有的数值都是有效的。

4、最终运行效果


可以看到能够正常测量频率和占空比。

GD32测量pwm波频率以及占空比相关推荐

  1. STM32测量PWM波频率及占空比

    测量PWM波频率 PWM模式输入 基本原理 实验(PWM输入部分代码) 测量一段时间内脉冲个数求频率 PWM模式输入 该方式是在STM32输入捕获模式基础上扩展升级的功能,可以测量PWM波的频率及占空 ...

  2. 如何测量PWM波的占空比

    占空比 一个频率波形有信号与无信号的比值叫占空比. 有占空比还要知道频率.眼睛能识别的频率为25HZ. 频率很高时,看不到闪烁,占空比越大,LED越亮: 频率很低时,可看到闪烁,占空比越大,LED越亮 ...

  3. 使用TIM捕获测量PWM频率和占空比

    原理说明 STM32的通用TIM可以捕获输入引脚的上升或下降沿,并获得输入引脚发生变化时的计数值. 如要检测PWM波频率,使用上升沿作为TIM计数器复位条件,每次复位前可获得计数值,可用于计算两次上升 ...

  4. 练习STM32动态更改PWM波频率和占空比

    STM32的PWM波动态调频和调占空比 以TIM3_CH1为例 (1)定时器工作原理 定时器的时基单元包含三个部分:①自动装载寄存器(TIMx_ARR),②预分频器寄存器 (TIMx_PSC),③计数 ...

  5. STM32 PWM波频率、占空比以及死区计算详细讲解

    频率.占空比设置的相关参数: (1)TIM_TimeBaseStructure.TIM_Period   ====== ARR ------>决定周期 (2)TIM_TimeBaseStruct ...

  6. c++ 定时器_【话说定时器系列】之十:PWM输入模式测量脉宽及占空比实验

    STM32定时器是 ST MCU 内部最基础且常用的外设,实际应用尤为普遍.去年,电堂推出了<STM32 TIMER基础及常规应用介绍>,为大家梳理了 STM32 TIMER 的庞大内容, ...

  7. 10. GD32F103C8T6 定时器-测量pwm的占空比和频率

    一. 利用TIM2的输入通道0,通道1测量pwm的占空比和频率 1. 配置gpio void inpit_gpio_config(void) {rcu_periph_clock_enable(RCU_ ...

  8. STM32学习笔记(六)丨TIM定时器及其应用(输入捕获丨测量PWM波形的频率和占空比)

    本篇文章包含的内容 一.输入捕获 1.1 输入捕获简介 1.2 输入捕获通道的工作原理 1.3 输入捕获的主从触发模式 1.4 输入捕获和PWMI结构 二.频率的测量方法 2.1 测频法 2.2 测周 ...

  9. STM32笔记——定时器输入捕获功能(测量PWM的频率和占空比)

    目录 一.概述 二.输入捕获功能 2.1 输入捕获简介 2.2 输入捕获通道 三.输入捕获功能测量PWM波的频率和占空比 3.1 测量频率的方法 3.2 测量过程 一.概述 主要介绍通用定时器的输入捕 ...

最新文章

  1. java.lang.OutOfMemoryError: Java heap space错误及...
  2. boost::intrusive::value_traits用法的测试程序
  3. 很多字段的数据要插入另一张表_一文看懂数据库设计之逻辑设计,值得收藏
  4. 控件属性、事件持久化(转)
  5. 网易视频云分享:如何搭建视频转码集群
  6. 作者:刘剑(1979-),男,中国联合网络通信集团有限公司信息化事业部项目一处工程师...
  7. 这些基因的名字太有才了,研究一下都可以发10分文章
  8. 支付宝蚂蚁森林入选2019年世界环境日实践案例
  9. 典型测试错误(英中文对照)
  10. 守护进程和inetd超级服务器
  11. 1248. 统计「优美子数组」
  12. Ta还没有分享呢,过段时间再来看看吧~ 解决办法
  13. 在 Oracle 中使用正则表达式
  14. Spring Framework标记库初学指南
  15. 【手把手教你】使用QuantLib进行债券估值和期权定价分析
  16. 巴巴运动网学习笔记(76-80)
  17. ElasticSearch head 安装
  18. php微信二维码签到墙互动,微久信微信墙2017全新版本教程第二篇:微信签到/扫码3D签到/微信手绘签到...
  19. 怎样在今日头条引流卖产品?今日头条免费引流技巧?
  20. 程序设计思维与实践 Week12 作业 必做题 A-zjm找数

热门文章

  1. 米思齐(Mixly)图形化系列教程(六)-for循环
  2. Frida hook零基础教程
  3. matlab 伯德图 横坐标步长_【龙腾原创】教您使用matlab画伯德图(看了你就学会了,比mathcad好用多了。谁用谁知道!)...
  4. H5 css伪类选择器
  5. 传美光科技竞标尔必达获胜 收购金额25亿美元
  6. MATLAB教程(1) MATLAB 基础知识
  7. 基于单片机定时闹钟设计
  8. 666666666666.com路路解密破解游戏第一部23题攻略
  9. 中鑫吉鼎|家庭成长期如何进行理财规划
  10. js获取手机品牌型号,系统型号等