GD32 定时器输入捕获模式测量PWM占空比和频率

简介

利用GD32 定时器的PWM输入捕获模式来实现PWM波形的占空比和频率的测量。相应的简介可以参考GD32用户手册中关于定时器输入捕获的章节,PWM输入捕获模式是输入捕获模式的一个特例。(记录自己学习过程,如有错误请留言指出)

原理

如何利用定时器测量一个PWM的频率和占空比

只需要测量出下面两个时间 T1 和 T2 即可算出。

frequency =  1/ T1            duty cycle =  T2/T1

再来简单看看定时器输入捕获的原理

通 道 输 入 信 号 CIx 有 两 种 选 择 , 一 种 是 TIMERx_CHx 信 号 , 另 一 种 是
TIMERx_CH0,TIMERx_CH1 和 TIMERx_CH2 异或之后的信号。通道输入信号 CIx 先被
TIMER_CK 信号同步,然后经过数字滤波器采样,产生一个被滤波后的信号。通过边沿检测
器,可以选择检测上升沿或者下降沿。通过配置 CHxP 选择使用上升沿或者下降沿。配置
CHxMS.,可以选择其他通道的输入信号,内部触发信号。配置IC 预分频器,使得若干个输入
事件后才产生一个有效的捕获事件。捕获事件发生, TIMERx_CHxCV 存储计数器的值。
 

如何使用定时器捕获PWM

用户手册里面的描述如下,我们来进行一步一步拆解:

(1)首先一个 PWM波连接到 CI0,在代码中配置TIM2的CH0输入进来,也就是选择了CI0输入信号为TIMER2_CH0 。

(2) 然后配置 TIMERx_CHCTL0 寄存器中 CH0MS 为2’b01,选择通道0 的捕获信号为CI0 并设置上升沿捕获。

(3) 配置 TIMERx_CHCTL0 寄存器中 CH1MS 为2’b10,选择通道1捕获信号为 CI0 并设置下降沿捕获。

具体怎么配置上升沿和下降沿捕获呢,可以看到下面的寄存器配置

内部捕获通道0设置为上升沿捕获,内部捕获通道1设置为下降沿捕获,在代码实现中其实只需要设置内部捕获通道0为上升沿,代码默认设置了内部捕获通道1为下降沿捕获,具体如下:

void timer_input_pwm_capture_config(uint32_t timer_periph, uint16_t channel, timer_ic_parameter_struct* icpwm)
{//进行了省略,只保留了配置极性/* Set channel input polarity */if(TIMER_IC_POLARITY_RISING == icpwm->icpolarity){    //极性取了反icpolarity = TIMER_IC_POLARITY_FALLING;}else{icpolarity = TIMER_IC_POLARITY_RISING;}if(TIMER_CH_0 == channel){/* reset the CH0P and CH0NP bits */TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH0P|TIMER_CHCTL2_CH0NP));/* set the CH0P and CH0NP bits */TIMER_CHCTL2(timer_periph) |= (uint32_t)(icpwm->icpolarity);/* reset the CH1P and CH1NP bits */TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH1P|TIMER_CHCTL2_CH1NP));   //利用icpolarity 配置/* set the CH1P and CH1NP bits */TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)icpolarity << 4U);}
}

(2) (3) 两步的配置CHxMS主要是,为了把经过边沿选择器生成的上升沿触发信号和下降沿触发信号分别映射到IS0和IS1上 (个人理解这个IS0和IS1是用于分别输入内部的输入捕获CH0通道和CH1通道,用于实现两个输入通道对1个信号的上升沿捕获和下降沿捕获,也就是一个信号输入到两个输入捕获器,只不过一个上升沿触发,一个下降沿触发)

定时器主从管理——复位模式

把TIM2设置为主从管理复位模式,触发源选择CI0FE0,当外部信号为上升沿时触发,根据复位模式的定义,上升沿触发时,会将定时器的计数值清空。定时器主从复位模式,真的是完美契合用于测量PWM频率和占空比,这里借用一下ST手册里面的图来理解一下具体怎么测量频率和占空比的。

