STM32的HAL库开发-通用定时器输入捕获实验

一、通用定时器输入捕获部分框图介绍

1、捕获/比较通道的输入部分(通道1)

首先设置 TIM_CCMR1的CC1S[1:0]位,设置成01,那么IC1来自于TI1,也就是说连接到TI1FP1上边。设置成10,那个IC1来自于TI2,连接到TI2FP1上。设置成11,将IC1连接到TRC上边。

假设IC1连接到TI1FP1上,那么TIMx_CH1作为输入,首先来到一个滤波器,滤波器需要设置TIMx_CCMR1的ICF[3:0]位设置滤波方式,配合着通过设置TIMx_CR寄存器的CKD[1:0]位,设置采样频率fCKD。这个在前面通用定时器讲过。

然后输入信号来到边沿检测器,通过设置TIMx_CCER的CC1P位设置边沿检测方式。设置之后上升沿或者下降沿只有一个信号能进来,然后经过一个捕获分频器,通过设置TIMx_CCMR1的IC1PS[1:0]位,设置捕获分频系数。

最后使能TIMx_CCER的CC1E位,信号就来到了捕获/比较寄存器了。

2、捕获/比较通道1的主电路---输入部分

首先CC1S需要设置成输入模式,同时将CC1E设置为1,使能捕获。图中IC1PS信号来自于前面的分频后的捕获信号。 经过一个与门结果为1,上面的或门至少有一个为1,结果为1,与门为1那么经过或门还是1,下面的那个CC1G信号为软件产生捕获事件。这样就会产生一个捕获事件,计数器的值就会转移到捕获/比较影子寄存器里边。

捕获/比较影子寄存器不能直接读,需要将值转移到捕获/比较寄存器里边,那么需要capture_transfer条件。需要与门的两个信号都是1,CC1S信号一定是1,上面那个信号是raed操作,也就是说在读CCR1寄存器的时候不能转移数据。

例子:捕获信号一个脉冲信号

假如有一个脉冲信号,首先配置上升沿捕获,当上升沿来的时候,经过前面的滤波器分频器来到IC1PS,然后产生捕获事件,计数器的值转移到捕获/比较寄存器里边,然后程序读取CCR1的值即为CNT1,马上将输入设置为下降沿触发,然后再读取CCR1寄存器的值,设置为CNT2,利用CNT2的值减去CNT1的值,得到计数的个数,乘上一个数的事件,就得到了脉冲事件。

二、通用定时器输入捕获脉宽测量原理

首先将输入捕获通道配置成上升沿触发,对应图中就是在t1时刻产生上升沿,此实计数器的值会转移到捕获比较寄存器里,记为CCRx1。然后同是将计数器的值设置为0。之后有两种发情况,一种就是高电平时间非常短,在计时器一个周期里边下降沿就来了,那么计数个数就是t2时刻对应的CCRx2的值。第二种情况是在t1时刻与t2时刻之间,计数器发生了N次溢出事件,那么总共的计数器个数就是(ARR + 1)*N + CRRx2。计时器记一个数的时间乘上总共记得个数,就是高电平总共时间。时钟频率PCLK除分频系数PSC,就是计数器得工作频率,再取倒数,就是记一个数得时间。

三、通用定时器输入捕获实验配置步骤

1、HAL_TIM_IC_init()函数,配置定时器基础工作参数。,与base_init()函数一样

2、HAL_TIM_IC_MspInit()函数,配置NVIC、CLOCK、GPIO等。

3、HAL_TIM_IC_ConfigChannel()函数,配置输入通道映射、捕获边沿等。

4、HAL_NVIC_SetPriority()、HAL_NVIC_EnablelRQ()函数,设置优先级,使能中断。

5、__HAL_TIM_ENABLE IT()宏定义,使能定时器更新中断。

6、HAL_TIM_IC_Start_IT()函数,使能捕获、捕获中断及计数器。

7、TIMx IROHandler()->HAL TIM IROHandler(),中断服务函数。

8、HAL_TIM_PeriodElapsedCallback()函数,更新中断回调函数

HAL_TIM_IC_CaptureCallback()函数,输入捕获中断回调函数。

四、通用定时器输入捕获实验

实验:通过定时器5通道1来捕获按键高电平脉宽时间,通过串口打印出来

1MHz频率测量精度高,计数器计一个数就是1us。ARR的值随便设置,设置小的话溢出次数多。

1、使用寄存器配置输入捕获

