STM32 HAL库高级定时器输入捕获脉宽测量

STM32 HAL库高级定时器输入捕获脉宽测量


  • 📌相关篇《STM32 HAL库定时器输入捕获SlaveMode脉宽测量》
  • ✨相比于上面所使用的高级定时器输入捕获从模式来测量PWM信号,实现方法更为复杂一下,但是还是将实现的方法记录下来。
  • 📌本篇实现方法内容参考《定时器TIM的输入捕获——正交编码器模式与PWM输入》
  • 🔖想了解详细的有关实现方法可以前往相关篇内容了解。
  • 🌿本篇基于STM32f030R8单片机。
📓本工程主要改善了,减少测量误差,将测量换算内容,换到了中断函数中执行,用时间换精度。并且采用多次读取测量结果,取多次连续测量值中,出现频率最高的数值作为输出值,有效减少单次数据异常情况。

🛠STM32CubeMX配置

  • 🔧高级定时器1配置:(👉🏻在参数配置上,尽可能的将捕获定时器的自动载计数值设置大一点,减少定时器溢出更新事件)
    在这里插入图片描述
  • 🌿时钟源:外部时钟
  • 🌿定时器1分频系数,更具个人使用的芯片型号而定。
  • 🌿向上计数方式。
  • 🌿不开启自动重装载(auto-reload preload),相对于不使能影子寄存器。
  • 其他都是默认选项配置。
  • 🔨 配置定时器14作为一个PWM信号输出源:
    在这里插入图片描述

  • 🔰使能定时器捕获、更新中断,以及中断优先级配置:(TIM1更新中断 > TIM1捕获中断)
    在这里插入图片描述

📑功能代码实现部分

  • 📝中断回调函数:
