【正点原子STM32连载】第二十章 通用定时器脉冲计数实验 摘自【正点原子】APM32F407最小系统板使用指南

news2025/1/12 8:06:11

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

第二十章 通用定时器脉冲计数实验

本章将介绍使用APM32F407通用定时器对输入脉冲的个数进行计数。通过本章的学习,读者将学习到通用定时器从模式的使用。
本章分为如下几个小节:
20.1 硬件设计
20.2 程序设计
20.3 下载验证

20.1 硬件设计
20.1.1 例程功能

  1. 捕获KEY_UP按键按下产生的脉冲次数,并通过串口输出
  2. 按下KEY0按键可以清零统计值
  3. LED0闪烁,指示程序正在运行
    20.1.2 硬件资源
  4. LED
    LED0 - PF9
  5. 按键
    KEY0 - PE4
    KEY_UP - PA0
  6. 定时器2
    通道1 - PA0
  7. USART1(PA9、PA10连接至板载USB转串口芯片上)
    20.1.3 原理图
    本章实验使用的定时器2为APM32F407的片上资源,因此没有对应的连接原理图。
    20.2 程序设计
    20.2.1 Geehy标准库的TMR驱动
    本章实验将使用KEY_UP按键按下时产生的上升沿作为TMR2计数的触发源,因此除了像第十七章实验配置定时器的基本参数外,该需要配置通用定时器为外部时钟模式1及其相关配置,具体的步骤如下:
    ①:配置TMR2的自动重装载值和预分频器数值等参数
    ②:配置TMR2为外部时钟触发
    ③:使能TMR2的更新中断
    ④:使能TMR2中断,并配置其相关的中断优先级
    ⑤:使能TMR2
    在Geehy标准库中对应的驱动函数如下:
    ①:配置TMR
    请见第16.2.1小节中配置TMR的相关内容。
    ②:配置TMR为外部时钟触发
    该函数用于配置TMR为外部时钟触发,其函数原型如下所示:
    void TMR_ConfigTrigExternalClock( TMR_T* tmr,
    TMR_TRIGGER_SOURCE_T triggerSource,
    TMR_IC_POLARITY_T ICpolarity,
    uint16_t ICfilter)
    该函数的形参描述,如下表所示:
    在这里插入图片描述

表20.2.1.1 函数TMR_ConfigTrigExternalClock()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表20.2.1.2 函数TMR_ConfigTrigExternalClock()返回值描述
该函数的使用示例,如下所示:

#include "apm32f4xx.h"
#include "apm32f4xx_tmr.h"

void example_fun(void)
{
    /* 配置TMR2的触发源为其通道1输入信号的上升沿 */
    TMR_ConfigTrigExternalClock(	TMR2,
    									TMR_TRIGGER_SOURCE_TI1FP1,
    									TMR_IC_POLARITY_RISING,
    									0);
}

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

#define GTMR_TMRX_CNT				TMR2
#define GTMR_TMRX_CNT_IRQn			TMR2_IRQn
#define GTMR_TMRX_CNT_IRQHandler	TMR2_IRQHandler
#define GTMR_TMRX_CNT_CHY			TMR_CHANNEL_1
#define GTMR_TMRX_CNT_CLK_ENABLE()							\
    do {														\
    		RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR2);	\
    } while (0)

#define GTMR_TMRX_CNT_CHY_GPIO_PORT		GPIOA
#define GTMR_TMRX_CNT_CHY_GPIO_PIN			GPIO_PIN_0
#define GTMR_TMRX_CNT_CHY_GPIO_PIN_SOURCE	GPIO_PIN_SOURCE_0
#define GTMR_TMRX_CNT_CHY_GPIO_AF			GPIO_AF_TMR2
#define GTMR_TMRX_CNT_CHY_GPIO_CLK_ENABLE()				\
    do {														\
    		RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);	\
    } while (0)
通用定时器驱动中TMR2的初始化函数,如下所示:
/**
 * @brief	初始化通用定时器脉冲计数
 * @note	当APB1PSC!=1时,定时器的时钟频率为APB1时钟的2倍
 * 			因此定时器的时钟频率为84MHz
 * 			定时器溢出时间计算方法:Tout = ((arr + 1) * (psc + 1)) / TMRxCLK
 * 			TMRxCLK=定时器时钟频率,单位MHz
 * @param	psc: 预分频器数值
 * @retval	无
 */
