【正点原子STM32连载】第十九章 通用定时器输入捕获实验 摘自【正点原子】APM32F407最小系统板使用指南

1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html#

第十九章 通用定时器输入捕获实验

本章将介绍使用APM32F407通用定时器的输入捕获功能。通过本章的学习,读者将学习到通用定时器输入捕获的使用。
本章分为如下几个小节:
19.1 硬件设计
19.2 程序设计
19.3 下载验证

19.1 硬件设计

19.1.1 例程功能

  1. 捕获KEY_UP按键按下拉高PA0的脉冲时间,并通过串口输出
  2. LED0闪烁,指示程序正在运行
    19.1.2 硬件资源
  3. LED
    LED0 - PF9
  4. 按键
    KEY_UP - PA0
  5. 定时器5
    通道1 - PA0
  6. USART1(PA9、PA10连接至板载USB转串口芯片上)
    19.1.3 原理图
    本章实验使用的定时器5为APM32F407的片上资源,因此没有对应的连接原理图。
    19.2 程序设计
    19.2.1 Geehy标准库的TMR驱动
    本章实验将使用TMR5的通道1捕获KEY_UP按键被按下的高电平脉冲宽度,因此除了像第十七章实验配置定时器的基本参数外,还需要配置通用定时器的输入捕获通道,具体的步骤如下:
    ①:配置TMR5的自动重装载值和预分频器数值等参数
    ②:配置输入捕获通道1
    ③:使能TMR5的捕获比较通道1中断和更新中断
    ④:使能TMR5中断,并配置其相关的中断优先级
    ⑤:使能TMR5
    在Geehy标准库中对应的驱动函数如下:
    ①:配置TMR
    请见第16.2.1小节中配置TMR的相关内容。
    ②:配置输入捕获通道
    该函数用于配置TMR的任意输入捕获通道,其函数原型如下所示:
    void TMR_ConfigIC(TMR_T* tmr, TMR_ICConfig_T* ICConfig);
    该函数的形参描述,如下表所示:
    在这里插入图片描述

该函数的返回值描述,如下表所示:
返回值 描述
无 无
表19.2.1.2 函数TMR_ConfigIC()返回值描述
该函数使用TMR_ICConfig_T类型的结构体变量传入TMR输入捕获通道的配置参数,该结构体的定义如下所示:

typedef enum
{TMR_CHANNEL_1					= 0x0000,	/* 定时器通道1*/TMR_CHANNEL_2					= 0x0004,	/* 定时器通道2*/TMR_CHANNEL_3					= 0x0008,	/* 定时器通道3*/TMR_CHANNEL_4					= 0x000C	/* 定时器通道4*/
} TMR_CHANNEL_T;typedef enum
{TMR_IC_POLARITY_RISING			= 0x00,		/* 捕获上升沿 */TMR_IC_POLARITY_FALLING			= 0x02,		/* 捕获下降沿 */TMR_IC_POLARITY_BOTHEDGE		= 0x0A		/* 捕获双边沿 */
} TMR_IC_POLARITY_T;typedef enum
{TMR_IC_SELECTION_DIRECT_TI		= 0x01,		/* 输入捕获映射在TI1上 */TMR_IC_SELECTION_INDIRECT_TI	= 0x02,		/* 输入捕获映射在TI2上 */TMR_IC_SELECTION_TRC			= 0x03		/* 输入捕获映射在TRC上 */
} TMR_IC_SELECTION_T;typedef enum
{TMR_IC_PSC_1,								/* 不分频 */TMR_IC_PSC_2,								/* 每2个事件触发1次捕获 */TMR_IC_PSC_4,								/* 每4个事件触发1次捕获 */TMR_IC_PSC_8									/* 每8个事件触发1次捕获 */
} TMR_IC_PSC_T;typedef struct
{TMR_CHANNEL_T		channel;	/* 定时器通道 */TMR_IC_POLARITY_T	polarity;	/* 输入捕获极性 */TMR_IC_SELECTION_T	selection;	/* 输入捕获映射 */TMR_IC_PSC_T			prescaler;	/* 输入捕获通道预分频因子 */uint16_t				filter;		/* 输入捕获通道滤波器 */
} TMR_ICConfig_T;

该函数的使用示例,如下所示:

#include "apm32f4xx.h"
#include "apm32f4xx_tmr.h"void example_fun(void)
{TMR_ICConfig_T tmr_ic_init_struct;/* 配置TMR5输入捕获通道1 */tmr_ic_init_struct.channel		= TMR_CHANNEL_1;tmr_ic_init_struct.polarity		= TMR_IC_POLARITY_RISING;tmr_ic_init_struct.selection	= TMR_IC_SELECTION_DIRECT_TI;tmr_ic_init_struct.prescaler	= TMR_IC_PSC_1;tmr_ic_init_struct.filter		= 0;TMR_ConfigIC(GTMR_TMRX_CAP, &tmr_ic_init_struct);
}

