STM32之基本定时器TIM6和TIM7

1.定时器概念和作用

在编程任务中,定时器是非常常用的一个问题。当需要定时发送数据,定时起某个任务,定时做某个操作等等,这些都离不开定时器。本文基于以STM32F4xx系列开发板,介绍一下基本定时器。

2.基本定时器TIM6和TIM7介绍

如下图所示,基本定时器有两个,分别是TIM6和TIM7。它们的计数器都是16位的,也就是意味着取值范围对无符号数来说是0到65535。基本定时器工作时,主要涉及三个寄存器,分别是计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。
在这里插入图片描述
顾名思义,计数器寄存器(TIMx_CNT)是用来计数的,它的值是从0开始递增。而当计数寄存器的值等于自动重载寄存器(TIMx_ARR)中的值时,就会生 成事件,将相关事件标志位置位,生成中断输出。

预分频器寄存器(TIMx_PSC)是用来分频的,它有一个输入时钟CK_PSC和一个输出时钟CK_CNT。
CK_CNT=fCK_PSC/(PSC[15:0]+1)

定时周期就是由预分频器寄存器(TIMx_PSC)和自动重载寄存器(TIMx_ARR)来决定。

假如自动重载寄存器(TIMx_ARR)的值为4999,即计数器寄存器(TIMx_CNT)从0开始计数,到4999时(总共计数50000次)就会产生中断。假如此时定时器的定时频率为10000Hz,那么一个定时周期就是50000*(1/10000)= 5S。即5S就会产生一次定时中断,我们就可以在中断处理程序中,添加我们的业务逻辑代码。

3.代码

