使用定时器进行串口通信和点灯
一、定时器理论知识
1、定时器分类
STM32定时器分类如图,这些定时器完全独立、互不干扰,可以同步操作。
STM32F103微控制器内部集成多个可编程定时器,分为基本定时器、通用定时器和高级定时器3大类。
基本定时器:TIM6和TIM7;
通用定时器:TIM2、TIM3、TIM4和TIM5;
高级定时器:TIM1和TIM8。
从功能强度上看:高级定时器>通用定时器>基本定时器
2、定时器功能
(1)计数:对外部脉冲信号进行计数
(2)定时:时间控制,通过对微控制器内部的时钟脉冲进行计数来实现定时功能
(3)输入捕获:对输入信号进行捕获(采样或存储),实现对脉冲的频率测量,可用于对外部输入信号脉冲宽度的测量。
(4)输出比较:将计数器当前的计数值和设定值进行比较,根据比较结果输出不同电平,用于控制输出波形。
3、通用定时器
本次设计使用通用定时器,所以这里重点介绍通用定时器。
通用定时器TIMx(x=2,3,4,5)主要由时钟源、时钟单元、捕获和比较通道组成。
(1)时钟源:系统默认配置中,TIMxCLK的时钟频率都是72MHz.
(2)预分频器(PSC):可以以1~65535之间的任意数值对时钟源CK_PSC的时钟频率进行分频,输出的CK_CNT脉冲供计数器计数。
(3)计数器(CNT):计数范围为1~65535,可以向上计数、向下计数或向上向下双向计数。当计数值达到设定值时,会产生溢出事件,溢出时产生中断或DMA请求。
(4)自动装载寄存器(ARR):每次计数器溢出事件后将设定的计数数值重新装载到计数器中。
定时时间=(ARR+1)×(预分频值PSC+1)/输出时钟频率
二、工程创建
1、设计要求
设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁,实现一个多任务并发运行的功能。
2、配置STM32CubeMX
创建一个新项目
选择STM32F103C8T6芯片
配置RCC
配置SYS
配置IO口输出
配置时钟
配置定时器
这里选择通用定时器TIM2和TIM3
系统处理的时候会把分频系数自动加上1,所以输入的71分频,实际进行的是72分频。由于时钟配置为72MHZ,分频后得到1MHZ的时钟。计数5000次得到时间5000/1000000=0.005秒。也就是每隔0.005秒定时器2会产生一次定时中断。
配置中断
配置USART
项目管理
项目生成
在Keil中打开
三、代码编写
1、启动定时器TIM2、TIM3
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
2、串口发送“hello windows!”
/* USER CODE BEGIN 0 */
uint8_t hello[20]="hello windows!\r\n";
/* USER CODE END 0 */
HAL_UART_Transmit(&huart1,hello,20,100000);
3、定时器中断回调
设计要求是每隔5秒从串口发送“hello windows!”,LED周期性地闪烁的周期为两秒。定义time_cnt和time_cnt1用来计数,由于配置的一次定时中断的时间是0.005秒,5/0.005=1000,2/0.005=400。time_cnt1 = 1000时,串口发送消息,time_cnt = 400时,LED的状态翻转一次。
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t time_cnt =0;
static uint32_t time_cnt1 =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_cnt1 >= 1000)
{
time_cnt1 =0;
HAL_UART_Transmit(&huart1,hello,20,100000);
}
}
}
/* USER CODE END 4 */
四、结果演示
使用定时器进行串口通信和点灯
五、总结
使用定时器节省了资源也减短了设计时间,只需要通过简单的计算就可以达到理想时间的定时。如果不使用定时器,可以在主循环中通过嵌套不同的延时循环来分别实现两个不同周期的任务。这种方法是比较简单直接的,但会占用大量的 CPU 资源,并且时间精度相对较低。