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 0000
	TIM5->CCMR1 &= ~(0X0F << 4);
	
	//设置输入分频 IC1PSC 00 不分频
	TIM5->CCMR1 &= ~(0X03 << 2);
	
	//设置CC1S为输入模式 将IC1映射到通道一 01
	TIM5->CCMR1 |= (1 << 0);
	TIM5->CCMR1 &= ~(1 << 1);
	
	//设置CC1P 上升沿捕获
	TIM5->CCER &= ~(1 << 1);
	
	//设置分频系数PSC
	TIM5->PSC = 71;
	
	//设置ARR值为999 计数器溢出一次时间为0.1s
	TIM5->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  还是连接到通道2
	HAL_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;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript 复习

文章目录 语法前置语法组成引入位置内部引入外部引入 基础语法输出变量变量声明规则变量赋值变量的作用范围 数据类型强制类型转换强转为 Number强转为 Boolean强转为 String强转为 整数 | 浮点数 运算符流程控制隐式转换函数常用内置对象String 对象Array 数组对象Math 数学对…

【C】链表算法题5 -- 相交链表

leetcode链接https://leetcode.cn/problems/intersection-of-two-linked-lists/description/https://leetcode.cn/problems/intersection-of-two-linked-lists/description/ 题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节…

蓝桥杯准备 【入门3】循环结构

素数小算法&#xff08;埃氏筛&&欧拉筛&#xff09; 以下四段代码都是求20以内的所有素数 1.0版求素数 #include<iostream> using namespace std;int main() {int n 20;for(int i2;i<n;i){int j0;for(j2;j<i;j)//遍历i{if(i%j0){break;}}if(ij){cout&l…

寒假2.6--SQL注入之布尔盲注

知识点 原理&#xff1a;通过发送不同的SQL查询来观察应用程序的响应&#xff0c;进而判断查询的真假&#xff0c;并逐步推断出有用的信息 适用情况&#xff1a;一个界面存在注入&#xff0c;但是没有显示位&#xff0c;没有SQL语句执行错误信息&#xff0c;通常用于在无法直接…

Servlet笔记(下)

HttpServletRequest对象相关API 获取请求行信息相关(方式,请求的url,协议及版本) | API | 功能解释 | | ----------------------------- | ------------------------------ | | StringBuffer getRequestURL(); | 获取客户端…

QQ自动发送消息

QQ自动发送消息 python包导入 import time import pandas as pd import pyautogui import pyperclip图像识别函数封装 本程序使用pyautogui模块控制鼠标和键盘来实现QQ自动发送消息&#xff0c;因此必须得到需要点击位置的坐标&#xff08;当然也可以在程序中将位置写死&…

5.1计算机网络基本知识

5.1.1计算机网络概述 目前&#xff0c;三网融合(电信网络、有线电视网络和计算机网络)和宽带化是网络技术的发展的大方向&#xff0c;其应用广泛&#xff0c;遍及智能交通、环境保护、政府工作、公共安全、平安家居等多个领域&#xff0c;其中发展最快的并起到核心作用的则是计…

51单片机之冯·诺依曼结构

一、概述 8051系列单片机将作为控制应用最基本的内容集成在一个硅片上&#xff0c;其内部结构如图4-1所示。作为单一芯片的计算机&#xff0c;它的内部结构与一台计算机的主机非常相似。其中微处理器相当于计算机中的CPU&#xff0c;由运算器和控制器两个部分构成&#xff1b;…

13.PPT:诺贝尔奖【28】

目录 NO1234 NO567 NO8/9/10 NO11/12 NO1234 设计→变体→字体→自定义字体 SmartArt超链接新增加节 NO567 版式删除图片中的白色背景&#xff1a;选中图片→格式→删除背景→拖拉整个图片→保留更改插入→图表→散点图 &#xff1a;图表图例、网格线、坐标轴和图表标题…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(一)