③:使能TMR指定中断
请见第16.2.1小节中使能TMR指定中断的相关内容。
④:配置TMR中断
请见第12.2.3小节中配置中断的相关内容。
⑤:使能TMR
请见第16.2.1小节中使能TMR的相关内容。
19.2.2 通用定时器驱动
本章实验的通用定时器驱动主要负责向应用层提供通用定时器的初始化函数,并实现通用定时器的中断回调函数。本章实验中,通用定时器的驱动代码包括gtmr.c和gtmr.h两个文件。
通用定时器驱动中,对TMR、GPIO的相关宏定义,如下所示:

#define GTMR_TMRX_CAP				TMR5
#define GTMR_TMRX_CAP_IRQn			TMR5_IRQn
#define GTMR_TMRX_CAP_IRQHandler	TMR5_IRQHandler
#define GTMR_TMRX_CAP_CHY			TMR_CHANNEL_1
#define GTMR_TMRX_CAP_CLK_ENABLE()							\do {														\RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR5);	\} while (0)#define GTMR_TMRX_CAP_CHY_GPIO_PORT		GPIOA
#define GTMR_TMRX_CAP_CHY_GPIO_PIN			GPIO_PIN_0
#define GTMR_TMRX_CAP_CHY_GPIO_PIN_SOURCE	GPIO_PIN_SOURCE_0
#define GTMR_TMRX_CAP_CHY_GPIO_AF			GPIO_AF_TMR5
#define GTMR_TMRX_CAP_CHY_GPIO_CLK_ENABLE()				\do {														\RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);	\} while (0)
通用定时器驱动中TMR5的初始化函数,如下所示:
/*** @brief	初始化通用定时器输入捕获* @note	当APB1PSC!=1时,定时器的时钟频率为APB1时钟的2倍* 			因此定时器的时钟频率为84MHz* 			定时器溢出时间计算方法:Tout = ((arr + 1) * (psc + 1)) / TMRxCLK* 			TMRxCLK=定时器时钟频率,单位MHz* @param	arr: 自动重装载值* @param	psc: 预分频器数值* @retval	无*/
void gtmr_tmrx_cap_chy_init(uint16_t arr, uint16_t psc)
{GPIO_Config_T gpio_init_struct;TMR_BaseConfig_T tmr_init_struct;TMR_ICConfig_T tmr_ic_init_struct;/* 使能时钟 */GTMR_TMRX_CAP_CLK_ENABLE();							/* 使能通用定时器时钟 */GTMR_TMRX_CAP_CHY_GPIO_CLK_ENABLE();				/* 使能输入捕获引脚端口时钟 *//* 配置输入捕获引脚 */gpio_init_struct.pin	= GTMR_TMRX_CAP_CHY_GPIO_PIN;	/* 输入捕获引脚 */gpio_init_struct.mode	= GPIO_MODE_AF;					/* 复用功能模式 */gpio_init_struct.speed	= GPIO_SPEED_100MHz;			/* 高速 */gpio_init_struct.otype	= GPIO_OTYPE_PP;				/* 推挽输出 */gpio_init_struct.pupd	= GPIO_PUPD_DOWN;				/* 下拉 */GPIO_Config(GTMR_TMRX_CAP_CHY_GPIO_PORT, &gpio_init_struct);/* 配置引脚复用功能 */GPIO_ConfigPinAF(	GTMR_TMRX_CAP_CHY_GPIO_PORT,GTMR_TMRX_CAP_CHY_GPIO_PIN_SOURCE,GTMR_TMRX_CAP_CHY_GPIO_AF);/* 配置通用定时器 */tmr_init_struct.countMode		= TMR_COUNTER_MODE_UP;	/* 向上计数 */tmr_init_struct.clockDivision	= TMR_CLOCK_DIV_1;		/* 时钟分频系数 */tmr_init_struct.period			= arr;					/* 自动重装载值 */tmr_init_struct.division		= psc;					/* 预分频器数值 */TMR_ConfigTimeBase(GTMR_TMRX_CAP, &tmr_init_struct);	/* 配置通用定时器 *//* 配置输入捕获通道 */tmr_ic_init_struct.channel		= GTMR_TMRX_CAP_CHY;	/* 输入捕获通道 */tmr_ic_init_struct.polarity		= TMR_IC_POLARITY_RISING;/* 捕获上升沿 */tmr_ic_init_struct.selection	= TMR_IC_SELECTION_DIRECT_TI;/* 输入捕获映射 */tmr_ic_init_struct.prescaler	= TMR_IC_PSC_1;			/* 输入信号预分频系数 */tmr_ic_init_struct.filter		= 0;					/* 滤波器 */TMR_ConfigIC(GTMR_TMRX_CAP, &tmr_ic_init_struct);		/* 配置输入捕获通道 *//* 使能通用定时器及其相关中断 */NVIC_EnableIRQRequest(GTMR_TMRX_CAP_IRQn, 1, 0);	/* 使能中断 */TMR_EnableInterrupt(GTMR_TMRX_CAP, TMR_INT_CC1);	/* 使能输入捕获通道1中断 */TMR_EnableInterrupt(GTMR_TMRX_CAP, TMR_INT_UPDATE);	/* 使能更新中断 */TMR_Enable(GTMR_TMRX_CAP);							/* 使能通用定时器 */
}