void gtmr_tmrx_cnt_chy_init(uint16_t psc)
{
    GPIO_Config_T gpio_init_struct;
    TMR_BaseConfig_T tmr_init_struct;
    
    /* 使能时钟 */
    GTMR_TMRX_CNT_CLK_ENABLE();							/* 使能通用定时器时钟 */
    GTMR_TMRX_CNT_CHY_GPIO_CLK_ENABLE();				/* 使能输出捕获引脚端口时钟 */
    
    /* 配置输入捕获引脚 */
    gpio_init_struct.pin	= GTMR_TMRX_CNT_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_CNT_CHY_GPIO_PORT, &gpio_init_struct);
    GPIO_ConfigPinAF(GTMR_TMRX_CNT_CHY_GPIO_PORT,			/* 配置引脚复用功能 */
    GTMR_TMRX_CNT_CHY_GPIO_PIN_SOURCE,
    GTMR_TMRX_CNT_CHY_GPIO_AF);
    
    /* 配置通用定时器 */
    tmr_init_struct.countMode		= TMR_COUNTER_MODE_UP;	/* 向上计数 */
    tmr_init_struct.clockDivision	= TMR_CLOCK_DIV_1;		/* 时钟分频系数 */
    tmr_init_struct.period			= 0xFFFF;				/* 自动重装载值 */
    tmr_init_struct.division		= psc;					/* 预分频器数值 */
    TMR_ConfigTimeBase(GTMR_TMRX_CNT, &tmr_init_struct);	/* 配置通用定时器 */
    
    /* 配置外部时钟 */
    TMR_ConfigTrigExternalClock(	GTMR_TMRX_CNT,			/* 配置外部时钟 */
    									TMR_TRIGGER_SOURCE_TI1FP1,
    									TMR_IC_POLARITY_RISING,
    									0);
    
    /* 使能通用定时器及其相关中断 */
    NVIC_EnableIRQRequest(GTMR_TMRX_CNT_IRQn, 1, 0);		/* 使能中断 */
    TMR_EnableInterrupt(GTMR_TMRX_CNT, TMR_INT_UPDATE);		/* 使能更新中断 */
    TMR_Enable(GTMR_TMRX_CNT);								/* 使能通用定时器 */
}

从TMR2的初始化代码中可以看到,不仅配置了TMR2的自动重装载值和预分频器数值等基本参数,还调用函数TMR_ConfigTrigExternalClock()配置使用TMR2通道1输入信号的上升沿作为TMR2的外部时钟来触发计数,并开启了TMR2的更新中断,来处理计数溢出的情况,由于需要使用GPIO引脚来获取外部的输入信号,因此对应的GPIO引脚也配置了复用功能。
通用定时器驱动中,获取和清零计数值的函数,如下所示:

/**
 * @brief	获取通用定时器当前计数值(含溢出)
 * @param	无
 * @retval	当前计数值
 */
uint32_t gtmr_tmrx_cnt_chy_get_count(void)
{
    uint32_t count;
    
    count = g_tmrxchy_cnt_ofcnt * (0xFFFF + 1);	/* 计算溢出次数对应的计数值 */
    count += TMR_ReadCounter(GTMR_TMRX_CNT);	/* 加上当前的CNT值 */
    
    return count;
}

/**
 * @brief	重启通用定时器计数
 * @param	无
 * @retval	无
 */
void gtmr_tmrx_cnt_chy_restart(void)
{
    TMR_Disable(GTMR_TMRX_CNT);				/* 关闭通用定时器计数 */
    g_tmrxchy_cnt_ofcnt = 0;				/* 溢出次数记录清零 */
    TMR_ConfigCounter(GTMR_TMRX_CNT, 0);	/* 通用计数器计数值清零 */
    TMR_Enable(GTMR_TMRX_CNT);				/* 使能通用计数器计数 */
}

从上面的代码中可以看到,获取计数值时,就是对定时器当前的计数值和溢出次数进行计算得出的,清零计数值就是清零计数值和溢出次数。定时器的溢出次数是在TMR2的更新中断中累加的。
通用定时器驱动中,TMR2的中断回调函数,如下所示:

/**
 * @brief	通用定时器中断服务函数
 * @param	无
 * @retval	无
 */
void GTMR_TMRX_CNT_IRQHandler(void)
{
    if (TMR_ReadIntFlag(GTMR_TMRX_CNT, TMR_INT_UPDATE) == SET)/* 判断更新中断标志 */
    {
    		g_tmrxchy_cnt_ofcnt++;							/* 更新通用定时器溢出次数 */
    		
    		TMR_ClearIntFlag(GTMR_TMRX_CNT, TMR_INT_UPDATE);	/* 清除更新中断标志 */
    }
}