/*** @brief 输入捕获回调函数* @retval None*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim)
{static uint8_t RisingEdge_count = 0;if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){if(capture_flag & 0x40)										//0X40是0100 0000,高电平期间捕获到下降沿{capture_flag &= 0x3F;										//0X3F是0011 1111,清除捕获到上升沿的标记位和捕获完成的标记位value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);	//获取当前的捕获值__HAL_TIM_DISABLE(htim);        						//关闭定时器__HAL_TIM_SET_COUNTER(htim, value2);						//以value2为基准重新计数TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1);      	//复位极性选择才能进行下行配置/*输入捕获功能的重配与开启,硬件启动会产生几个时钟的延迟*/TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);	//下次上升沿捕获__HAL_TIM_ENABLE(htim);									//重开定时器}else	            								 		//捕获到上升沿{capture_flag |= 0x40;										//0X40是0100 0000,标记捕捉到了一次上升沿RisingEdge_count++;if((RisingEdge_count % 2 == 0))								//每捕获两次相同跳变沿表示过了一个PWM周期{value3 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //检测完一个周期的那个上升沿为value3capture_flag |= 0x80;								 //标记捕获完了一个周期Pulse_Width = value2 + OverflowCount_high * TIM1_Period_Value - value1 + 4;	//经验值:再进行4个时钟的补偿PWM_Period_ARR[PWM_Period_CNT++] = value3 + OverflowCount_high * TIM1_Period_Value + OverflowCount_low * TIM1_Period_Value - value1 + 7;if(PWM_Period_CNT == 5){PWM_Period = findMostFrequentNum(PWM_Period_ARR, 5);PWM_Period_CNT = 0;}OverflowCount_high = OverflowCount_low = 0;//清空溢出计数__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);//清零中断标志位}else				 								   //正在检测PWM信号的第一个上升沿,意味着下次捕获下降沿{capture_flag &= 0x7F;								 //0X7F是0111 1111,清除PWM捕获完成标志,开始新一轮PWM周期捕获value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //第一个上升沿是value1}__HAL_TIM_DISABLE(htim);__HAL_TIM_SET_COUNTER(htim, value1);					//以value1为基准重新计数TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1);  	//复位极性选择才能进行下行配置TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);	//下次下降沿捕获__HAL_TIM_ENABLE(htim);								//重开定时器}}
}/*** @brief (高级定时器TIM特有)更新溢出中断函数*/
//void TIM1_UP_IRQHandler(void)
//{
//    HAL_TIM_IRQHandler(&htim1);
//}
/*** @brief 更新溢出回调函数* @retval None*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{if((capture_flag & 0X80) == 0)			//PWM的一个周期没检测完{if(capture_flag & 0x40)				//在高电平期间溢出M次{OverflowCount_high++;}else								//在低电平期间溢出N次{OverflowCount_low++;}}else								   //PWM的一个周期检测完了{OverflowCount_high = 0;OverflowCount_low = 0;}
}
  • ⚡连续读取的数值中获取出现频率最高的数值实现方法:
//比较函数,用于排序
int compare(const void* a, const void* b)
{return (*(int*)a - * (int*)b);
}uint32_t findMostFrequentNum(uint32_t arr[], int size)
{// 对数组进行排序qsort(arr, size, sizeof(int), compare);//需要包含stdlib.h头文件int maxCount = 1; // 最大重复次数int currentCount = 1; // 当前元素的重复次数uint32_t mostFrequentNumber = arr[0]; // 最频繁出现的数for(int i = 1; i < size; i++){if(arr[i] == arr[i - 1]){// 如果当前元素与前一个元素相同,则重复次数加1currentCount++;}else{// 如果当前元素与前一个元素不同,则重复次数重置为1currentCount = 1;}if(currentCount > maxCount){// 如果当前元素的重复次数超过最大重复次数,则更新最大重复次数和最频繁出现的数maxCount = currentCount;mostFrequentNumber = arr[i];}}return mostFrequentNumber;
}
  • 📗main函数代码以及相关变量定义:
/* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
volatile char capture_flag = 0;				//捕获状态标记变量,0x80最高位标记捕获完一个周期,0x40表示捕获到了上升沿
volatile uint8_t OverflowCount_high = 0;		//高电平期间溢出次数
volatile uint8_t OverflowCount_low = 0;		//低电平期间溢出次数
volatile uint32_t value1, value2, value3;	  //下图中三个边沿中的值
volatile uint32_t Pulse_Width = 0;		  //脉宽
volatile uint32_t PWM_Period = 0;				//周期
uint32_t PWM_Period_ARR[5] = {0};
uint8_t PWM_Period_CNT = 0;
/* USER CODE END PV */int main(void)
{/* USER CODE BEGIN 1 */uint32_t TimerUART;
//    uint16_t plusewidth = 500;//脉冲宽度;f=1000 000/500=2000Hz
//    uint16_t plusedelay = 20;//脉宽40us/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM1_Init();MX_TIM14_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */uint32_t sysclock = 0;
//sysclock =RCC_GetHSIFreq();sysclock = HAL_RCC_GetSysClockFreq();//RCC_GetHSIFreq()TimerUART = HAL_GetTick();printf("STM32F030 SysClockFreq:%d \r\n", sysclock);
//		__HAL_TIM_SET_AUTORELOAD(&htim14, plusewidth - 1); //调整分频系数,可以改变arr以改变频率
//    __HAL_TIM_SET_COMPARE(&htim14, TIM_CHANNEL_1, plusedelay); //PWM脉冲宽度,修改占空比比较值/* 使能PWM输出 */HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1);/* 清零中断标志位 */__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);/* 使能定时器的更新事件中断 */__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);/* 使能输入捕获 */HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */if((HAL_GetTick() - TimerUART) > 1000){printf("/********************/\r\n");printf("脉宽为: %d us\r\n", Pulse_Width);printf("周期为:	%d us\r\n", PWM_Period);printf("/********************/\r\n");TimerUART = HAL_GetTick();}}/* USER CODE END 3 */
}
  • 📜测试调试输出:
    在这里插入图片描述
    在这里插入图片描述
  • ✨修改PWM相关参数测试了几次,结果也没有发现测量的输出结果异常,符合预期。

