STM32F103 通过定时器Timer方式实现时间的精准控制,实现串口通信并让LED等周期性地闪烁

1、任务背景

通过定时器Timer方式实现时间的精准控制。
设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁。

2、什么是定时器

定时器/计数器作为SoC的外设,主要用来实现定时执行代码的功能。定时器相对于SoC来说,就好像闹钟相对于人来说意义一样。单核的CPU是单线程的,只能干一件事情,干完这件事情完去干另一件事情需要定时器来提醒。
2. 计数器时钟(CK_CNT)
定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。
3. 计数器(CNT)
计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
4. 自动重装载寄存器(ARR)
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

分类
定时器可分为3类:

1、基本定时器:功能最少,只能充当基本的时基,甚至都没有外部引脚
2、通用定时器:拥有基本定时器的全部功能,同时有输入捕获模式,用以接收外部的PWM,脉冲之类的信息
3、高级定时器:又有通用定时器的全部功能,又有互补输出模式,功能最为强大

作用

(1)定时器可以让SoC在执行主程序的同时,可以(通过定时器)具有计时功能,到了一定时间(计时结束)后,定时器会产生中断提醒CPU,CPU会去处理中断并执行定时器的ISR。从而去执行预先设定好的事件。

(2)定时器就好像是CPU的一个秘书一样,这个秘书专门管帮CPU来计时,并到时间后提醒CPU要做某件事情。所以CPU有了定时器之后,只需要预先把自己XX时间之后必须要做的事情绑定到定时器中断ISR即可,到了时间之后定时器就会以中断的方式提醒CPU来处理这个事情。

原理

(1)定时器计时其实是通过计数来实现的。定时器内部有一个计数器,这个计数器根据一个时钟(这个时钟来自于ARM的APB总线,然后经过时钟模块内部的分频器来分频得到)来工作。每隔一个时钟周期,计数器就就计数一次,定时器的时间就是计数器计数值x时钟周期。

(2)定时器内部有1个寄存器TCNT,计时开始时我们会把一个总的计数值(譬如说300)放入TCNT寄存器中,然后每隔一个时钟周期(假设为1ms)TCNT中的值会自动减1(硬件自动完成,不需要CPU软件去干预),知道TCNT中减为0的时候,TCNT就会触发定时器中断。最后的计时时间就是300ms。

(3)定时时间是由2个东西共同决定的:一个是TCNT中的计数值,一个是时钟周期。譬如上例中,定时周期就为300x1ms=300ms。

3、项目创建

①、RCC配置

在这里插入图片描述

②、SYS配置

在这里插入图片描述

③、设置端口输出

这里是将PC15作为LED灯的输出,将其选为GPIO_Output
在这里插入图片描述

④、配置定时器

在这里插入图片描述
分频系数为71,向上计数模式,计数周期为5000,使能自动重载模式。

⑤、配置中断

开启时钟2的中断
在这里插入图片描述
生成定时器2中断优先级配置代码。
在这里插入图片描述

⑥、配置USART1

选择异步通信Asynchronous
在这里插入图片描述

⑦、设置时钟

在这里插入图片描述

⑧、配置项目

在这里插入图片描述

在这里插入图片描述

4、编写代码

在Keil中打开工程,修改main.c文件,添加如下代码:

  HAL_TIM_Base_Start_IT(&htim2);

然后再定义一个全局变量用于存储输出信息

char hello[20]="hello windows!\r\n";

在main函数的下面重写回调中断函数

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_5);
		}
	}
	if(htim->Instance == TIM3)
	{
		if(++time_cnt3 >= 1000)
		{
			time_cnt3 =0;
    HAL_UART_Transmit(&huart1,hello,20,100000);
		}
			
	}
}

5、电路连接

LED灯短脚 —> C15
LED灯长脚 —> 3V3
在这里插入图片描述

6、烧录

7、运行结果

在这里插入图片描述
LED灯以每两秒的间隔进行闪烁
在这里插入图片描述
输出以每五秒的间隔进行输出

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用定时器控制LED灯1s闪烁1次的代码: ```c /* 包含头文件 */ #include "stm32f10x.h" /* 定义LED灯的GPIO端口和引脚号 */ #define LED_GPIO_PORT GPIOB #define LED_GPIO_PIN GPIO_Pin_5 /* 定义定时器的时钟频率和周期 */ #define TIMER_CLOCK_FREQ 72000000 #define TIMER_PERIOD 1000 /* 函数声明 */ void LED_Init(void); void TIM_Init(void); /* 主函数 */ int main(void) { /* 初始化LED灯和定时器 */ LED_Init(); TIM_Init(); while (1) { /* 无限循环 */ } } /* LED灯初始化函数 */ void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* 使能LED灯对应的GPIO时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* 配置LED灯对应的GPIO为推挽输出模式 */ GPIO_InitStruct.GPIO_Pin = LED_GPIO_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); } /* 定时器初始化函数 */ void TIM_Init(void) { TIM_TimeBaseInitTypeDef TIM_InitStruct; /* 使能定时器2时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* 配置定时器2为向上计数模式,时钟频率为72MHz */ TIM_InitStruct.TIM_Period = TIMER_PERIOD - 1; TIM_InitStruct.TIM_Prescaler = TIMER_CLOCK_FREQ / TIMER_PERIOD - 1; TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_InitStruct); /* 使能定时器2的更新事件中断 */ TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); /* 启动定时器2 */ TIM_Cmd(TIM2, ENABLE); /* 配置中断优先级 */ NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); } /* 定时器2中断处理函数 */ void TIM2_IRQHandler(void) { /* 判断是否为定时器2的更新事件中断 */ if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { /* 翻转LED灯的状态 */ GPIO_WriteBit(LED_GPIO_PORT, LED_GPIO_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_GPIO_PORT, LED_GPIO_PIN))); /* 清除定时器2的更新事件中断标志位 */ TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } ``` 该代码使用定时器2控制LED灯1s闪烁1次,具体实现方式是: 1. 在LED_Init函数中,配置LED灯对应的GPIO为推挽输出模式; 2. 在TIM_Init函数中,配置定时器2为向上计数模式,时钟频率为72MHz,定时器周期为1000,即1ms;然后使能定时器2的更新事件中断,并启动定时器2;最后配置中断优先级; 3. 在TIM2_IRQHandler函数中,判断是否为定时器2的更新事件中断,如果是,则翻转LED灯的状态。 注意:该代码是基于StdPeriph库编写的,需要在工程中添加StdPeriph库,并在main函数中调用RCC_Configuration函数。此外,需要在STM32的硬件电路中连接一个LED灯到GPIOB的5号引脚。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值