TMR2的中断回调函数就是用于在TMR2发生更新中断时,统计TMR2的溢出次数。
20.2.3 实验应用代码
本章实验的应用代码,如下所示:

int main(void)
{
    uint8_t key;
    uint32_t curcnt;
    uint32_t oldcnt = 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 */
    key_init();											/* 初始化按键 */
    gtmr_tmrx_cnt_chy_init(0);							/* 初始化通用定时器脉冲计数 */
    gtmr_tmrx_cnt_chy_restart();						/* 重启通用定时器计数 */
    
    while (1)
    {
    		key = key_scan(0);							/* 扫描按键 */
    		
    		if (key == KEY0_PRES)
    		{
    			gtmr_tmrx_cnt_chy_restart();			/* 重启通用定时器计数 */
    		}
    		
    		curcnt = gtmr_tmrx_cnt_chy_get_count();	/* 获取通用定时器当前计数值 */
    		
    		if (oldcnt != curcnt)
    		{
    			oldcnt = curcnt;
    			printf("CNT:%d\r\n", oldcnt);			/* 打印脉冲个数 */
    		}
    		
    		t++;
    		if (t > 20)
    		{
    			t = 0;
    			LED0_TOGGLE();
    		}
    		
    		delay_ms(10);
    }
}

从上面的代码中可以看到,TMR2的预分频系数被配置为0,因此每个脉冲都会触发TMR2的计数值加1。完成相关初始化后,便不断地扫描按键和获取TMR2的计数值,若KEY0按键被按下,则会清零TMR2的计数值;若KEY_UP按键被按下,则会触发TMR2的计数值加1,同时会将新的计数值通过串口输出至串口调试助手。
20.3 下载验证
在完成编译和烧录操作后,连续按下KEY_UP按键,模拟产生多个脉冲,可以通过串口调试助手观察到KEY_UP按键被按下的次数,同时按下KEY0按键,可清零统计值。

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

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

相关文章

页眉横线怎么删除?4个方法,高效删除!

“刚写了一篇文章,但格式上出了点问题,页眉上一直有一条横线,想把它删掉但是一直都删不掉。这是为什么呢?有什么方法可以删除页眉横线吗?” 在使用Word时,用户可以按个人的需求对页面进行调整。在页眉上可以…

老铁,测试小白也可以飙车了!XMind2TestCase,逼格满满!

目录 一、XMind测试用例通用模板 二、导入TestLink 三、导入禅道(ZenTao) 四、使用Web转换工具 总结 “ 测!不!用!脑?别傻了,用XMind2TestCase,测试更轻松,更牛掰! …

移动端和PC端对比【组件库+调试vconsole +构建vite/webpack+可视化echarts/antv】

