STM32F767 Timer定时器与Usart串口综合实训

基于B站小蜜蜂笔记!本文利用STM32F767开发板实现该实训!

题目要求: 利用STM32应用开发,完成以下功能。

1.开机后,LED0LED1依次点亮,然后熄灭,进行灯光检测。

2.系统通过串口1发送一个“STMFXxx欢迎你!”

3.LED0作为一个秒闪灯,系统向上位机发送完字符串后,开始亮0.5s,灭0.5s…循环闪烁,并开始启动系统运行程序时间的记录,其时分秒的格式为“xx:xx:xx

4.上位机通过一个由3字节组成的命令帧控制LED1灯开关。该命令的帧的格式为“0xBF 控制字 0xFB

0xBF为帧头,0xFB为帧尾,控制字的定义如下:

0xA1:打开LED1,返回信息“xx:xx:xx LED1打开!

0xA2关闭LED1,返回信息“xx:xx:xx LED1关闭!”

其他:返回信息“xx:xx:xx 这是一个错误指令!”

本次使用的开发板是正点原子的F767阿波罗开发板,如果换成其他开发板,只需修改对应的CubeMX配置引脚即可。参数配置使用CubeMX

1.分析题目

第一步:要求开机后做灯光自检,那就利用HAL_GPIO_WritePin()函数进行LED管脚的值的写入,再利用延时函数HAL_Delay()函数进行延时从而持续点亮LED

第二步:要求发送“STMFXxx欢迎你!”给上位机,那就利用HAL_UART_Transmit()函数进行通信。

第三步:LED要作为一个秒闪灯进行时间的监视,因为这里用的是0.5s的时间间隔,我们就要将定时器时间设置为0.5s,并且利用定时中断的回调函数实现LED0的关闭和开启,并且每次在调用回调函数时,利用HAL_GPIO_TogglePin()函数对LED0的引脚进行电平翻转,从而控制LED0的亮灭,并且同时在回调函数中利用嵌套计时进行时分秒的记录。

第四步:利用上位机发出的指令对STM32进行控制,这里就要利用串口的中断接收函数HAL_UART_Receive_IT进行指令的接受并且在中断回调函数HAL_UART_RxCpltCallback()中对指令进行相应的操作。同时在中断回调函数HAL_UART_RxCpltCallback()中,再次调用HAL_UART_Receive_IT重新接收上位机指令。

2.利用CubeMX配置参数

RCC配置:只需要将高速时钟HSE和低速时钟LSE选择为Crystal/Ceramic Resonator(使用晶振/陶瓷振荡器)即可,其余默认选项。

时钟树配置见:F767时钟树配置

GPIO引脚配置:

因为我所使用的开发板的LED0LED1分别连接到的是STM32F767芯片的PB1PB0引脚(可查阅对应的原理图得到,不同的板子会使用的不同的引脚),故将PB1PB0引脚设置为Output(输出),且引脚需要直接驱动LED灯,故将其设置为推挽输出,又因为在原理图中可得当知当PB1PB0引脚为低电平时LED灯点亮,所以PB1PB0引脚初始值应该为高电平。总的来说,PB1的设置就是如下表格:(PB1类似)

GPIO output level(初始状态)

High(高电平)

GPIO mode (模式)

Output Push Pull(推挽输出)

GPIO Pull-up/Pull-down(上下拉)

Pull-up

Maximum output speed(输出速度)

Very High

User label(使用标签)

LED1

Timer定时器配置:

使用TIM2定时器,先设置Clock source(时钟源)Internal Clock(内部时钟),然后根据定时器计算公式来计算出所需要调节的分频系数PSC和计数周期ARR,因为我用的是TIM2,可以查询STM32F7的参考手册中的系统和存储器概述中的存储器组织结构中的寄存器边界地址来看到是用的哪条总线上的时钟。

再通过CubeMX时钟树上得到的APB1的时钟频率(公式中的输入时钟)来进行计算,我这里得到的是108Mhz

最后,我们想要的溢出时间为500ms5s),我们就设置分频系数psc499,计数周期arr107999