第一次配置好定时器后,输入的上升沿会触发定时器,让定时器的计数归0,后面每一次下降沿触发时,CCR2记录定时器的CNT值,也就是高电平时间,上升沿触发时CCR1记录定时器的CNT值,也就是一个周期的时间,然后再将定时器复位从0开始计数。GD32中 CCR1为 CH0CV,CCR2为CH1CV。

(吐槽一下GD32的框图画的是真难理解,很多都是参考ST的框图来进行理解)

具体代码实现

void timer2_pwm_inputcapter_init(unsigned short arr, unsigned short psc)
{rcu_periph_clock_enable(RCU_GPIOA);rcu_periph_clock_enable(RCU_AF);/*configure PA6 (TIMER2 CH0) as alternate function*/gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);/* TIMER2 configuration: PWM input mode ------------------------the external signal is connected to TIMER2 CH0 pinthe rising edge is used as active edgethe TIMER2 CH0CV is used to compute the frequency valuethe TIMER2 CH1CV is used to compute the duty cycle value------------------------------------------------------------ */timer_ic_parameter_struct timer_icinitpara;timer_parameter_struct timer_initpara;rcu_periph_clock_enable(RCU_TIMER2);timer_deinit(TIMER2);/* TIMER2 configuration */timer_initpara.prescaler = psc;timer_initpara.alignedmode = TIMER_COUNTER_EDGE;timer_initpara.counterdirection = TIMER_COUNTER_UP;timer_initpara.period = arr;timer_initpara.clockdivision = TIMER_CKDIV_DIV1;timer_initpara.repetitioncounter = 0;timer_init(TIMER2, &timer_initpara);/* TIMER2 configuration *//* TIMER2 CH0 PWM input capture configuration */timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; // 配置了 CH0P   [CH0NP==0, CH0P==0]:把 CIxFE0 的上升沿作为捕获或者从模式下触发的有效信// 号,并且 CIxFE0 不会被翻转。timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;timer_icinitpara.icfilter = 0x0;timer_input_pwm_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);/* slave mode selection: TIMER2 */timer_input_trigger_source_select(TIMER2, TIMER_SMCFG_TRGSEL_CI0FE0); // 触发中断源选择 TIMER_SMCFG_TRGSEL_CI0FE0timer_slave_mode_select(TIMER2, TIMER_SLAVE_MODE_RESTART);			  // 配置定时器为复位模式/* select the master slave mode */ // 复位模式. 选中的触发输入的上升沿重新初始化计数器,并且产生更新事件timer_master_slave_mode_config(TIMER2, TIMER_MASTER_SLAVE_MODE_ENABLE);/* auto-reload preload enable */timer_auto_reload_shadow_enable(TIMER2);/* clear channel 0 interrupt bit */timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0);/* channel 0 interrupt enable */timer_interrupt_enable(TIMER2, TIMER_INT_CH0);/* channel 0 interrupt enable */timer_interrupt_enable(TIMER2, TIMER_INT_CH0); // 允许更新中断和CH0捕获中断nvic_irq_enable(TIMER2_IRQn, 5, 0);/* 创建消息队列用于接收数据 */xQueueTime2capter = xQueueCreate(10, sizeof(timer2_ic_pwm_struct));if (NULL == xQueueTime2capter){while (1);}/* TIMER2 counter enable */timer_enable(TIMER2);
}__IO uint16_t dutycycle = 0;
__IO uint16_t frequency = 0;
void TIMER2_IRQHandler(void)
{timer2_ic_pwm_struct ic_data;BaseType_t xHigherPriorityTaskWoken;xHigherPriorityTaskWoken = pdFALSE;if (SET == timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_CH0)){/* clear channel 0 interrupt bit */timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0);/* read channel 0 capture value */ic1value = timer_channel_capture_value_register_read(TIMER2, TIMER_CH_0) + 1;if (0 != ic1value){/* read channel 1 capture value */ic2value = timer_channel_capture_value_register_read(TIMER2, TIMER_CH_1) + 1;/* calculate the duty cycle value */dutycycle = (ic2value * 100) / ic1value;/* calculate the frequency value */frequency = 1000000 / ic1value;ic_data.dutycycle = dutycycle;ic_data.frequency = frequency;ic_data.cnt = timer_counter_read(TIMER2);xQueueSendFromISR(xQueueTime2capter, &ic_data, &xHigherPriorityTaskWoken);/* Now the buffer is empty we can switch context if necessary. */if (xHigherPriorityTaskWoken){/* Actual macro used here is port specific. */portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}}else{dutycycle = 0;frequency = 0;}}
}