#include "./BSP/TIMER/TIM_IC.h"void TIM_IC_Init(void)
{//开启定时器5时钟RCC->APB1ENR |= (1 << 3);//开启ARR寄存器缓冲功能TIM5->CR1 |= (1 << 7);//设置计数器向上计数模式TIM5->CR1 &= ~(1 << 4);//设置输入滤波 IC1F 0000TIM5->CCMR1 &= ~(0X0F << 4);//设置输入分频 IC1PSC 00 不分频TIM5->CCMR1 &= ~(0X03 << 2);//设置CC1S为输入模式 将IC1映射到通道一 01TIM5->CCMR1 |= (1 << 0);TIM5->CCMR1 &= ~(1 << 1);//设置CC1P 上升沿捕获TIM5->CCER &= ~(1 << 1);//设置分频系数PSCTIM5->PSC = 71;//设置ARR值为999 计数器溢出一次时间为0.1sTIM5->ARR = 999;//开启定时器3捕获比较通道1的捕获中断请求TIM5->DIER |= (1 << 1);//开启定时器三更新中断TIM5->DIER |= (1 << 0);//开启GPIOA时钟RCC->APB2ENR |= (1 << 2);//设置PA0为输入模式GPIOA ->CRL &= ~(0X03 << 0);//设置PA0为输入浮空GPIOA->CRL |= (1 << 2);GPIOA->CRL &= ~(1 << 3);	//使能定时器3中断HAL_NVIC_SetPriority(TIM5_IRQn, 2, 2);HAL_NVIC_EnableIRQ(TIM5_IRQn);TIM5->SR  = 0;//使能计数器 CEN位TIM5->CR1 |= (1<< 0);//开启输入捕获 CC1E位TIM5->CCER |= (1 << 0);
}uint16_t IC_Value = 0;//定义输入捕获寄存器的值
uint8_t rising = 0;//定义捕获到上升沿 1为已经捕获到上升沿
uint8_t flag = 0;//捕获高电平完成
uint16_t yichu = 0;
void TIM5_IRQHandler(void)
{//判断计数器溢出中断if(TIM5->SR & (1 << 0)){TIM5->SR &= ~(1 << 0);yichu ++;}//这里注意标志位一定要进中断立马清除  不要放在if里边 //因为如果条件不能成立 那么标志位没有清除 他会一直进中断  要不然就是使用库函数  捕获出现这种情况//清空SR输入捕获事件标志位  if(flag == 0 && TIM5->SR & (1 << 1)){		//还没有上升沿if(rising == 0 ){//清空计数器值TIM5->CNT = 0;//将输入捕获设置为下降沿TIM5->CCER  |= (1 << 1);rising = 1;//捕获到上升沿yichu = 0;}else{	//读取计数器得值IC_Value = TIM5->CCR1;//将输入捕获设置为上降沿TIM5->CCER  &= ~(1 << 1);			rising = 0;flag = 1;IC_Value = 1000*yichu + IC_Value;}}TIM5->SR &= ~(1 << 1);}

在配置过程中,最开始将SR中断标志位清除写在了if判断里边,导致条件一直不满足,就一直进入中断,主函数里边的程序也一直被中断卡着。

注意:这个程序捕获的额第一次数据不准确,目前还没有找到问题在哪,怀疑是第一次上升沿触发有问题。从第二次捕获开始,数据准确。

2、使用库函数配置输入捕获

tim_inCapture.h头文件

#ifndef __TIM_INCAPTURE_H
#define __TIM_INCAPTURE_H#include "stm32f1xx.h"void TIM_IC_Init(uint16_t psc,uint16_t arr);#endif

tim_inCapture.c源文件

#include "./BSP/TIMER/tim_inCapture.h"TIM_HandleTypeDef htim;void TIM_IC_Init(uint16_t psc,uint16_t arr)
{htim.Instance = TIM5;htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;htim.Init.CounterMode = TIM_COUNTERMODE_UP;htim.Init.Period = arr;htim.Init.Prescaler = psc;//定时器初始化 PSC ARR 计数模式 ARR缓冲功能HAL_TIM_IC_Init(&htim);//这个要给初始化0  不然里边的值是随机的  会影响配置TIM_IC_InitTypeDef sConfig = {0};sConfig.ICFilter = 0x0;sConfig.ICPolarity = TIM_ICPOLARITY_RISING;sConfig.ICPrescaler = TIM_ICPSC_DIV1;sConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;//定时器输入捕获配置 滤波器 分频器 输入极性(上升沿、下降沿) IC1来连接到通道1  还是连接到通道2HAL_TIM_IC_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1);//开启更新事件中断__HAL_TIM_ENABLE_IT(&htim, TIM_IT_UPDATE);//启动定时器 输入捕获使能 输入捕获中断HAL_TIM_IC_Start_IT(&htim, TIM_CHANNEL_1);
}void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{if(htim ->Instance == TIM5){//开启定时器5时钟__HAL_RCC_TIM5_CLK_ENABLE();//开启GPIOA时钟__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_Init;GPIO_Init.Mode = GPIO_MODE_INPUT;GPIO_Init.Pin = GPIO_PIN_0;GPIO_Init.Pull = GPIO_NOPULL;GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;//速度是输出用的 可以不设置//初始化PA0为浮空输入HAL_GPIO_Init(GPIOA, &GPIO_Init);		HAL_NVIC_SetPriority(TIM5_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM5_IRQn);}
}//定时器5中断处理函数
void TIM5_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim);
}uint16_t IC_Value = 0;//定义输入捕获寄存器的值
uint8_t rising = 0;//定义捕获到上升沿 1为已经捕获到上升沿
uint8_t flag = 0;//捕获高电平完成
uint16_t yichu = 0;//定时器输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{if(htim ->Instance ==TIM5){//还没有捕获到高电平if(flag ==0){//还没有捕获到上升沿if(rising ==0){//已经捕获到了上升沿rising = 1;yichu = 0;//设置计数器的值为0__HAL_TIM_SET_COUNTER(htim, 0);//设置为下降沿捕获__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);}else{//获取捕获寄存器的值IC_Value = __HAL_TIM_GET_COMPARE(htim, TIM_CHANNEL_1);//设置为上降沿捕获__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);rising = 0;flag =1;IC_Value = 1000*yichu + IC_Value;}}}
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim ->Instance ==TIM5){yichu++;}
}

