首先 打开cube 选择芯片 略。。。

以F1系列为例

CubeMX没选Debug_串口

SYSTEM CORE选择外部高速晶振↓

CubeMX没选Debug_嵌入式硬件_02

CubeMX没选Debug_串口_03

dubug选择        SW↑

CubeMX没选Debug_串口_04

时钟树配好↑

CubeMX没选Debug_单片机_05

选择一个串口打开 ↑,参数不用管 波特率115200就行↓

CubeMX没选Debug_数据_06

把中断打开,功能少的话 优先级不用管 0 0就行↓

CubeMX没选Debug_CubeMX没选Debug_07

项目名称 路径 ide version选好↓

CubeMX没选Debug_串口_08

CubeMX没选Debug_单片机_09

直接生成代码就可以了

USART.C(修改后)

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
#include <string.h>//调用了 size of 和 memset 
uint8_t RecieveBuffer[1] = {0}; // U3接收数据缓冲区 
char RXBuffer[256]; // 串口数据暂时储存区
uint8_t USART_RX_LEN = 0; // 用于存储每个USART接收数据的长度 

//重定义printf
#include <stdio.h>
 
 #ifdef __GNUC__
     #define PUTCHAR_PROTOTYPE int _io_putchar(int ch)
 #else
     #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
 #endif /* __GNUC__*/
 
 /******************************************************************
     *@brief  Retargets the C library printf  function to the USART.
     *@param  None
     *@retval None
 ******************************************************************/
 PUTCHAR_PROTOTYPE
 {
     HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1,0xFFFF);
     return ch;
 }

/* 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 */
   HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);//U1开启接收中断 
  /* 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_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    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 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//阻塞接收 循环callback 主函数
{	
	    RXBuffer[USART_RX_LEN++] = RecieveBuffer[0]; // 接收数据转存
        if(RXBuffer[USART_RX_LEN-1] == 0x0A && RXBuffer[USART_RX_LEN-2]  == 0x0D )
        {
		   printf("test\r\n");
					
			 USART_RX_LEN = 0;//LEN重新置零
			 memset(RXBuffer,0x00,sizeof(RXBuffer));//清空buffer
		 }
		 HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);//调用回调函数之后,重新开启U1接收中断等待下一次接收		 	
}
 
/* USER CODE END 1 */

其中有几处是需要自行添加的

首先

/* USER CODE BEGIN 0 */
 #include <string.h>//调用了 size of 和 memset 
 uint8_t RecieveBuffer[1] = {0}; // U3接收数据缓冲区 
 char RXBuffer[256]; // 串口数据暂时储存区
 uint8_t USART_RX_LEN = 0; // 用于存储每个USART接收数据的长度 //重定义printf
 #include <stdio.h>
  
  #ifdef __GNUC__
      #define PUTCHAR_PROTOTYPE int _io_putchar(int ch)
  #else
      #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  #endif /* __GNUC__*/
  
  /******************************************************************
      *@brief  Retargets the C library printf  function to the USART.
      *@param  None
      *@retval None
  ******************************************************************/
  PUTCHAR_PROTOTYPE
  {
      HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1,0xFFFF);
      return ch;
  }/* USER CODE END 0 */

上述部分可以分为三部分 

1. include string 方便调用 memset和sizeof

2.定义了缓冲区以及长度标志

3.重定义printf使得串口发送可以直接用printf代替HAL_Transmit。。。。。

其次

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 */
    HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);//U1开启接收中断 
   /* USER CODE END USART1_Init 2 */}


 

这一部分重点在于开启接收中断,也是唯一需要自行添加的代码 (倒数第三行)

 HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);//U1开启接收中断 

Mspinit里边的东西看看就行(包括NVIC,GPIO时钟),之前在cubemx已经配置过了,不用管。

最后,重新定义一下 HAL_UART_RxCpltCallback

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//阻塞接收 循环callback 主函数
 {    
         RXBuffer[USART_RX_LEN++] = RecieveBuffer[0]; // 接收数据转存
         if(RXBuffer[USART_RX_LEN-1] == 0x0A && RXBuffer[USART_RX_LEN-2]  == 0x0D )//判断结束位
         {
            printf("test\r\n");
                     
              USART_RX_LEN = 0;//LEN重新置零
              memset(RXBuffer,0x00,sizeof(RXBuffer));//清空buffer
          }
          HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);//调用回调函数之后,重新开启U1接收中断等待下一次接收             
 }
  
 /* USER CODE END 1 */

这里边比较重要的是

1.接收数据的转存。

RXBuffer[USART_RX_LEN++] = RecieveBuffer[0]; // 接收数据转存到RXBuffer

2.串口数据可以有个结束位,一般以\r\n结尾,即0x0D,0x0A,

if(RXBuffer[USART_RX_LEN-1] == 0x0A && RXBuffer[USART_RX_LEN-2]  == 0x0D )

3.判断收到结束位之后,就可以执行相应的功能,比如说RXBuffer内的数据处理,如SPI发送RXBuffer内的数据,或者执行其他功能如ADC,GPIO iic发送数据之类的。本代码以printf打印数据为例。 

4.最后一定要把RXBuffer清零,RX LEN重新置零,然后再一次开启接收中断,方便下一次接收。

 

 

之后把代码烧录到单片机中,在单片机串口接收到数据的时候会自动从while循环中跳入串口中断,执行callback函数内的相应功能。