输入一个5Khz,50%占空比的方波,使用pwm输入捕获测量的结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/190812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VUE设计与实现共读系列之ref的实现【响应式原理】

前言 我们先顺一下vue使用响应式数据的流程&#xff1a; vue 是通过 ref 和 reactive 来创建响应式值&#xff0c;改变响应式值&#xff0c;视图跟着发生变化。 我们今天就来看一下ref和reactive是如何实现的 准备 首先&#xff0c;打开ref函数的位置 我们可以看到一个被re…

SmartSoftHelp8,SQL语句优化,耗时,返回数据行,kb

SQL语句优化 SQL语句耗时测试&#xff0c;耗时优化 SQL语句查询返回数据行统计 SQL语句查询返回数据大小统计&#xff0c;kb 总量统计 下载地址&#xff1a;https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

施人玫瑰手留余香和影像组学、医学人工智能未来漫谈

今天收到进阶班学员的留言&#xff1a; 提示&#xff1a;本文有硬核软文嫌疑&#xff0c;请慎重阅读。“ 我用您给我们讲的CLEAR&#xff0c;与一个审稿人进行了battle。有理有据。评估下来&#xff0c;我感觉我们的文章还是挺符合CLEAR的。” 我从来不排斥在商言商&#xff0…

12月02日每日信息差

_灵感 &#x1f396; 六国入境免签首日2029人次享便利 &#x1f384; 国内首个超大规模“光伏气膜”项目在江苏投运 &#x1f30d; 东京将推出氢气交易市场 &#x1f30b; 中国疾控中心&#xff1a;建议尽早接种流感疫苗&#xff0c;尤其是老年人和儿童 &#x1f381; 偏高1.…

MySQL列操作记录

在 MySQL 中&#xff0c;你可以使用多种命令和语句来执行列操作&#xff0c;包括添加、修改、删除列等。以下是一些与列操作相关的常用 MySQL 命令和语句&#xff1a; 1. 添加列&#xff1a; 添加新列到表格中&#xff1a; ALTER TABLE table_name ADD COLUMN column_name d…

01_学习使用javax_ws_rs_上传文件

文章目录 1 前言2 Maven 依赖3 上传接口4 如何解析 MultipartFormDataInput5 结语 1 前言 使用 Spring MVC 来处理文件上传&#xff0c;想必是大家耳熟能详的了&#xff0c;如下代码&#xff1a; ResponseBody PostMapping("/upload") public String upload(Request…

【Qt开发流程】之事件系统1:事件系统描述及键盘事件

Qt的事件系统 在Qt中&#xff0c;事件是对象&#xff0c;派生自抽象的QEvent类&#xff0c;它表示应用程序内部发生的事情或作为应用程序需要知道的外部活动的结果。事件可以由QObject子类的任何实例接收和处理&#xff0c;但它们与小部件特别相关。以下描述了在典型应用程序中…

MATLAB算法实战应用案例精讲-【图像处理】数字图像处理(补充篇)

目录 算法原理 数字图像处理常用算法 1.二值化: 2.海报化 3.灰度化

基于ZLMediaKit的webrtc实时视频传输demo搭建

环境 ubuntu 20.04 ​ gcc version 9.4.0 ​ cmake version 3.16.3 部署ZLMediaKit流媒体服务器 安装openssl 首先可以检查一下自己的openssl的版本如果是1.1.1以上就可以忽略这一步 wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz tar -xvzf openssl-1.1.1k…

【新论文】【模型攻击】DiffAttack 针对基于扩散的对抗性净化的逃避攻击