这个是用库函数版本的程序,没啥问题,数据全是准确的。

main.c主函数

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/tim_inCapture.h"extern uint16_t IC_Value;//定义输入捕获寄存器的值
extern uint8_t flag;//捕获高电平完成
int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */led_Init();                         /* LED初始化 */usart_init(115200);TIM_IC_Init(71 ,999);while(1){ LED0(1);LED1(0);delay_ms(500);LED0(0);LED1(1);delay_ms(500);printf("脉冲时间为%dUS\r\n",IC_Value);flag = 0;}
}

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

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

相关文章

python编程-内置函数 bytes() , bytearray()详解

bytes()函数用于创建一个新的不可变的字节序列对象&#xff0c;它是bytearray()的不可变版本。这个函数非常有用&#xff0c;尤其是在处理二进制数据、进行网络编程或者文件操作时。 bytes() 和 bytearray() 都用于处理二进制数据的两个内置函数。它们的主要区别在于 bytes 是不…

深度整理总结MySQL——索引正确使用姿势

索引正确使用姿势 前言MySQL索引优缺点分析✅ 索引的优势⚠️ 索引的代价 如何合理建立索引?——关键原则总结重要的优化机制索引覆盖——通俗的方式讲解索引下推索引跳跃式扫描 前言 这篇文章是补充一些基本概念和实战的一些使用建议. MySQL索引优缺点分析 ✅ 索引的优势 …

SpringBoot中的多环境配置管理

SpringBoot中的多环境配置管理 文章目录 SpringBoot中的多环境配置管理SpringBoot中的多环境配置管理 多环境配置的概述1. 为什么需要多环境配置&#xff1f;2. Spring Boot 中如何实现多环境配置&#xff1f;3. 多环境配置的应用场景4. 如何实现配置隔离&#xff1f; Spring B…

Oracle 变更redo log文件位置

更改Oracle数据库的Redo log文件位置&#xff0c;可以按照以下步骤操作。 1.查询当前Redo log文件信息 select * from v$log; select * from v$logfile;通过查询结果可知Redo log文件放在/oradata/redofile 目录下。 2.拷贝redo log文件到新的位置/Data/redolog $cd /orada…

git代理设置

在 Git 中&#xff0c;可以通过以下命令查看当前设置的代理配置&#xff1a; 查看 HTTP 代理 git config --get http.proxy查看 HTTPS 代理 git config --get https.proxy查看全局代理设置 如果你设置了全局代理&#xff0c;可以通过以下命令查看&#xff1a; git config …

全网多平台媒体内容解析工具使用指南

一、工具特性概述 近期体验了一款基于Web端的多媒体解析服务&#xff0c;该平台通过技术创新实现跨平台内容解析功能&#xff0c;主要特点如下&#xff1a; 1.1 跨平台支持 兼容主流社交媒体&#xff1a;Bilibili、YouTube、Twitter、Instagram等 支持短视频平台&#xff1a…

C# winforms 使用菜单和右键菜单

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

网工_以太网MAC层

2025.02.05&#xff1a;网工老姜学习笔记 第12节 以太网MAC层 2.1 MAC层的硬件地址2.2 MAC地址特殊位含义2.3 终端适配器&#xff08;网卡&#xff09;具有过滤功能2.4 MAC帧的格式2.4.1 DIX Ethernet V2标准&#xff08;先私有&#xff0c;后开放&#xff0c;用得比较多&#…

