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 流水灯控制。
关键交互逻辑

  1. 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 等待下一字节。
  2. 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

posted @ 2025-05-27 13:02  少年执笔  阅读(32)  评论(0)    收藏  举报