【嵌入式知识11】使用STM32定时器中断控制串口发送“hello windows!”

  本次实验学习通过定时器Timer方式实现对时间的精准控制,相当于给CPU上了一个闹钟,CPU平时处理其它任务,当定时时间到了以后,处理定时相关的任务。设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁。

一、定时器概念

1. 定时器的分类

定时器可分为

  • 高级定时器 TIM1 TIM8
  • 通用定时器 TIM2 TIM3 TIM4 TIM5
  • 基本定时器 TIM6 TIM7

在这里插入图片描述

  定时器中断是由单片机中的定时器溢出而申请的中断。STM32中共有11个定时器,具体如下:

1、两个高级定时器:TIM1、TIM8-------------------------APB2
2、四个通用定时器:TIM2~TIM5-------------------------APB1
3、两个基本定时器:TIM6、TIM7-------------------------APB1 4、两个看门狗
5、一个系统嘀嗒定时器(SysTick)

2. 高级定时器、通用定时器和基本定时器的区别

TIM1和TIM8定时器的功能包括【增强型】

● 16位向上、向下、向上/下自动装载计数器
●16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值
● 多达4个独立通道: ─输入捕获 ─ 输出比较 ─ PWM生成(边缘或中间对齐模式) ─ 单脉冲模式输出
● 死区时间可编程的互补输出
●使用外部信号控制定时器和定时器互联的同步电路
允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
●刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
● 如下事件发生时产生中断/DMA: ─更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) ─ 输入捕获 ─ 输出比较─ 刹车信号输入
● 支持针对定位的增量(正交)编码器和霍尔传感器电路
●触发输入作为外部时钟或者按周期的电流管理

TIMx主要功能通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括【通用型】

● 16位向上、向下、向上/向下自动装载计数器
●16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值
● 4个独立通道: ─ 输入捕获 ─输出比较 ─ PWM生成(边缘或中间对齐模式) ─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
●如下事件发生时产生中断/DMA: ─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) ─
触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) ─ 输入捕获 ─ 输出比较

●支持针对定位的增量(正交)编码器和霍尔传感器电路
● 触发输入作为外部时钟或者按周期的电流管理

TIM6和TIM7定时器的主要功能包括【精简型】

● 16位自动重装载累加计数器
● 16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1~65536之间的任意数值分频
触发DAC的同步电路 注:此项是TIM6/7独有功能.
● 在更新事件(计数器溢出)时产生中断/DMA请求

二、定时器功能

1. 定时器结构图

定时器结构框图分为5部分

  • 时钟产生部分
  • 定时器部分
  • 输入比较部分
  • 输出比较部分
  • 寄存器部分

具体结构如图所示:
在这里插入图片描述

2. STM32定时器功能—计时&&中断

  定时器的计时我个人理解为控制计数的数量来控制定时的时间,由于定时器的计数频率和计数量可调,所以可以控制定时器的计时时间、计数频率和系统时钟、重装载值(arr)和预分频系数(psc)有关。
  系统时钟在前面关于时钟的学习总结中已经讲解,我们会在主函数的最开始设置系统时钟,STM32单片机的时钟一般设置为最高的72M。预分频系数是指系统时钟经过几分频作为定时器的时钟,预分频系数设置为0的时候就是1分频,也就是不分频,设置为1时候是2分频,3的时候就是4分频,4的时候…总的来说就是PSC+1倍分频。
   最大重装载值就是定时器的最大计数值,STM32定时器有一个十六位的计数寄存器,最大计数值就是65535。每次配置定时器都要设置arr和psc,下面给出一段定时器配置的程序。

	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period=arr;
	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//定时器初始化,配置参数

  定时器中断就是在定时器的计数值达到想要的最大计数值时(可以理解为爆表),也就是想要的计时时间后,进入一次中断,在中断中执行特定的代码。
以下代码为定时器中断的配置,设置了定时器的计数时间,中断的触发方式(更新中断,也就是爆表),以及中断的优先级,以及最重要的使能中断。

void TIM2_Int_Init(u16 arr,u16 psc)//定时器2中断初始化  arr为重装载值 psc为分频系数 主函数要进行中断分组
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//定时器时钟使能
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period=arr;
	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//定时器初始化,配置参数
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//设置更新中断
	
	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	
	NVIC_Init(&NVIC_InitStruct);
	TIM_ARRPreloadConfig(TIM2,ENABLE);
	TIM_Cmd(TIM2,ENABLE);//使能TIM2定时器
}

3. 定时时钟计算方法和计数模式

定时器的时钟计算公式为:

Tout = ((arr+1)(psc+1))/Tclk

  • Tclk:定时器的输入时钟频率(单位MHZ)
  • Tout:定时器溢出时间(单位为us)
  • arr: 计数装载值
  • psc: 时钟分频系数

定时器的计数模式分为以下三种:

  • 向上计数模式: 计数值从0计数到自动加载值(TIM_ARR),产生一个计数溢出事件,然后重新从0开始计数

  • 向下计数模式:计数器从自动装入的值(TIM_ARR)开始向下计数到0,产生一个计数溢出事件,然后从计数装入值重新开始。

  • 中央对齐模式: 计数器从O开始到(自动装入值-1),产生计数溢出事件,然后向下计数到1,产生定时器溢出事件,然后从0开始计数。

三、CubeMX初始化配置

1. 选择芯片开始创建项目

选择STM32F103C8T6——>开始项目
在这里插入图片描述

2. 配置时钟

选择外部时钟HSE
在这里插入图片描述
配置时钟树
在这里插入图片描述

3. TIM2中断相关配置

  TIM2选择外部时钟作为时钟源,APB1时钟频率为72M,经过PSC72分频后定时器时钟频率为1Mhz,计数周期5000计满时间为0.005S,计数方式为向上计数。
在这里插入图片描述
定时器中断
在这里插入图片描述

4. 外设引脚配置

在这里插入图片描述
初始化USART1串口
在这里插入图片描述

5. 项目命名与工程导出

文件命名为 timer interrupt

在这里插入图片描述

四、 代码编写

1. 启动TIM2定时器中断

	HAL_TIM_Base_Start_IT(&htim2); //启动定时器2中断   //PAB1总线时钟频率72M,分频系数72-1

写在while()函数之前
在这里插入图片描述

2. 初始化定时器TIM2

代码CubeMX自动配置好了

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 5000;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

3. 回调函数

回调函数,计时满2s时,LED电平翻转一次;计时满5s时,串口发送一个字符串到上位机。

__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(htim);
	time_count1++;
	time_count2++;
	if(time_count1==400)                //200次定时器中断计时满2s,计满2s控制PA3的LED灯电平翻转
	{
		HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_3);
		time_count1=0;
	}
	if(time_count2==1000)
	{
		HAL_UART_Transmit(&huart1,Tx_buf,sizeof(Tx_buf),100);		//1000次定时器中断计时满5s,计满串口发送字符串
		time_count2=0;
	}
	
  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */
}

实验结果见视频:

定时器中断

五、总结

  本次实验学习了通过定时器Timer方式实现时间的精准控制,设置一个5秒的定时器,每隔5秒串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁。
  实验过程中,对定时器的配置是最开始需要注意的,不然CubeMX导出的文件将出现问题。相比于Delay函数,定时器中断能更准确地把握时间,中断一触发,就执行中断服务函数中的功能。定时器中断与串口通信的结合,完成了中断控制串口通信的功能,这也让我对所学知识有了更深一步的认识。

六、参考资料

http://www.mcublog.cn/stm32/2021_01/stm32cubemx-dingshiqi-led/

https://www.cnblogs.com/kmist/p/11669232.html

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32G431系列定时器中断的配置需要通过STM32CubeMX软件进行参数配置。首先,需要在定时器模块选择所需的定时器(如高级定时器TIM1、TIM8、通用定时器TIM2、TIM3、TIM4等)。然后,在KEIL5软件编写定时器中断函数,该函数会在定时器中断发生时被调用。接下来,启动定时器,使其开始计时并触发定时器中断。 请注意,根据网络上的资料来看,蓝桥杯嵌入式竞赛好像不考察外部断,因此在学习蓝桥杯嵌入式开发板时,可以跳过外部断的学习,重点关注定时器的应用。在STM32G431系列,定时器通常分为高级定时器、通用定时器和基本定时器三种,它们分别具有不同的功能和使用方式。高级定时器具有完整的三种定时器模式(向上、向下、向上/向下),可以用于各种目的,如测量输入脉冲长度信号(输入捕获)或产生输出波形(输出比较、PWM、带死区插入的互补PWM)。通用定时器与高级定时器类似,但无法输出互补PWM波。基本定时器一般用于驱动DAC,在其他情况下较少使用。 总之,要实现STM32G431定时器中断,需要使用STM32CubeMX软件配置定时器参数,编写定时器中断函数,并启动定时器。具体的定时器选择和配置取决于所需的功能和应用场景。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [蓝桥杯--嵌入431RBT6(定时器中断篇)](https://blog.csdn.net/weixin_57089671/article/details/129093658)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [蓝桥杯STM32G431RBT6学习——定时器中断](https://blog.csdn.net/weixin_44098974/article/details/128729412)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小梅同学charles

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值