STMF407串口通信流水灯
STM32F407实现串口控制流水灯
本次实现用到正点原子的STM32F407ZGT6(根据自己板子调整),通过STM32CubeMx+Keil5进行实现,实现效果是通过串口控制向左流水灯,向右流水灯,熄灭,过程代码如果有错误地方恳请各位大佬指正。
STM32CubeMx配置界面
首先是初始界面

双击进入配置界面

配置引脚
将LED初始电平设置为高电平,这里选用了四个灯PA1,PA2,PA3,PA4,PF9和PF10两个灯用于判断程序中问题


配置RCC时钟
我们使用的是外部高速晶振

配置SYS

配置串口和定时器,我这里使用的是串口1定时器6,串口1引脚PA9,PA10,可以根据情况自己修改
配置串口1异步通信,开启中断

配置定时器6,开启中断

配置MCU时钟树
根据以下图片修改

选择代码保存路径
以下分别对应路径名称,存储位置,需要注意的是最好为英文,否则会出现一些奇奇怪怪的问题,可以根据自己路径进行修改

代码生成,这里就完成了,点击生成文件

接下来就是Keil5实现
主要文件

这里需要注意的是选择魔法棒,勾选Mircro,不然无法进行printf打印

上代码,代码有注释
代码如下:
**main.c main函数代码,只修改了main函数**
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6);//定时器6中断启用
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
HAL_UART_Receive_IT(&huart1,(uint8_t *)RxBuff,1);//启动UART接收中断
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
usart.c
#include "usart.h"
#include "stdio.h"
#include "string.h"
/* USER CODE BEGIN 0 */
int fputc(int ch,FILE *f)//重新定义标准输出,串口1输出
{
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,0xffff);
return ch;
}
uint8_t RxBuff[1];//缓存数组每次保留一位字符
uint8_t RxBuffer[7];//实际存储数组
uint8_t c=0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//回调函数,数据接收成功进行回调
{
if(huart ->Instance == USART1)//寄存器地址是否是USART1
{
RxBuffer[c++]=RxBuff[0];
if(RxBuff[0] == '#')//数据停止位,可以自己根据情况自行修改
{
printf("count == %d \r\n",c);//打印长度
printf("RxBuff5 == %d \r\n",RxBuffer[5]);//存储进实际数组
if(RxBuffer[5]<=51)//ASCLL码 49对应1,50对应2,51对应3
{
LED_Control(RxBuffer[5]);//LED流水灯函数三种模式
}
c=0;
memset(RxBuffer,0,sizeof(RxBuffer));//防止溢出
}
}
HAL_UART_Receive_IT(&huart1,(uint8_t *)RxBuff,1);//数据回调
}
/* USER CODE END 0 */
UART_HandleTypeDef huart1;
/* USART1 init function */
void MX_USART1_UART_Init(void)//串口初始化函数
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */
/* USER CODE END USART1_MspInit 0 */
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspDeInit 0 */
/* USER CODE END USART1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
/* USART1 interrupt Deinit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
usart.h
#ifndef __USART_H__
#define __USART_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN Private defines */
extern uint8_t RxBuff[1];
extern uint8_t RxBuffer[7];
/* USER CODE END Private defines */
void MX_USART1_UART_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */
LED.c
#include "LED.h"
#include "gpio.h"
#include "usart.h"
int Cnt_to_300ms=0;//0.3秒切换一次
unsigned char a=0,b=0;
uint16_t led_pin[] = {GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3, GPIO_PIN_4};//gpio流水灯存储数组
void LED_Control(int k)//LED判断
{
switch (k)
{
case 49:
a=1;
break;
case 50:
a=2;
break;
case 51:
a=3;
break;
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器中断回调
{
if(htim->Instance == TIM6)
{
Cnt_to_300ms++;
if(Cnt_to_300ms >= 30)//当大于0.3s
{
Cnt_to_300ms=0;//清零不断循环
switch(a)
{
case 1:
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,1);//熄灭
if(b>=3){b=0;}else{b++;}//向右流水灯
HAL_GPIO_WritePin(GPIOA,led_pin[b],0);//点亮
break;
case 2:
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,1);//熄灭
if(b<=0){b=3;}else{b--;}//向左流水灯
HAL_GPIO_WritePin(GPIOA,led_pin[b],0);//点亮
break;
case 3:
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,1);//熄灭
break;
}
}
}
UNUSED(htim);
}
LED.h
#ifndef __LED_H
#define __LED_H
void LED_Control(int k);
#endif
如果感兴趣的话可以进stm32f4xx_it,stm32f4xx_hal_usart库看看。
效果展示
串口调试助手效果:

STM32F407ZGT6效果:

介绍
1. 系统初始化层
HAL_Init():初始化 HAL 库,配置系统时钟树、中断优先级等底层资源。
SystemClock_Config():配置主频(如 72MHz,需在 system_stm32xx.c 中实现)。
2. 外设初始化层
MX_GPIO_Init():
配置 LED 引脚(PA1-PA4)为推挽输出。
配置 USART1 引脚(PA9-TX, PA10-RX)为复用功能。
MX_USART1_UART_Init():
设置波特率 115200,8 位数据位,1 停止位,无校验。
使能 USART1 全局中断(NVIC)。
MX_TIM6_Init():
配置 TIM6 为 1kHz 中断。
3. 中断启动层
HAL_TIM_Base_Start_IT(&htim6):
启动 TIM6 定时器,使能更新中断。
每 1ms 触发一次中断(用于 LED 流水灯周期控制)。
4. 主循环层
HAL_UART_Receive_IT(&huart1, RxBuff, 1):
非阻塞接收:启动 UART 接收中断,接收 1 字节到 RxBuff。
自动重入:每次接收完成后,回调函数中会再次调用此函数,实现持续监听。
代码执行流程
初始化阶段:
配置系统时钟、GPIO、USART1、TIM6。
启动 TIM6 中断(1kHz 定时)。
主循环阶段:
持续启动 UART 接收中断,等待数据到达。
中断触发场景:
UART 接收中断:接收到 1 字节时触发,数据存入 RxBuff。
TIM6 更新中断:每 1ms 触发一次,用于 LED 流水灯控制。
关键交互逻辑
- UART 数据接收流程
调用 HAL_UART_Receive_IT 启动接收。
接收完成时,触发 USART1_IRQHandler,执行 HAL_UART_IRQHandler。
调用用户回调函数 HAL_UART_RxCpltCallback:
将数据存入 RxBuffer。
遇到结束符 # 时:
打印接收数据长度和第 6 字节值。
根据 ASCII 码(49='1', 50='2', 51='3')调用 LED_Control 设置模式。
重置计数器 c 并清空缓冲区。
重新调用 HAL_UART_Receive_IT 等待下一字节。 - LED 流水灯控制
TIM6 定时中断:
每 1ms 触发一次,累计 300 次(300ms)后切换 LED 状态。
模式切换:
模式 1:向右流水(PA1→PA2→PA3→PA4)。
模式 2:向左流水(PA4→PA3→PA2→PA1)。
模式 3:熄灭所有 LED。**
源码地址
百度网盘:STM32F407ZGT6串口通信
链接: https://pan.baidu.com/s/1MUFlYV4Yx_fGOLjA_-d4UA?pwd=1111 提取码: 1111

浙公网安备 33010602011771号