目录 组件库 移动端 vue vant PC端 react antd vue element 调试:vconsole vs dev tools中的控制台(Console) ​​​​​​​vconsole:在真机上调试 构建工具 webpack 原理 Babel:JS编译器(…

学员心得 | 突破瓶颈!云计算HCIE帮我走出职场舒适区

大家好,我是誉天云计算的吴同学,是安徽的一名“大龄考生”。读研后我已工作多年:在上海奋斗七年,回到老家又安稳了十年。这期间做过领导,也当过小兵,起起伏伏走到今天,才发现职业与技术都已然面…

7年测试经验之谈 —— 编写一个接口自动化测试程序

下面是一个简单的接口自动化测试程序的示例,使用requests库发送HTTP请求并使用unittest框架进行断言: import requests import unittestclass ApiTests(unittest.TestCase):def setUp(self):self.base_url "http://api.example.com/"def tes…

C# 工厂模式

一、概述 工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。在C#中,工厂模式通过定义一个公共接口或抽象类来创建对象,而具体的对象创建则由工厂类来实现。 工厂模式主要包含三个角色…

Jmeter性能测试 —— TPS拐点寻找

寻找TPS性能拐点1、准备脚本①在本地电脑调试Jmeter压测脚本 寻找TPS性能拐点1、准备脚本①在本地电脑调试Jmeter压测脚本 2、执行压力测试①执行压测脚本 jmeter –n –t xianchengzuse.jmx ②记录业务压测数据 3、监控服务器性能指标 ①监控CPU输入top命令 ②监控内存 fre…

AcrelEMS-HIM高速公路综合能效解决方案-安科瑞黄安南

高速公路供配电行业背景 合能效解决方案 高速公路电力监控及综合能效管理系统 高速公路典型硬件

游戏中的图片打包流程,免费的png打包plist工具,一款把若干资源图片拼接为一张大图的免费工具

手机游戏开发中,为了提高图片渲染性能,经常需要将小图片合并成一张大图进行渲染。如果手工来做的话就非常耗时。TexturePacker就是一款非常不错方便的处理工具。TexturePacker虽然非常优秀,但不是免费的。 对于打包流程,做游戏的…

读SQL学习指南(第3版)笔记03_创建和填充数据库

1. 创建数据表 1.1. sql CREATE TABLE person(person_id SMALLINT UNSIGNED,fname VARCHAR(20),lname VARCHAR(20),eye_color CHAR(2),birth_date DATE,street VARCHAR(30),city VARCHAR(20),state VARCHAR(20),country VARCHAR(20),postal_code VARCHAR(20),CONSTRAINT pk_p…

软件测试技术分享丨使用Postman搞定各种接口token实战

现在许多项目都使用jwt来实现用户登录和数据权限,校验过用户的用户名和密码后,会向用户响应一段经过加密的token,在这段token中可能储存了数据权限等,在后期的访问中,需要携带这段token,后台解析这段token才…

凯迪正大—变比测试仪

一、产品简介 KDB-II全自动变比组别测试仪是根据 《中华人民共和国电力行业标准》制造的高电压测试设备,按通用技术条件 DL/T963-2005设计,依据《电力设备交接和预防性试验规程》,可有效监督变压器产品出厂及使用过程中的质量,防…

java.lang.IllegalStateException: Failed to load ApplicationContext异常

错误原由 今天在编写SpringBoot项目整合MyBatis框架的过程中,产生了这个错误 java.lang.IllegalStateException: Failed to load ApplicationContextat org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheA…

Flutter性能揭秘之RepaintBoundary

作者:xuyisheng Flutter会在屏幕上绘制Widget。如果一个Widget的内容需要更新,那就只能重绘了。尽管如此,Flutter同样会重新绘制一些Widget,而这些Widget的内容仍有部分未被改变。这可能会影响应用程序的执行性能,有时…

04架构管理之分支管理实践-一种git分支管理最佳实践

专栏说明:针对于企业的架构管理岗位,分享架构管理岗位的职责,工作内容,指导架构师如何完成架构管理工作,完成架构师到架构管理者的转变。计划以10篇博客阐述清楚架构管理工作,专栏名称:架构管理…

Sentinel 控制台(集群流控管理)

规则配置 要通过 Sentinel 控制台配置集群流控规则&#xff0c;需要对控制台进行改造。我们提供了相应的接口进行适配。 从 Sentinel 1.4.0 开始&#xff0c;我们抽取出了接口用于向远程配置中心推送规则以及拉取规则&#xff1a; DynamicRuleProvider<T>: 拉取规则Dy…

面试官问我Redis怎么测,我一脸懵逼!

有些测试朋友来问我&#xff0c;redis要怎么测试&#xff1f;首先我们需要知道&#xff0c;redis是什么&#xff1f;它能做什么&#xff1f; redis是一个key-value类型的高速存储数据库。 redis常被用做&#xff1a;缓存、队列、发布订阅等。 所以&#xff0c;“redis要怎么测试…

单片机的ADC

如何理解ADC。ADC就是将模拟量转换成数字量的过程&#xff0c;就是转换为计算机所能存储的0和1序列&#xff0c;比如将模拟量转换为一个字节&#xff0c;所以这个字节的大小要能反应模拟量的大小&#xff0c;比如一个0-5V的电压测量量&#xff08;外部输入电压最小0V,最大为5V&…

Lnton羚通视频算法算力云平台如何快速了解pandas(下)

数据分组 Splitting : 利用某些条件将数据进行分组Applying : 函数应用于每个单独的分组Combining : 合并最终的结果 df pd.DataFrame({"A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo&q…

内网 里面安装 vue

1.先在内网电脑上安装node,跟自己电脑一样的版本 2.把自己电脑 node里面 node-cache, node_global&#xff0c;node_modules 三个文件 拷贝到内网电脑 的node 里面 3.内网在配置 node_cache的环境变量环境变量如何配置连接