验证结果:((107999+1*499+1))/108Mhz = 500ms(上述公式的单位为ms

最后别忘记使能定时器中断

USART1串口配置:F767 USART1配置

详细解释见:

在此处还要注意,开发板的USART1串口引脚和CubeMX所自动生成的引脚号是否对应!查阅原理图可得PA8PA9才是对应的USART1,所以要对自动生成的引脚分配进行修改!

将自动生成的PB14PB15改为PA9PA10!

工程设置见:F767工程设置

3.宏定义常用函数以及程序中所使用的变量

#define LED0_ON() HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET)
#define LED0_OFF() HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET)
#define LED0_TOG() HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin)
#define LED1_ON() HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET)
#define LED1_TOG() HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin)     //宏定义打开LED,关闭LED以及切换LED状态的函数                                                                                                               
uint8_t str1[]="------------F767欢迎你!------------\r\n";	       //定义开机字符
uint8_t hh=0,mm=0,ss=0,s05=0;					                   //定义时分秒以及0.5秒报时初始值
uint8_t str_buff[64];						                       //在sprintf()函数中存放转换结果的字符串
uint8_t RX_data[16];						                       //定义接收数据初始值

4.将要用的函数进行封装方便调用

void LED_Check(void)												//LED自检函数
{
	LED0_ON();
	HAL_Delay(500);
	LED0_OFF();
	HAL_Delay(500);
	
	LED1_ON();
	HAL_Delay(500);
	LED1_OFF();
	HAL_Delay(500);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)	//重写0.5秒定时器中断回调函数
{
	LED0_TOG();
	s05++;
	if(s05==2)
	{
		ss++;
		s05=0;
		if(ss==60)
		{
			mm++;
			ss=0;
			if(mm==60)
			{
				hh++;
				mm=0;
			}
		}
	}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART1)
	{
		if(RX_data[0] == 0xBF && RX_data[2] == 0xFB)
		{
			switch(RX_data[1])
			{
				case 0xA1:
					LED1_ON();
					sprintf((char*)str_buff,"%2d:%2d:%2d  LED1 OPEN!\r\n",hh,mm,ss);
				break;
				
				case 0xA2:
					LED1_OFF();
					sprintf((char*)str_buff,"%2d:%2d:%2d  LED1 CLOSE!\r\n",hh,mm,ss);
				break;
				
				default:
					sprintf((char*)str_buff,"%2d:%2d:%2d  这是一个错误命令!\r\n",hh,mm,ss);
				break;
				
			}
			HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000);
			HAL_UART_Receive_IT(&huart1,RX_data,3);
		}		
	}
}

5.编写主函数

int main(void)
{
    LED_Check();                                               //自检LED灯是否正常
    HAL_UART_Transmit(&huart1,str1,sizeof(str1),10000);        //开机后向上位机发送开机字符
    HAL_TIM_Base_Start_IT(&htim2);                             //打开定时器函数           
    HAL_UART_Receive_IT(&huart1,RX_data,3);                    //串口接收函数
}

6.运行结果

Timer+Usart实验现象

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您可以使用STM32定时器来计时,并且在定时器中断中将计时值发送到串口。 以下是一个简单的示例代码: ```c #include "stm32f4xx.h" #include <stdio.h> #define TIMER_FREQ 1000000 // 定时器频率为1MHz #define BAUD_RATE 115200 // 串口波特率为115200bps volatile uint32_t timer_count = 0; // 定时器计数值 // 定时器中断处理函数 void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) // 检查定时器更新中断是否发生 { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除定时器更新中断标志位 timer_count++; // 计数值加1 } } int main(void) { // 初始化系统时钟、GPIO、串口等 // ... // 配置定时器 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能定时器2时钟 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_Period = TIMER_FREQ - 1; // 定时器重载值,计数到1MHz - 1后触发更新中断 TIM_TimeBaseInitStruct.TIM_Prescaler = SystemCoreClock / TIMER_FREQ - 1; // 定时器分频系数,使计数频率为1MHz TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 定时器时钟分频 TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 定时器计数模式为向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); // 配置定时器中断 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); TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除定时器更新中断标志位 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能定时器更新中断 // 启动定时器 TIM_Cmd(TIM2, ENABLE); // 发送计时值到串口 while (1) { if (timer_count > 0) // 如果计数值大于0 { char buf[16]; sprintf(buf, "%lu\r\n", timer_count); // 将计数值转换成字符串 USART_SendString(buf); // 发送字符串到串口 timer_count = 0; // 重置计数值为0 } } } ``` 在上述代码中,我们使用了定时器2来计时,计时频率为1MHz。在定时器中断处理函数中,将计数值加1。在主循环中,如果计数值大于0,则将计数值转换成字符串并发送到串口

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yelens

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

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

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

打赏作者

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

抵扣说明:

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

余额充值