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

news2024/10/6 10:29:08

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.coloradmin.cn/o/913374.html

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

相关文章

一个例子看懂IO模型

1.用户态和内核态 现代操作系统将空间划分为用户空间和内核空间。 用户态:一般都是些应用程序,不能直接的访问内核空间和硬盘。 内核态:操作系统的核心,只有切换到内核态才能操作磁盘。 2.同步、异步、阻塞、非阻塞 我们使用前后…

Java请求webservice踩过的坑

最近项目对接过程中,因为对方系统比较旧,我们和对方进行交互使用webservice方式进行,对方给出相关文档, 接口地址:http://ip:port/abc/def/xxxService?wsdl 接口名称:methodA 1-springboot配合CXF使用 …

智慧水务建设项目可研报告-222页【可研报告】

导读:原文《智慧水务建设项目可研报告-222页【可研报告】》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 部分内容: 业务需求分析 3.3.1业…

CentOS7中使用Docker进行MySQL主从复制【论文式教程】

1、安装Docker 卸载docker sudo yum remove docker*安装 yum-utils 工具集,它提供了一些额外的命令和功能,帮助你更好地管理 YUM 软件包管理器。其中包含了一个工具叫做 yum-config-manager,它用于管理 YUM 配置,包括软件仓库源…

计算机视觉:比SAM快50倍的分割一切视觉模型FastSAM

目录 引言 1 FastSAM介绍 1.1 FastSAM诞生 1.2 模型算法 1.3 实验结果 2 FastSAM运行环境构建 2.1 conda环境构建 2.2 运行环境安装 2.3 模型下载 3 FastSAM运行 3.1 命令行运行 3.1.1 Everything mode 3.1.2 Text prompt 3.1.3 Box prompt (xywh) 3.1.4 Points p…

Docker容器学习:部署安装Docker基础使用

目录 1、安装Docker-CE 1)参考阿里云的yum安装 2)二进制安装docker(推荐、生产环境使用较多) 3)配置Docker镜像加速 2、下载系统镜像(Ubuntu、 centos) 1)先查看我们所需的镜像…

如何通过人工智能和自动化提高供应链弹性?

全球供应链中的数字化转型已经引起了广泛关注,尽管在过去的十年中,这一话题被广泛讨论,但许多公司仍然对如何实现这一不明确的目标感到困惑。人们普遍认识到这种转变的重要性,而新冠疫情及其带来的巨大影响也为行业向数字化转型方…

数字生意,经九长兴 | 带您一起回顾秦丝9年成长历程

今年是秦丝科技成立的第9年,9年前我国90%以上的商家处于原始手工记账状态,急需SaaS软件实现数字化转型,高效管理门店,秦丝科技创始人主动扛起了帮中小商家数字化转型的重任。 经过9年的发展,秦丝目前已经成功帮助200万…

drools8尝试

drools7升级到drools8有很大很大的变更.几乎不能说是一个项目了. 或者说就是名字相同的不同项目, 初看下来变化是这样 两个最关键的东西都retired了 https://docs.drools.org/8.42.0.Final/drools-docs/drools/migration-guide/index.html business central变成了一个VS code…

回归预测 | MATLAB实现WOA-RF鲸鱼优化算法优化随机森林算法多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现WOA-RF鲸鱼优化算法优化随机森林算法多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现WOA-RF鲸鱼优化算法优化随机森林算法多输入单输出回归预测(多指标,多图)效果一览…

【计算机网络】日志与守护进程

文章目录 日志日志的创建logmessage 函数日志左边部分实现日志右边部分实现 完整代码log.hpp(整体实现)err.hpp (错误信息枚举) 守护进程PGID SID TTY 的介绍shell中控制进程组的方式结论 为什么要有守护进程存在?守护进程的创建使用守护进程的条件守护进…

centos7.6安装、卸载openssh

1.卸载openssh 执行 rpm -qa openssh*查看是否已经安装过了。 rpm -qa openssh* 依次卸载: yum remove openssh-server-7.4p1-23.el7_9.x86_64 yum remove openssh-7.4p1-23.el7_9.x86_64 或者使用:yum remove openssh-* 全部卸载掉 yum remove opens…

客户案例:中圣科技—CAC2.0防范盗号威胁,加固安全防线

客户背景 中圣科技(江苏)股份有限公司(以下简称“中圣科技”),是一家以技术研发为驱动,以清洁能源核心成套装备和节能环保工程服务为支撑的科技创新型企业。其以南京为核心运营基地,与当地政府…

【云原生】3分钟快速在Kubernetes1.25部署Prometheus2.42+Grafana9.5.1+Alertmanager0.25

文章目录 1、简介2、GitHub地址3、环境信息4、安装5、访问Grafana1、简介 Prometheus-operator帮助我们快速创建Prometheus+Grafana+Alertmanager等服务,而kube-prometheus更加完整的帮助我们搭建全套监控体系,这包括部署多个 Prometheus 和 Alertmanager 实例, 指标导出器…

Ubuntu20 安装 libreoffice

1 更新apt-get sudo apt-get update2 安装jdk 查看jdk安装情况 Command java not found, but can be installed with:sudo apt install default-jre # version 2:1.11-72, or sudo apt install openjdk-11-jre-headless # version 11.0.138-0ubuntu1~20.04 sud…

发布 net 项目 到 Docker

背景 因为发布到 centOS8 使用 screen -S 可以,想开机自启 使用 nohup 命令有启动不起来。环境问题不好找,就想尝试用 docker 运行 步骤 在生成的 Dockerfile 文件里增加修改时区指令 因为我们用的都是北京时间所以 创建镜像的时候就调整好 #设置时间…

SQLSTATE[IMSSP]: The active result for the query contains no fields.

我的是SQL server 报错场景,代码: $psendmx_sql"SET IDENTITY_INSERT PSENDMX ON;INSERT INTO psendmx (DJBH,MIBH,MXBH,SPDM,GG1DM,GG2DM,SL,SL_2,CKJ,ZK,DJ,DJ_1,JE,HH) VALUES {$mx_values};SET IDENTITY_INSERT PSENDMX OFF;"; $a$db_er…

算法通关村第九关——透彻理解二分查找

1.前言 常见的查找算法有顺序查找、二分查找、插值查找、斐波那契查找、树表查找、分块查找、哈希查找等。如果进行归类,那么二分查找、插值查找(一种查找算法)以及斐波那契查找都可以归为插值查找(大类)。而插值查找…

macOS上编译obs-studio

前言 最近基于obs的1个二开程序,需要移植到macOS平台上,由于遇到些问题,本文记录下如何在macOS上配置&编译&运行obs程序完整过程。 下载 首先下载cmake-gui工具,下载CMAKE,选择对应macOS平台的cmake版本&…

过来人经验,PMP考试第七版要怎么学?

第七版没有大家说的那么难,根据考纲来看,一半内容将考查预测型项目管理方法,一半考查敏捷或混合型方法 🌈备考建议是:先学第六版和敏捷,再来学第七版,第七版其实可以理解为第六版的升级&#xf…