#作者&#xff1a;闫乾苓 文章目录 RabbitMQ简介RabbitMQ与VMware的关系架构工作流程RabbitMQ 队列工作模式及适用场景简单队列模式&#xff08;Simple Queue&#xff09;工作队列模式&#xff08;Work Queue&#xff09;发布/订阅模式&#xff08;Publish/Subscribe&#xff…

DFX(Design for eXcellence)架构设计全解析:理论、实战、案例与面试指南*

一、什么是 DFX &#xff1f;为什么重要&#xff1f; DFX&#xff08;Design for eXcellence&#xff0c;卓越设计&#xff09;是一种面向产品全生命周期的设计理念&#xff0c;旨在确保产品在设计阶段就具备**良好的制造性&#xff08;DFM&#xff09;、可测试性&#xff08;…

【Elasticsearch】diversified sampler

作用就是聚合前的采样&#xff0c;主要是采样 它就是用来采样的&#xff0c;采完样后在进行聚合操作 random_sampler和diversified_sampler是 Elasticsearch 中用于聚合查询的两种采样方法&#xff0c;它们的主要区别如下&#xff1a; 采样方式 • random_sampler&#xff1a…

2月7号.

二叉树是一种特殊的树形数据结构&#xff0c;具有以下特点&#xff1a; 基本定义 节点的度&#xff1a;二叉树中每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。 子树的顺序性&#xff1a;二叉树的子树有左右之分&#xff0c;且顺序不能颠倒。 递归定义&…

openpnp2.2 - 环境搭建 - 编译 + 调试 + 打包

文章目录 openpnp2.2 - 环境搭建 - 编译 调试 打包概述笔记前置任务克隆代码库切到最新的tag清理干净编译工程关掉旧工程打开已经克隆好的openpnp2.2工程将IDEA的SDK配置为openjdk23 切换中英文UI设置JAVA编译器 构建工程跑测试用例单步调试下断点导出工程的JAR包安装install…

【复现论文】DAVE

网站&#xff1a; GitHub - jerpelhan/DAVE 下载完以后&#xff0c;阅读 readme文件 新建终端&#xff0c;打印文件树&#xff0c;不包含隐藏文件&#xff1a; 命令&#xff1a;tree -I .* . ├── LICENSE ├── README.md ├── demo.py ├── demo_zero.py ├── mai…

GB/T28181 开源日记[8]:国标开发速知速会

服务端源代码 github.com/gowvp/gb28181 前端源代码 github.com/gowvp/gb28181_web 介绍 go wvp 是 Go 语言实现的开源 GB28181 解决方案&#xff0c;基于GB28181-2022标准实现的网络视频平台&#xff0c;支持 rtmp/rtsp&#xff0c;客户端支持网页版本和安卓 App。支持rts…

完美解决phpstudy安装后mysql无法启动

phpstudy数据库无法启动有以下几个原因。 **一、**自己在电脑上安装了MySQL数据库,MySQL的服务名为MySQL,这会与phpstudy的数据库的服务名发生冲突&#xff0c;从而造成phpstudy中的数据库无法启动&#xff0c;这时我们只需要将自己安装的MySQL的服务名改掉就行。 但是&#…

grafana面板配置opentsdb

新增面板&#xff1a; 这里add-panel: 如果不是想新增面板而是想新增一行条目&#xff0c;则点击convert to row: 在新增的面板这里可以看到选择数据源 Aggregator&#xff1a;聚合条件&#xff0c;区分下第一行和第二行的aggregator&#xff0c;第一个是对指标值的聚合&…

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

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

【Uniapp-Vue3】从uniCloud中获取数据

需要先获取数据库对象&#xff1a; let db uniCloud.database(); 获取数据库中数据的方法&#xff1a; db.collection("数据表名称").get(); 所以就可以得到下面的这个模板&#xff1a; let 函数名 async () > { let res await db.collection("数据表名称…