从TMR5的初始化代码中可以看到,不仅配置了TMR5的自动重装载值和预分频器系数等基本参数,还配置了TMR5的输入捕获通道1,并开启了TMR5的输入捕获通道1中断和TMR5更新中断,由于需要使用GPIO引脚来获取外部信号,因此对应的GPIO引脚也配置了复用功能。
通用定时器驱动中TMR5的中断回调函数,如下所示:

/*** @brief	通用定时器中断服务函数* @param	无* @retval	无*/
void GTMR_TMRX_CAP_IRQHandler(void)
{/* 捕获比较通道1中断 */if (TMR_ReadIntFlag(GTMR_TMRX_CAP, TMR_INT_CC1) == SET){if ((g_tmrxchy_cap_sta & 0x80) == 0)			/* 高电平捕获未完成 */{if ((g_tmrxchy_cap_sta & 0x40) == 0)		/* 第一次捕获到上升沿 */{g_tmrxchy_cap_sta = 0;g_tmrxchy_cap_val = 0;g_tmrxchy_cap_sta |= 0x40;				/* 标记已经捕获到上升沿 */TMR_Disable(GTMR_TMRX_CAP);/* 清空计数值,准备计数高电平时间 */TMR_ConfigCounter(GTMR_TMRX_CAP, 0);/* 配置为下降沿捕获 */TMR_ConfigOC1Polarity(GTMR_TMRX_CAP, TMR_OC_POLARITY_LOW);TMR_Enable(GTMR_TMRX_CAP);}else										/* 捕获到下降沿 */{g_tmrxchy_cap_sta |= 0x80;				/* 标记高电平捕获完成 *//* 获取当前的捕获值 */g_tmrxchy_cap_val = TMR_ReadCaputer1(GTMR_TMRX_CAP);/* 重新配置为上升沿捕获 */TMR_ConfigOC1Polarity(GTMR_TMRX_CAP, TMR_OC_POLARITY_HIGH);}}TMR_ClearIntFlag(GTMR_TMRX_CAP, TMR_INT_CC1);	/* 清除捕获比较通道1中断 */}/* 更新中断 */if (TMR_ReadIntFlag(GTMR_TMRX_CAP, TMR_INT_UPDATE) == SET){if ((g_tmrxchy_cap_sta & 0x80) == 0)			/* 高电平捕获未完成 */{if ((g_tmrxchy_cap_sta & 0x40) == 0x40)	/* 已经捕获到上升沿 */{if ((g_tmrxchy_cap_sta & 0x3F) == 0x3F)/* 溢出次数超出最大值 */{g_tmrxchy_cap_sta |= 0x80;			/* 强行标记已完成捕获 */g_tmrxchy_cap_val = 0xFFFF;			/* 设为最大值 *//* 重新配置为上升沿捕获 */TMR_ConfigOC1Polarity(GTMR_TMRX_CAP, TMR_OC_POLARITY_HIGH);}else{g_tmrxchy_cap_sta++;	/* 记录定时器自捕获到上升沿后的溢出次数 */}}}TMR_ClearIntFlag(GTMR_TMRX_CAP, TMR_INT_UPDATE);/* 清除定时器更新中断 */}
}

从上面的代码中可以看出,在TMR5的中断回调函数中会依次捕获输入信号的上升沿和下降沿,并在第一次捕获到输入信号上升沿的时候清空TMR5的计数值,随后在捕获到信号下降沿的时候读取TMR5的计数值,该值就是该输入信号高电平脉宽对应的计数值,只要根据TMR5的计数频率,就能够计算出输入信号高电平脉宽的时间。TMR5的更新中断是用于处理计数溢出的。
19.2.3 实验应用代码
本章实验的应用代码,如下所示:

int main(void)
{uint32_t temp = 0;uint8_t t = 0;NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_3);	/* 设置中断优先级分组为组3 */sys_apm32_clock_init(336, 8, 2, 7);					/* 配置系统时钟 */delay_init(168);										/* 初始化延时功能 */usart_init(115200);									/* 初始化串口 */led_init();											/* 初始化LED */gtmr_tmrx_cap_chy_init(0xFFFF, 84 - 1);				/* 初始化通用定时器输入捕获 */while (1){if (g_tmrxchy_cap_sta & 0x80)			/* 成功捕获到了一次高电平 */{temp = g_tmrxchy_cap_sta & 0x3F;	/* 获取定时器溢出次数 */temp *= 0xFFFF;						/* 计算溢出时间总和 */temp += g_tmrxchy_cap_val;			/* 计算总的高电平时间 */printf("HIGH:%d us\r\n", temp);		/* 打印总的高点平时间 */g_tmrxchy_cap_sta = 0;				/* 开启下一次捕获 */}t++;if (t > 20){t = 0;LED0_TOGGLE();}delay_ms(10);}
}

从上面的代码中可以看到,TMR5的预分频系数被配置为(84-1),同时因为TMR5的时钟频率为84MHz,因此TMR5的计数频率为1MHz,因此在TMR5成功捕获到外部输入信号的高电平后,可以直接计算出捕获到高电平的脉宽时间。
19.3 下载验证
在完成编译和烧录操作后,短暂按下并抬起KEY_UP按键,可以通过串口调试助手观察到捕获到的KEY_UP按键被按下的时间。

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

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

相关文章

2023七夕小程序

又是一年七夕节 往年七夕小程序 2020 https://blog.csdn.net/chen_227/article/details/107062998 2022 视频 QiXi2022 代码 https://gitee.com/chen227/qixi2022-qt-qml 2023 效果 代码 https://gitee.com/chen227/qixi2023-qt-qml

Android Studio中引入MagicIndicator

1.github中下载文件 GitHub - hackware1993/MagicIndicator: A powerful, customizable and extensible ViewPager indicator framework. As the best alternative of ViewPagerIndicator, TabLayout and PagerSlidingTabStrip —— 强大、可定制、易扩展的 ViewPager 指示器框…

TCP特点UDP编程

目录 1、tcp协议和udp协议 2、多线程并发和多进程并发: (1)多进程并发服务端 (2)多进程并发客户端: 3、tcp: 4、粘包 5、UDP协议编程流程 (1)服务器端: (2)客户端: 6、tcp状…

Java请求Http接口-hutool的HttpUtil(超详细-附带工具类)

概述 HttpUtil是应对简单场景下Http请求的工具类封装&#xff0c;此工具封装了HttpRequest对象常用操作&#xff0c;可以保证在一个方法之内完成Http请求。 此模块基于JDK的HttpUrlConnection封装完成&#xff0c;完整支持https、代理和文件上传。 导包 <dependency>&…

Android事件分发机制被我翻烂了

作者&#xff1a;积木zz 这次说下Android中的事件分发机制 从开始点击屏幕开始&#xff0c;就会产生从Activity开始到decorview一直到最里层的view一连串事件传递。每一层view或者viewgroup都会首先调用它的dispatchTouchEvent方法&#xff0c;然后判断是否就在当前一层消费掉事…

LLaMA模型泄露 Meta成最大受益者

一份被意外泄露的谷歌内部文件&#xff0c;将Meta的LLaMA大模型“非故意开源”事件再次推到大众面前。“泄密文件”的作者据悉是谷歌内部的一位研究员&#xff0c;他大胆指出&#xff0c;开源力量正在填平OpenAI与谷歌等大模型巨头们数年来筑起的护城河&#xff0c;而最大的受益…

selenium中处理验证码问题

验证码 基本作用&#xff1a;可以实现当前访问页面的数据安全性、还可以减少用户的并发数&#xff1b; 类型&#xff1a;1、纯数字、纯字母&#xff1b;2、汉字组合&#xff1b;3、数学运算题&#xff1b;4、滑动&#xff1b;5、图片&#xff08;选不同的、选相同、成语顺序&…

Ubuntu 20.04使用Livox mid 360 测试 FAST_LIO