📚测试工程

链接:https://pan.baidu.com/s/1pgs9OFyiI291pxBMsuutdQ 
提取码:rotp

  • 🔖此文章仅作为个人学习探索知识的总结,不作为他人或引用者的理论依据,由于学识所限,难免会出现错误或纰漏,欢迎大家指正。

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

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

相关文章

0基础学习PyFlink——Map和Reduce函数处理单词统计

在很多讲解大数据的案例中&#xff0c;往往都会以一个单词统计例子来抛砖引玉。本文也不免俗&#xff0c;例子来源于PyFlink的《Table API Tutorial》&#xff0c;我们会通过几种方式统计不同的单词出现的个数&#xff0c;从而达到循序渐进的学习效果。 常规方法 # input.py …

正点原子嵌入式linux驱动开发——pinctrl和gpio子系统

在上一篇笔记中&#xff0c;学习编写了基于设备树的LED驱动&#xff0c;但是驱动的本质还是没变&#xff0c;都是配置LED灯 所使用的GPIO寄存器&#xff0c;驱动开发方式和裸机基本没区别。Linux是一个庞大而完善的系统&#xff0c;尤其是驱动框架&#xff0c;像GPIO这种最基本…

二叉树,堆排序及TopK问题

要讲二叉树的概念&#xff0c;就要先讲树的概念。 树是什么呢&#xff1f; 树其实是一种储存数据的结构&#xff0c;因为他的结构倒过来和生活中的树很相似所以才被称之为树。 这是一颗多叉树&#xff0c;从最顶端的节点可以找到下边的几个节点&#xff0c;下边的节点又可以找…

Chrome插件精选 — 标签效率管理插件

Chrome实现同一功能的插件往往有多款产品&#xff0c;逐一去安装试用耗时又费力&#xff0c;在此为某一类型插件挑选出比较好用的一款或几款&#xff0c;尽量满足界面精致、功能齐全、设置选项丰富的使用要求&#xff0c;便于节省一个个去尝试的时间和精力。 1. OneTab Plus 下…

从0-1,使用腾讯OCR进行身份证识别

目录 1.申请腾讯OCR权限 2.代码思路 3.Postman测试​ 1.申请腾讯OCR权限 获取 secretId 和 secretKey&#xff0c;见上文从0到1&#xff0c;申请cos服务器并上传图片到cos文件服务器-CSDN博客https://blog.csdn.net/m0_55627541/article/details/133902798 2.代码思路 入参…

【PXIE301-211】青翼科技基于PXIE总线的16路并行LVDS数据采集、1路光纤数据收发处理平台

板卡概述 PXIE301-211是一款基于PXIE总线架构的16路并行LVDS数据采集、1路光纤收发处理平台&#xff0c;该板卡采用Xilinx的高性能Kintex 7系列FPGA XC7K325T作为实时处理器&#xff0c;实现各个接口之间的互联。板载1组64位的DDR3 SDRAM用作数据缓存。板卡具有1个FMC&#xf…

2023_Spark_实验十四:SparkSQL入门操作

1、将emp.csv、dept.csv文件上传到分布式环境&#xff0c;再用 hdfs dfs -put dept.csv /input/ hdfs dfs -put emp.csv /input/ 将本地文件put到hdfs文件系统的input目录下 2、或者调用本地文件也可以。区别&#xff1a;sc.textFile("file:///D:\\temp\\emp.csv&qu…

OpenLDAP LDIF详解

手把手一步步搭建LDAP服务器并加域 有必要理解的概念LDAPWindows Active Directory 服务器配置安装 OpenLDAP自定义安装修改对象&#xff08;用户和分组等&#xff09;修改olcSuffix 和 olcRootDN 属性增加olcRootPW 属性修改olcAccess属性验证新属性值 添加对象&#xff08;用…

