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

news2024/12/24 2:09:18

简介

利用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 pin
		the rising edge is used as active edge
		the TIMER2 CH0CV is used to compute the frequency value
		the 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_CI0FE0
	timer_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.coloradmin.cn/o/1277713.html

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

相关文章

JavaSE-习题-循环结构等

第 1 题&#xff08;编程题&#xff09; 题目名称&#xff1a; 打印 X 图形 题目内容&#xff1a; https://www.nowcoder.com/practice/83d6afe3018e44539c51265165806ee4 假设i代表行&#xff0c;j代表列&#xff0c;当ij 或者 ij1 n&#xff0c;此时为星号。其余的都是空格。…

杨志丰:OceanBase助力企业应对数据库转型深水区挑战

11 月 16 日&#xff0c;OceanBase 在北京顺利举办 2023 年度发布会&#xff0c;正式宣布&#xff1a;将持续践行“一体化”产品战略&#xff0c;为关键业务负载打造一体化数据库。OceanBase 产品总经理杨志丰发表了《助力企业应对数据库转型深水区挑战》主题演讲。 以下为演讲…

SmartSoftHelp8,SQL语句美化,格式化,压缩

SQL语句美化&#xff0c;格式化&#xff0c;压缩 下载地址&#xff1a;https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

在oracle中的scn技术

SCN可以说是Oracle中一个很基础的部分&#xff0c;但同时它也是一个很重要的。它是系统中维持数据的一致性和顺序恢复的重要标志&#xff0c;是数据库非常重要的一种数据结构。 转载&#xff1a;深入剖析 - Oracle SCN机制详细解读 - 知乎 (zhihu.com)https://zhuanlan.zhihu.…

【计算机概论 ①】- 电脑:辅助人脑的好工具

目录 一、电脑硬件的五大单元 二、一切设计的起点&#xff1a;CPU 的架构 三、其他单元的设备 四、运行流程 五、电脑的分类 六、电脑上面常用的计算单位&#xff08;容量、速度等&#xff09; 操作系统跟硬件有相当程度的关联性&#xff0c;所以&#xff0c;如果不了解一…

详解原生Spring框架下的类切入点表达式与切入点函数

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

汉威科技家电传感器解决方案,助力智能家电市场蓬勃发展

2017年以来&#xff0c;我国家电市场承压前行&#xff0c;零售总额基本保持在9000亿元左右&#xff0c;虽然距离万亿市场只有一步之遥&#xff0c;却一直未能企及。随着物联网、传感器、AI、云计算、大数据、5G等技术的快速发展迭代&#xff0c;智能家电成为行业转型发展的突破…

C语言结构体详解(一)(能看懂文字就能明白系列)

&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;个人主页&#xff1a; 古德猫宁- &#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;…

re:Invent大会,亚马逊云科技为用户提供端到端的AI服务

11月末&#xff0c;若是你降落在拉斯维加斯麦卡伦国际机场&#xff0c;或许会在大厅里看到一排排AI企业和云厂商相关的夸张标语。走向出口的路上&#xff0c;你的身边会不断穿梭过穿着印有“AI21Lab”“Anthropic”等字样的AI企业员工。或许&#xff0c;你还会被机场工作人员主…

6大关键词:尝新/随心/低忠诚···,全面解读食品饮料行业发展趋势与消费者洞察|徐礼昭

内容&#xff1a;重构零售实验室&商派 《2023食品饮料行业零售数字化洞察报告》节选 作者&#xff1a;徐礼昭&#xff08;商派市场负责人&#xff0c;重构零售实验室负责人&#xff09; 如今品牌的影响力不再止于资本与业绩数字&#xff0c;更多是在产品核心价值以及消费…

Django HMAC 请求签名校验与 Vue.js 实现安全通信

概要 在 Web 应用的开发过程中&#xff0c;确保数据传输的安全性和完整性是一个不容忽视的问题。使用 HMAC&#xff08;Hash-based Message Authentication Code&#xff09;算法对请求内容进行签名校验&#xff0c;是一种常见且有效的安全策略。本文将详细介绍如何在 Django …

Git 简介及异常场景处理

一、简介 介绍Git之前&#xff0c;还得先介绍下 版本控制系统&#xff08;VCS&#xff09;&#xff0c; 和它的发展历史 纵观版本控制系统的发展历史&#xff0c;广义上讲&#xff0c;版本控制工具的历史可以分为三代&#xff1a; 第一代 第一代版本控制系统被称为本地版本控…

组合(回溯+剪枝、图解)

77. 组合 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 样例输入 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],…

LORA概述: 大语言模型的低阶适应

LORA概述: 大语言模型的低阶适应 LORA: 大语言模型的低阶适应前言摘要论文十问实验RoBERTaDeBERTaGPT-2GPT-3 结论代码调用 LORA: 大语言模型的低阶适应 前言 LoRA的核心思想在于优化预训练语言模型的微调过程&#xff0c;通过有效地处理权重矩阵的变化&#xff08;即梯度更新…

Docker中部署并启动RabbitMQ

目的 由于最近频繁更换云服务器&#xff0c;导致环境啥的都需要重新配置&#xff0c;关于RabbitMQ&#xff0c;我在看其他博主的文章时&#xff0c;总是不能第一时间找到想要的配置方法&#xff08;也不是没有&#xff0c;只是花的时间太久&#xff09;&#xff0c;于是打算自己…

接口响应时长几十秒问题排查以及解决

目录 背景 解决方案 总结 背景 线上系统运行几年后&#xff0c;被项目上提bug&#xff0c;有些接口响应很慢&#xff0c;加载页面要几十秒 解决方案 1、步骤一&#xff0c;加索引 性能优化成本高&#xff0c;需要开发周期&#xff0c;临时方案先分析慢sql&#xff0c;通过增…

C语言——深入理解指针(4)

目录 1.回调函数 2. qsort 函数的使用 2.1 排序整型数据 2.2 排序结构体数据 3. qsort 函数的模拟实现 1.回调函数 回调函数就是通过一个函数指针调用的函数。 你把函数的地址作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;被调…

Linux:查看端口占用的进程

命令 netstat -tunlp可以从图中看到&#xff0c;端口被那个进程占用&#xff0c;对应进程的pid是多少。

软件测试工程师如何面试?

首先作为HR的角度&#xff1a; 一般我们面试的时候都会问应聘者一些问题&#xff0c;但是问什么&#xff1f;怎么问&#xff1f;每个HR都会有不同的做法。 有的HR问的比较广泛&#xff0c;有的HR比较注重专业度&#xff0c;还有的HR喜欢问一些开放性的问题&#xff0c;没有标…

版本控制系统Git学习笔记-Git分支操作

文章目录 概述一、Git分支简介1.1 基本概念1.2 创建分支1.3 分支切换1.4 删除分支 二、新建和合并分支2.1 工作流程示意图2.2 新建分支2.3 合并分支2.4 分支示例2.4.1 当前除了主分支&#xff0c;再次创建了两个分支2.4.2 先合并test1分支2.4.3 合并testbranch分支 2.5 解决合并…