STM32配置TIM定时器计数

本文介绍了STM32的定时器Timer,包括定时器类型、基本结构和工作过程。通过HAL库配置了TIM2和TIM3,实现5秒间隔串口发送及2秒周期LED闪烁功能,强调了定时器中断的重要性,并提供了源代码和参考资料。

一、定时器Timer介绍

01 TIM简介

  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源的选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为高级定时器、通用定时器、基本定时器三种类型

02 定时器类型

STM32F103C8T6定时器资源只有TIM1、TIM2、TIM3、TIM4

类型编号总线功能
高级定时器TIM1 TIM8APB2拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能
通用定时器TIM2 TIM3 TIM4 TIM5APB1拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
基本定时器TIM6 TIM7APB1拥有定时中断、主模式触发DAC的功能

03 定时器基本结构

可以查阅STM32 F10xxx中文参考手册,理解三种定时器不同的寄存器结构

  1. 高级定时器在这里插入图片描述

  2. 通用定时器在这里插入图片描述

  3. 基本定时器在这里插入图片描述

04定时器中断基本结构

在这里插入图片描述

05 定时器工作过程

第一部分首先看到psc预分频器需要接收时钟源,而时钟源共有四种来源,分别如下:

  • RCC寄存器中的APB1外设时钟使能寄存器,经过倍频之后输出时钟源,这是因为该寄存器的位0到位5分别表示的是定时器2到定时器7的使能位。

  • 外部触发引脚TIMx_ETR的外部触发输入ETR,对应的引脚可以通过查数据手册得到。ETR经过分频得到ETRP,在经过滤波得到ETRF作为时钟信号。

  • 内部触发输入(ITRx),来自其他的定时器的时钟,即将,经过后面的选择器,进入到触发控制器。

  • 外部输入引脚Tix,这个主要来自于TIMx_CHx (四个通道)。

第二部分为时基单元,包括PSC预分频器、自动重装载寄存器和CNT计数器。首先由第一部分产生时钟源,进入PSC预分频器进行分频处理,得到新的时钟信号CK_CNT,使得CNT计数器加1或者减1,此时在自动重装载寄存器中有一个预先设定的装载值,当计数器的值达到装载值的时候,会产生溢出事件,然后触发中断。

第三部分为输入捕获,TIMx_CH1——TIMx_CH4 这四个通道,在芯片中都有对应的引脚,当脉冲从通道口进入时,经过输入滤波器(抗干扰的作用),然后经过边沿检测器检测到上升沿(下降沿),经过分频器,输入到捕获寄存器中,然后捕获寄存器记录此刻CNT计数器的值,当下一次下降沿(上升沿)过来时,也记录下CNT计数器的值,这样就可以计算出输入脉冲的宽度。

第四部分为输出比较(注意输入捕获和输出比较不可以同时进行),比如在比较寄存器中预先设定一个值,计数器从初始值到装载值之间计数时,当正好等于比较寄存器中的预设值时,控制TIMx_CH1——TIMx_CH4通道输出低电平或者高电平,这样随着计数器不断的计数,就可以获得一个脉冲,通过调整预设值,就可以调整脉冲宽度,调整初始值和装载值就可以调整周期。

二、HAL库小试定时器

01 题目要求

之前的延时功能都是通过循环、delay/Hal_delay函数等实现,本次通过定时器Timer方式实现时间的精准控制,相当于给CPU上了一个闹钟,CPU平时处理其它任务,当定时时间到了以后,处理定时相关的任务。请设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁。

02 配置CubeMX

  1. 配置RCC为高速时钟,在菜单栏中选Crystal/Ceramic Resonator 在这里插入图片描述

  2. 配置SYS,菜单栏中选Serial Wire在这里插入图片描述

  3. 配置端口输出,选择PA1作为LED灯的输出在这里插入图片描述

  4. 配置定时器TIM2和TIM3在这里插入图片描述其次在这里插入图片描述

注意:分频系数虽然是71,但系统处理的时候会自动加上1,所以实际进行的是72分频。由于时钟一般会配置为72MHZ,所以72分频后得到1MHZ的时钟;1MHZ的时钟,计数5000次,得到时间5000/1000000=0.005秒;也就是每隔0.005秒定时器2会产生一次定时中断

  1. 配置定时器中断在这里插入图片描述配置中断优先级在这里插入图片描述

  2. 配置USART1,异步通信Asynchronous在这里插入图片描述

  3. 配置时钟树在这里插入图片描述

  4. 生成项目

03 配置Keil

  1. 启动定时器的代码,“h”表示HAL库,“tim2”表示定时器2。所以这行代码的意思就是启动定时器2和定时器3。在这里插入图片描述

  2. 添加串口输出变量数组为全局变量,方便在后续回调函数中输出在这里插入图片描述

  3. 配置定时器中断回调。该函数为定时器的中断回调函数,当产生定时中断的时候,会自动调用这个函数。在函数内部定义了定时器的一个静态变量:time_cnt与定时器3 的time_cnt3。在这里插入图片描述回调函数如下:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint32_t time_cnt =0;
	static uint32_t time_cnt3 =0;
	if(htim->Instance == TIM2)
	{
		if(++time_cnt >= 400)
		{
			time_cnt =0;
			HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
		}
	}
	if(htim->Instance == TIM3)
	{
		if(++time_cnt3 >= 1000)
		{
			time_cnt3 =0;
    HAL_UART_Transmit(&huart1,hello,20,100000);
		}
			
	}
}

例如time_cnt,当它大于等于100的时候,才会执行if里面的代码。也就是说需要发生400次中断,才会让LED的状态翻转。前面已经算过了,一次定时中断的时间是0.005秒,所以400次中断的时间是0.005400=2秒。也就是说每隔2秒,LED的状态翻转一次。
例如time_cnt3,当它大于等于1000的时候,才会执行if里面的代码。也就是说需要发生1000次中断,才会让串口发一次消息。0.0051000=5秒,符合题目要求。

04 结果展示

2s转换灯的状态


5s串口通信展示

三、库函数实现定时器计数

笔者使用B站UP主江科大自化协实现一秒计时的功能,但是没有配置定时器中断,而在主函数循环中对计数的变量进行判断,但是无法完成间隔五秒串口发送信息。具体函数如下。

	while (1)
	{
		//OLED_ShowNum(1, 5, Num, 5);OLED输出Num的值
		if(Num % 2 == 0)
			LED1_ON();
		if(Num % 4 == 0)
			LED1_OFF();
		
		if(Num % 5 == 0)
			Flag = 1;	
		while(Flag == 1 ){
			Flag2 = 0;
			}
	}

Num在中断函数中执行Num++操作,笔者在和队友讨论之后认为是硬件在实现过程中在主函数多次循环,当Num由5变为6的时候,主函数执行了很多次串口通信的程序,所以定时器中断是不能没有的。这就是硬件编程和软件编程的很大区别。

四、总结

完成定时器中断学习了库函数和HAL库两种操作,这部分的内容有点繁杂,需要我们在之后中多多练习使用,才能加深理解,记得更牢固。如果没有自己动手操作,那么我们学到的知识也就会更少。多学多练才能完成更好。
非常感谢同学的解答和B站的优秀教程,给了我很大的帮助

源代码

  1. Gitee仓库地址,HAL库源码
  2. Gitee仓库地址,库函数源码(有小问题)

参考资料

  1. CSDN-定时器工作原理
  2. 优秀的HAL库定时器操作
  3. 江科大自化协B站教程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值