前言 Livox mid360需要使用Livox-SDK2&#xff0c;而非Livox-SDK&#xff0c;以及对应的livox_ros_driver2 。并需要修改FAST_LIO中部分代码。 1. 安装Livox-SDK2 参考官方教程。 1.1. 安装CMake sudo apt install cmake1.2. 安装编译Livox-SDK2 git clone https://github…

聚观早报 | 网龙发布EDA白皮书;日产合资旗下品牌使用东风纯电

【聚观365】8月22日消息 网龙发布EDA白皮书 日产合资公司旗下自主品牌将使用东风纯电平台 vivo Pad Air评测 辛巴818五周年专场带货GMV达22.3亿 X删除2014年12月前大多数图片和推文链接 网龙发布EDA白皮书 近日消息&#xff0c;由北京师范大学和联合国教科文组织教育信息…

ThreadLocal深度解析

简介 在并发编程中&#xff0c;导致并发bug的问题都会归结于对共享变量的操作不当。多个线程同时读写同一共享变量存在并发问题&#xff0c;我们可以利用写时复制、不变性来突破对原数据的写操作&#xff0c;没有写就没有并发问题&#xff0c;而本篇文章所介绍的技术是突破共享…

完美版积分商城系统-奇偶商城系统源码+独立代理后台

奇偶商城系统源码 完美版独立代理后台 1.演示环境&#xff1a;Linux Centos7以上版本 宝塔 2.Nginx 1.18.0 PHP7.0 Mysql5.6 3.伪静态选择thinkphp 4./Application/Common/Conf 修改数据库信息 详细搭建教程附在压缩包内了,下载查看

Vue3.X 路由与导航栏、侧边栏(四)

我们接着上一节的 Vue3.x 生命周期&#xff08;三&#xff09; 的说明&#xff0c;我们这一节讲解了项目中路由的配置与导航栏、侧边栏的关系。 一、路由配置 vue项目中路由配置有一个固有文件夹&#xff0c;可以配置路由&#xff0c;这样的优点使项目更加清晰明了。 如图&a…

美创科技荣获“2023年网络安全优秀创新成果大赛—杭州分站赛”两项优胜奖

近日&#xff0c;由浙江省互联网信息办公室指导、中国网络安全产业联盟&#xff08;CCIA&#xff09;主办&#xff0c;浙江省网络空间安全协会承办的“2023年网络安全优秀创新成果大赛-杭州分站赛”正式公布评选结果。 经专家评审&#xff0c;美创科技报名参赛的解决方案—“医…

【Web开发指南】MyEclipse XML编辑器的高级功能简介

MyEclipse v2023.1.2离线版下载 1. 在MyEclipse中编辑XML 本文档介绍MyEclipse XML编辑器中的一些可用的函数&#xff0c;MyEclipse XML编辑器包括高级XML编辑&#xff0c;例如&#xff1a; 语法高亮显示标签和属性内容辅助实时验证(当您输入时)文档内容的源&#xff08;Sou…

基于QT4的GPX文件编辑器开发

GPX文件是记录地理点的文件,本质是一种xml文件。GPX文件目前没有很好的编辑器,因此作者决定开发一款无需安装的绿色编辑器。 在QT4开发中,XML可以用DOM来实现,但其逻辑并不是很清晰。使用模型视图反而会更加可读。因此在开发中,使用model-view模式来实现数据读写。 1 需…

游戏找不到msvcr100.dll解决方法,常见的三种解决方法

在计算机领域&#xff0c;msvcr100.dll是一个非常重要的动态链接库文件。它是Microsoft Visual C 2010 Redistributable的一部分&#xff0c;用于支持Visual Studio 2010的开发环境。然而&#xff0c;在某些情况下&#xff0c;msvcr100.dll可能会出现问题&#xff0c;导致程序无…

【Leetcode】104.二叉树的最大深度

一、题目 1、题目描述 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例1: 输入:root = [3,9,20,null,null,15,7] 输出:3示例2: 输入:root = [1,null,2] 输出:2提示: 树中节点的数量在 [0, 104…

嵌入式设备应用开发(qt界面开发)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 linux界面开发有很多的方案可以选。比如说lvgl、minigui、ftk之类的。但是,这么多年来,一直屹立不倒的还是qt。相比较其他几种方案,qt支持多个平台,这里面就包括了linux平台。此…

Spring Boot 集成 WebSocket 实现服务端推送消息到客户端

WebSocket 简介 WebSocket 协议是基于 TCP 的一种新的网络协议&#xff0c;它实现了浏览器与服务器全双工&#xff08;full-duplex&#xff09;通信—允许服务器主动发送信息给客户端&#xff0c;这样就可以实现从客户端发送消息到服务器&#xff0c;而服务器又可以转发消息到客…