DiffAttack: Evasion Attacks Against Diffusion-Based Adversarial Purification 作者: Mintong Kang; Dawn Song; Bo Li 链接: http://arxiv.org/pdf/2311.16124v1 备注: Accepted to NeurIPS 2023 摘要: 基于扩散的净化防御利用扩散模型去除对抗样本的精心设计的扰动&#…

酷开科技 | 酷开系统,让家庭娱乐方式焕然一新!

在这个快节奏的社会&#xff0c;家庭娱乐已成为我们日常生活中不可或缺的一部分&#xff0c;为了给家庭带来更多欢笑与感动&#xff0c;酷开科技发力研发出拥有丰富内容和技术的智能电视操作系统——酷开系统&#xff0c;它集合了电影、电视剧、综艺、游戏、音乐等海量内容&…

我的2023年12月02日对文章发送的一个测试

1 Markdown.com.cn 简介 支持自定义样式的 Markdown 编辑器支持微信公众号、知乎和稀土掘金点击右上方对应图标&#xff0c;一键复制到各平台 2 Markdown语法教程 2.1 标题 不同数量的#可以完成不同的标题&#xff0c;如下&#xff1a; 一级标题 二级标题 三级标题 2.2…

C语言-指针_01

指针基础 1. 概述 地址编号&#xff1a;计算机为了存储数据&#xff0c;每一个程序在 32位 机中 占4G&#xff0c;最小操作单位 是 一个字节&#xff0c;每一个字节都有其对应的地址&#xff0c;该地址就是 地址编号。 指针&#xff1a;地址编号这个数据 的 数据类型。 指针变…

Java数组与List互换

asList():将数组转成list //将数组转换为listint[][] nums {{7,0},{4,4},{7,1},{5,0},{6,1},{5,2}};List<int[]> list new LinkedList<>(Arrays.asList(nums));for (int[] ints :list) {System.out.println(ints[0] " " ints[1]); //遍历list}toAr…

TPC通信-BS架构

BS架构-基本原理 BS框架基本原理 使用线程池对BS架构进行优化

docker部署typecho博客

文章目录 1.安装git2.安装compose3.拉取仓库4.创建目录5.配置文件修改6.启动容器7.修改MYSQL数据库8.安装成功9.参考GitHub文档 1.安装git 安装git yum -y install git2.安装compose &#xff08;docker安装参考&#xff1a;docker基本知识&#xff09; 确保已经安装了 Doc…

爬虫学习-基础(HTTP原理)

目录 一、URL和URI 二、HTTP和HTTPS &#xff08;1&#xff09;HTTP &#xff08;2&#xff09;HTTPS &#xff08;3&#xff09;HTTP与HTTPS区别 &#xff08;4&#xff09;HTTPS对HTTP的改进&#xff1a;双问的身份认证 三、TCP协议 &#xff08;1&#xff09;TCP三次握手…

⭐ Unity 里让 Shader 动画在 Scene 面板被持续刷新

写 Unity Shader的时候&#xff0c;只有播放状态下的 Game 面板能看到Shader 顺畅的动态效果&#xff0c;不方便。 想要带有动态效果的 Shader 在 Scene 面板持续更新动画&#xff0c;只需要打开一个开关就能让 Scene 持续刷新动画了。 感谢大家的观看&#xff0c;您的点赞和关…

android 13.0 launcher3中workspace app列表页不显示某个app图标

1.概述 在13.0的系统ROM定制化开发中,Launcher3 workspace的app列表页 会负责加载系统中app的所有图标 但针对某个不需要显示在桌面的app图标需要过滤掉 所以需要在加载和更新的时候过滤 需要更改两处地方, 一处是 加在列表时 一处是安装卸载app 更新app列表时,接下来具体分…

learn2learn环境配置(2023年12月)

learn2learn是元学习方向的一个非常实用的库&#xff0c;但其发布时间较早&#xff0c;与最新版本的pytorch可能存在一些兼容性问题&#xff0c;在2023年12月这个时间进行安装时会遇到一些问题&#xff0c;以下是我遇到的问题及解决的方法。 1. 在我第一次直接配置“pip instal…