一文吃透!DataStage 全面概述与核心知识要点大公开

目录 第一章 DataStage 基础知识 1.1 DataStage 定义及特点 1.2 DataStage 功能模块 1.3 DataStage 应用场景 第二章 DataStage 核心技术 2.1 数据抽取技术 2.2 数据转换技术 2.3 数据加载技术 第三章 DataStage 操作实践 3.1 环境搭建与配置 安装 DataStage 软件 配…

鼠标滚轮冒泡事件@wheel.stop

我有一个页面,是在画布上的组件,但是组件中有一个table,table中数据多了,就会出现滚动条,正常情况下,滚动条用鼠标滚轮就可以滑动,但是这个table是在画布上,滚动滚轮会让画布缩放 在table外层的div上加上 wheel.stop,就生效了 wheel.stop 用途&#xff1a;这个修饰符用于处理鼠…

探索从传统检索增强生成(RAG)到缓存增强生成(CAG)的转变

在人工智能快速发展的当下&#xff0c;大型语言模型&#xff08;LLMs&#xff09;已成为众多应用的核心技术。检索增强生成&#xff08;RAG&#xff09;&#xff08;RAG 系统从 POC 到生产应用&#xff1a;全面解析与实践指南&#xff09;和缓存增强生成&#xff08;CAG&#x…

graphRAG的原理及代码实战(1)基本原理介绍(上)

1、基本介绍 GraphRAG通过利用大模型从原始文本数据中提取知识图谱来满足跨上下文检索的需求。该知识图将信息表示为互连实体和关系的网络&#xff0c;与简单的文本片段相比&#xff0c;提供了更丰富的数据表示。这种结构化表示使 GraphRAG 能够擅长回答需要推理和连接不同信息…

PostgreSQL中级认证价值

PostgreSQL&#xff0c;作为一款开源的关系型数据库管理系统&#xff0c;以其强大的功能、高度的可扩展性和稳定性&#xff0c;赢得了广泛的认可。对于非科班出身、IT知识储备有限的你&#xff0c;选择PostgreSQL中级认证专家的学习路径&#xff0c;不仅是一次技能的提升&#…

论文翻译学习:《DeepSeek-R1: 通过强化学习激励大型语言模型的推理能力》

摘要 我们介绍了我们的第一代推理模型 DeepSeek-R1-Zero 和 DeepSeek-R1。DeepSeek-R1-Zero 是一个通过大规模强化学习&#xff08;RL&#xff09;训练的模型&#xff0c;没有经过监督微调&#xff08;SFT&#xff09;作为初步步骤&#xff0c;展示了卓越的推理能力。通过强化…

Android开发获取缓存,删除缓存

Android开发获取缓存&#xff0c;删除缓存 app设置中往往有清理缓存的功能。会显示当前缓存时多少&#xff0c;然后可以点击清理缓存 直接上代码&#xff1a; object CacheHelper {/*** 获取缓存大小* param context* return* throws Exception*/JvmStaticfun getTotalCache…

使用 Ollama 在腾讯云服务器环境部署 DeepSeek 大模型实战指南

文章目录 前言Ollama核心特性 实战步骤安装 Ollama验证安装结果部署 DeepSeek 模型拉取模型启动模型 交互体验命令行对话调用 REST API 总结个人简介 前言 近年来&#xff0c;大语言模型&#xff08;LLM&#xff09;的应用逐渐成为技术热点&#xff0c;而 DeepSeek 作为国产开…

DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求

DeepSeek 的 LLM 推理新方法 DeepSeek 推出了一种创新方法&#xff0c;通过强化学习 (RL) 来提高大型语言模型 (LLM) 的推理能力&#xff0c;其最新论文 DeepSeek-R1 对此进行了详细介绍。这项研究代表了我们如何通过纯强化学习来增强 LLM 解决复杂问题的能力&#xff0c;而无…

机器学习 —— 深入剖析线性回归模型

一、线性回归模型简介 线性回归是机器学习中最为基础的模型之一&#xff0c;主要用于解决回归问题&#xff0c;即预测一个连续的数值。其核心思想是构建线性方程&#xff0c;描述自变量&#xff08;特征&#xff09;和因变量&#xff08;目标值&#xff09;之间的关系。简单来…

【现代深度学习技术】深度学习计算 | 读写文件

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…

计算机三级数据库技术考试大纲

文章目录 基本要求&#xff11;&#xff0e;掌握数据库技术的基本概念、原理、方法和技术。&#xff12;&#xff0e;能够使用 &#xff33;&#xff31;&#xff2c; 语言实现数据库操作。&#xff13;&#xff0e; 具备数据库系统安装、配置及数据库管理与维护的基本技能。 T…