/*** @brief  初始化基本定时器* @param  无* @retval 无*/
void TIMx_Configuration(TIM_TypeDef * tim)
{TIMx_NVIC_Configuration(tim);	TIM_Mode_Config(tim);
}/*** @brief  基本定时器 TIMx,x[6,7]中断优先级配置* @param  TIM_TypeDef * tim:TIM6 or TIM7* @retval 无*/
static void TIMx_NVIC_Configuration(TIM_TypeDef * tim)
{if (tim == TIM6){NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		// 设置中断来源NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQn; 	// 设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 // 设置子优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}if (tim == TIM7){NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		// 设置中断来源NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM7_IRQn; 	// 设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 // 设置子优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}
}/** 注意TIM_TimeBaseInitTypeDef结构体中有5个成员,TIM6和TIM7的寄存器里面只有* TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可* 另外三个成员是通用定时器和高级定时器才有.*-----------------------------------------------------------------------------* TIM_Prescaler         都有* TIM_CounterMode			 TIMx,x[6,7]没有,其他都有(基本定时器)* TIM_Period            都有* TIM_ClockDivision     TIMx,x[6,7]没有,其他都有(基本定时器)* TIM_RepetitionCounter TIMx,x[1,8]才有(高级定时器)*-----------------------------------------------------------------------------*/
static void TIM_Mode_Config(TIM_TypeDef * tim)
{if (tim == TIM6){TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;// 开启TIMx_CLK,x[6,7] RCC_APB1PeriphClockCmd(BASIC_TIM_CLK, ENABLE); /* 累计 TIM_Period个后产生一个更新或中断*/		//当定时器从0计数到4999,即为5000次,为一个定时周期TIM_TimeBaseStructure.TIM_Period = 60 - 1;       // 每0.34ms启动一个定时器中断//定时时钟源 TIMxCLK = 2 * PCLK1  //				PCLK1 = HCLK / 4 //				=> TIMxCLK=HCLK/2=SystemCoreClock/2=84MHz// 设定 定时器频率为 =TIMxCLK/(TIM_Prescaler+1)=10000HzTIM_TimeBaseStructure.TIM_Prescaler = 1000 - 1;	// 初始化定时器 TIMx, x[2,3,4,5]TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);// 清除定时器更新中断标志TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);// 开启定时器更新中断TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);// 使能定时器//	TIM_Cmd(BASIC_TIM, ENABLE);		}if (tim == TIM7){TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;// 开启TIMx_CLK,x[6,7] RCC_APB1PeriphClockCmd(BASIC_TIM7_CLK, ENABLE); /* 累计 TIM_Period个后产生一个更新或中断*/		//当定时器从0计数到167,即为168次,为一个定时周期TIM_TimeBaseStructure.TIM_Period = 50000 - 1;       // 5s//定时时钟源 TIMxCLK = 2 * PCLK1  //				PCLK1 = HCLK / 4 //				=> TIMxCLK=HCLK/2=SystemCoreClock/2=84MHz// 设定 定时器频率为 =TIMxCLK/(TIM_Prescaler+1)=10000HzTIM_TimeBaseStructure.TIM_Prescaler = 8400 - 1;	//定时器频率10 Khz// 初始化定时器 TIMx, x[2,3,4,5]TIM_TimeBaseInit(BASIC_TIM7, &TIM_TimeBaseStructure);// 清除定时器更新中断标志TIM_ClearFlag(BASIC_TIM7, TIM_FLAG_Update);// 开启定时器更新中断TIM_ITConfig(BASIC_TIM7,TIM_IT_Update,ENABLE);// 使能定时器//	TIM_Cmd(BASIC_TIM, ENABLE);		}	
}

当产生中断时,中断号和中断处理函数为:
在这里插入图片描述
中断号:
在这里插入图片描述
在这里插入图片描述

实现业务逻辑为,当RS232串口接收到第一个字节数据时,把TIM7给使能(使能后,开始计数)。当一个定时周期(本程序设置的是5s),认为RS232串口已经收好一串数据了,此时在定时中断处理承租中,把一个全局变量标志置上,置成1,认为数据接收完成,可以进入数据处理了,在main函数中,添加对数据的处理的业务逻辑代码。

在这里插入图片描述

//串口中断处理函数---接收
#define UART_BUFF_SIZE      1024
volatile    uint16_t uart_len = 0;
uint8_t     g_uart_buff[UART_BUFF_SIZE] = {0};extern uint8_t g_recvData;void USART6_IRQHandler(void) //当串口上有字节传送过来的时候,便会产生中断,即每个字节过来会产生一次串口接收中断
{uint8_t clear;if(uart_len<UART_BUFF_SIZE){while(USART_GetITStatus(USART6, USART_IT_RXNE) != RESET) // USART6串口的接收数据寄存器非空,表明有新的数据待读取{g_uart_buff[uart_len] = USART_ReceiveData(USART6);uart_len++;TIM_Cmd(BASIC_TIM7, ENABLE);	//当转接板接收到长强板第一个数时,就把Tim7的使能给置上,Tim7开始计数USART_ClearITPendingBit(USART6, USART_IT_RXNE);}}else{ // 接收的数据长度超过UART_BUFF_SIZE 时,这次数据全部丢弃USART_ClearITPendingBit(USART6, USART_IT_RXNE);clean_usart_rebuff();       }if (USART_GetITStatus(USART6, USART_IT_IDLE) != RESET) // 用来判断是否收到一帧数据 https://blog.csdn.net/ASKLW/article/details/79246786{	//数据通过RS232接收到后,进入逻辑处理,调用motor.c相关函数// 定义一个全局变量,当数据接收完成后,把全局变量置为true,后续进行处理clear = USART6->SR; //先读SR,再读DR才能完成idle中断的清零,否则一直进入中断。clear = USART6->DR;uint16_t len = 0;
//			char str[1024] ={0};
//		  sprintf(str, "%d", ii);  
//			Usart_SendByte(USART6, len);
//		ii++;
//Usart_SendString(USART6, get_usart_rebuff(&len));	
//Usart_SendString(USART6, "AABBCCDDEEFFGG");	//      uint16_t len1 = 0;
//			const char* cmdline = get_usart_rebuff(&len1); // 测试用例:"0x81VT=100"
//					printf("cmdlineusart = %s\n", cmdline);	
//Usart_SendString(USART6, "0x82VT=100");		g_recvData = 0x01;}
}	

中断处理程序:

extern uint8_t g_timer7;
void  BASIC_TIM7_IRQHandler (void)
{if ( TIM_GetITStatus( BASIC_TIM7, TIM_IT_Update) != RESET ) {	
//		printf("timer");g_timer7 = 1; //在定时器中断。把标志位置上TIM_ClearITPendingBit(BASIC_TIM7 , TIM_IT_Update);  		 }		 	
}

数据处理:

		if (g_timer7 == 0x01) //表明接收数据已经完成,需要进入对数据的处理  g_recvData == 0x01{g_timer7 = 0;			uint16_t len = 0;const char* cmdline = get_usart_rebuff(&len); // 测试用例:"0x81VT=100"printf("cmdline=%s\n", cmdline);
//			Usart_SendString(USART6, get_usart_rebuff(&len));		}		

交流碰撞思想火花!欢迎大家留言评论!

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

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

相关文章

基于Ubuntu24.04,下载并编译Android12系统源码 (二)

1. 前言 上篇文章&#xff0c;我们基于Ubuntu24.04&#xff0c;已经成功下载下来了Android12的源码&#xff0c;这篇文章我们会接着上文&#xff0c;基于Ubuntu24.04来编译Android源码。 2. 编译源码 2.1 了解源码编译的名词 Makefile &#xff1a; Android平台的一个编译系…

鸿蒙网络编程系列28-服务端证书锁定防范中间人攻击示例

1. TLS通讯中间人攻击及防范简介 TLS安全通讯的基础是基于对操作系统或者浏览器根证书的信任&#xff0c;如果CA证书签发机构被入侵&#xff0c;或者设备内置证书被篡改&#xff0c;都会导致TLS握手环节面临中间人攻击的风险。其实&#xff0c;这种风险被善意利用的情况还是很…

PHP企业门店订货通进销存系统小程序源码

订货通进销存系统&#xff0c;企业运营好帮手&#xff01; &#x1f4e6; 开篇&#xff1a;告别繁琐&#xff0c;企业运营新选择 嘿&#xff0c;各位企业主和创业者们&#xff01;今天我要给大家介绍一款超实用的企业运营神器——“订货通进销存系统”。在这个数字化时代&…

Docker入门之构建

Docker构建概述 Docker Build 实现了客户端-服务器架构&#xff0c;其中&#xff1a; 客户端&#xff1a;Buildx 是用于运行和管理构建的客户端和用户界面。服务器&#xff1a;BuildKit 是处理构建执行的服务器或构建器。 当您调用构建时&#xff0c;Buildx 客户端会向 Bui…

Element UI

Element ui 就是基于vue的一个ui框架,该框架基于vue开发了很多相关组件,方便我们快速开发页面。 官网: https://element.eleme.io/#/zh-CN 安装Element UI vue init webpack element(项目名)确认项目是否构建成功&#xff1a;进入到项目的根路径 执行 npm start 访问 h…

NSSCTF

[NSSRound#1 Basic]basic_check nikto扫描 nikto -h url PUT请求&#xff0c;如果不存在这个路径下的文件&#xff0c;将会创建&#xff0c;如果存在&#xff0c;会执行覆盖操作。 [NSSRound#8 Basic]MyDoor if (isset($_GET[N_S.S])) {eval($_GET[N_S.S]); } php特性&#…

形式架构定义语言(ADL)

简介 形式规范 多年来&#xff0c;学术界一直在试图通过使用与测试截然不同且更加主动的方法来确保程序语义的正确执行&#xff1a;形式化方法。研究者们认为这种方法通过更加精确、无二义性的描述来达到让程序绝对地按照设计者的思想执行的目的。这种思想早期体现在Floyd在1…

STM32之OLED驱动函数

类似51单片机中的LCD1602驱动差不多&#xff0c; 1.oled驱动代码 oled.c #include "stm32f10x.h" #include "OLED_Font.h"/*引脚配置*/ #define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x)) #define OLED_W_SDA(x) GPIO_WriteBi…

Python入门(二)编程中的“真”与“假”,单双向选择的判断

编程中的“真”与“假” 在编程中&#xff0c;这种“真”、“假”状态我们用布尔数来表示&#xff0c;“真”是True&#xff0c;“假”是False。 另一种方式&#xff0c;是通过比较运算得到。 如图&#xff0c;3赋值给a&#xff0c;1赋值给b&#xff0c;进行大小的比较。 a &g…

U9的插件开发之BE插件(1)

U9插件可分为&#xff1a;BE插件、BP插件、UI插件&#xff1b; BE(Business Entity) 简单就是指实体&#xff0c;U9的元数据。 我的案例是设置BE默认值&#xff0c;即在单据新增时&#xff0c;设置单据某一个字段的默认值&#xff0c;具体如下&#xff1a; 1.插件开发工具&a…

Linux的目录结构 常用基础命令(2)

Linux的目录结构 根目录&#xff1a; 所有分区、目录、文件等的位置起点 整个树形目录结构中&#xff0c;使用独立的一个“/”表示 常见的子目录 /root /bin /boot /dev /etc /home /var /usr /sbin 基础知识 以 . 开头的文件均为隐藏文件 路径用/分开 / 不在第一位就…

plsql 高版本用不了 expaste 插件 问题

plsql 高版本用不了 expaste 插件 问题 其实不是版本问题&#xff0c;而是高版本的咩有在用这个插件&#xff0c;在另外一个功能里面&#xff0c; 查询你要的数据&#xff0c; 选择数据&#xff0c;右键&#xff0c;点 右键 复制为表达式列表&#xff0c;即可 在空白处粘贴…

【C++】C++11基础入门

目录 一、C11发展史&#xff1a; 二、列表初始化&#xff1a; 1、初始化&#xff1a; 2、initializer_list函数&#xff1a; 三、声明&#xff1a; 1、auto自动识别类型&#xff1a; 2、decltype&#xff1a; 3、nullptr&#xff1a; 四、范围for&#xff1a; 五、STL…

vue3+vue-baidu-map-3x 实现地图定位

文档地址&#xff1a;一个是2一个是3 https://dafrok.github.io/vue-baidu-map/#/zh/index vue-baidu-map-3x 1.首先要到百度地图开放平台上建一个账号&#xff0c;如果有百度账号可以直接登录百度地图-百万开发者首选的地图服务商,提供专属的行业解决方案 2.点击控制台&am…

V2X介绍

文章目录 什么是V2XV2X的发展史早期的DSRC后起之秀C-V2XC-V2X 和DSRC 两者的对比 什么是V2X 所谓V2X&#xff0c;与流行的B2B、B2C如出一辙&#xff0c;意为vehicle to everything&#xff0c;即车对外界的信息交换。车联网通过整合全球定位系统&#xff08;GPS&#xff09;导…

C#使用log4net结合sqlite数据库记录日志

0 前言 为什么要把日志存到数据库里? 因为结构化的数据库存储的日志信息,可以写专门的软件读取历史日志信息,通过各种条件筛选,可操作性极大增强,有这方面需求的开发人员可以考虑。 为什么选择SQLite? 轻量级数据库,免安装,数据库的常用的基本功能都有,可以随程序…

如何打开/解包星露谷物语XNB文件(附软件资源)

一、什么是 XNB 文件&#xff1f; 游戏将数据、地图和纹理存储在 .xnb 这种压缩数据文件中&#xff0c;它们在游戏的 Content 文件夹中。例如&#xff0c;对话期间显示的阿比盖尔的头像来自这个文件&#xff1a; Content\Portraits\Abigail.xnb。解包这个文件&#xff0c;你会…

SIP 业务举例之 Call Forwarding - No Answer(无应答呼叫转移)

目录 1. Call Forwarding - No Answer 简介 2. RFC5359 的 Call Forwarding - No Answer 信令流程 呼转开始 呼转完成 3. Call Forwording - No Answer 过程总结 博主wx:yuanlai45_csdn 博主qq:2777137742 想要 深入学习 5GC IMS 等通信知识(加入 51学通信),或者想要 …

ISO21434 信息安全开发流程咨询合规内容和步骤

ISO 21434是汽车网络安全风险管理的一项国际标准&#xff0c;旨在帮助汽车制造商和供应商识别、评估和管理车辆整个生命周期中的网络安全风险。以下是ISO 21434咨询可能包含的内容以及实施咨询的方法论步骤&#xff1a; 咨询内容&#xff1a; 标准解读与培训&#xff1a;帮助…

【Unity】Unity中文本中插入超链接且可点击响应,TextMeshPro的进阶用法

一、需求和尝试 今天遇到这样一个需求&#xff1a;在文本中插入超链接&#xff0c;且这个链接可以点击跳转对应的url&#xff0c;具体形式如下图所示。 其实这个有一个简单粗暴的方法&#xff0c;就是把需要加超链接的文本单独拿出来&#xff0c;和其他文本进行拼接&#xf…