【C语言必知必会 | 第四篇】一文带你精通顺序结构

引言 C语言是一门面向过程的、抽象化的通用程序设计语言&#xff0c;广泛应用于底层开发。它在编程语言中具有举足轻重的地位。 此文为【C语言必知必会】系列第四篇&#xff0c;进行C语言顺序结构的专项练习&#xff0c;结合专题优质题目&#xff0c;带领读者从0开始&#xff0…

[人工智能-综述-12]:第九届全球软件大会(南京)有感 -1-程序员通过大模型增强自身软件研发效率的同时,也在砸自己的饭碗

目录 前言&#xff1a; 一、什么是软件工程 1.1 什么软件工程 1.2 影响软件开发效能的三大因素 1.3 AI大模型是如何提升软件工程全过程效率的 二、AI大模型如何提升软件项目管理效率 2.1 概述 2.2 案例或工具 三、AI大模型如何提升软件开发工具的效率 3.1 概述 3.2 …

Git GUI使用笔记

看这个视频 Git GUI基本使用_哔哩哔哩_bilibili 1 下载 Git-2.42.0.2-64Window64位安装包-最新版资源-CSDN文库 安装软件就一路next就可以 2 配置 空白处右键&#xff0c;选择Open Git Bash here &#xff0c;输入下面两行配置信息 git config --global user.name "Y…

小程序之自定义组件 结合案例(会议OA的会议/投票管理及个人中心的搭建)详解 (4)

⭐⭐ 小程序专栏&#xff1a;小程序开发专栏 ⭐⭐ 个人主页&#xff1a;个人主页 目录 一.前言 二.小程序自定义组件及其使用 2.1 自定义组件的使用 三.使用自定义组件完成会议功能界面的实现 3.1 导航栏的实现 3.2 会议界面内容的实现 四.投票管理界面 五.个人中心 今天…

uview组件使用笔记

图标样式 修改图标的样式 通过color参数修改图标的颜色通过size参数修改图标的大小&#xff0c;单位为rpx 效果图 <u-icon name"photo" color"#2979ff" size"28"></u-icon>图片图标 1.3.0 这里说的图片图标&#xff0c;指的是小…

7、Linux驱动开发:设备-自动创建设备节点

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

【力扣刷题】回文链表、环形链表、合并两个有序链表

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 刷题篇 一、回文链表1.1 题目描述1.2 思路分…

msvcr120.dll缺失怎么修复,快速修复msvcr120.dll丢失的三个有效方法

随着计算机技术的不断发展&#xff0c;我们在使用软件或游戏时经常会遇到各种错误提示&#xff0c;其中找不到msvcr120.dll就是一种常见的错误。那么&#xff0c;msvcr120.dll是什么&#xff1f;它的作用是什么&#xff1f;如何修复这一错误呢&#xff1f;本文将为您详细介绍几…

7.7亿参数,超越5400亿PaLM!UW谷歌提出「分步蒸馏」,只需80%训练数据|ACL 2023

LLM不实用&#xff0c;小模型蒸馏才是「现实」的大模型应用路线&#xff0c;全面领先微调技术&#xff01;土豪请无视。。。 大型语言模型虽然性能优异&#xff0c;可以用零样本或少样本提示解决新任务&#xff0c;但LLM在实际应用部署时却很不实用&#xff0c;内存利用效率低…

基于Java的汽车维修预约管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

群晖synology DSM 7.2设置钉钉Webhooks通知

现在越来越多的小伙伴都有了自己的Nas系统&#xff0c;为了更加方便的接收Nas的消息&#xff0c;这篇文章带着大家一起配置一个钉钉&#xff08;机器人&#xff09;即时消息通知 首先登录钉钉的开放平台&#xff1a;开发者后台统一登录 - 钉钉统一身份认证 1.创建一个机器人&…