从新建工程开始使用C++开发单片机(以STM32为例):五、串口篇(1)UART收发接口(附代码)

一、STM32 串口UART简单介绍:

串口通信应该是单片机应用中用的最多的输出方式,具体的传输协议内容就不进行介绍了,各位大佬应该都会。STM32大容量处理器有5个串口(USART1,USART2,UART3~UART5),对于中容量的处理器有3个串口,小容量的有2个。本文中将会介绍串口的初始化、输出、输入接口以及串口接收缓冲区的管理。目前采用的传输方式为8数据位、1停止位、无校验位、对于USART无硬件流控,以后进行扩展的之后再来更新。
由于STM32不同型号的处理器,串口的数量不同,因此采用宏的方式来确定串口的数量,防止操作处理器不存在的串口而引起错误

#ifdef STM32F10X_HD
#define HAVE_SERIAL1
#define HAVE_SERIAL2
#define HAVE_SERIAL3
#define HAVE_SERIAL4
#define HAVE_SERIAL5
#define HAVE_I2C1
#define HAVE_I2C2
#define HAVE_SPI1
#define HAVE_SPI2
#define HAVE_SPI3
#elif STM32F10X_MD
#define HAVE_SERIAL1
#define HAVE_SERIAL2
#define HAVE_SERIAL3
#define HAVE_I2C1
#define HAVE_I2C2
#define HAVE_SPI1
#define HAVE_SPI2
#elif STM32F10X_LD
#define HAVE_SERIAL1
#define HAVE_SERIAL2
#define HAVE_I2C1
#define HAVE_SPI1
#endif

二、初始化和串口输出接口

请添加图片描述

1.枚举:

/**
* @brief 串口枚举 \n
* UART_1 串口1,以此类推
*/
typedef enum
{
#ifdef HAVE_SERIAL1
  UART_1 = (uint32_t)USART1,
#endif
#ifdef HAVE_SERIAL2
  UART_2 = (uint32_t)USART2,
#endif
#ifdef HAVE_SERIAL3
  UART_3 = (uint32_t)USART3,
#endif
#ifdef HAVE_SERIAL4
  UART_4 = (uint32_t)UART4,
#endif
#ifdef HAVE_SERIAL5
  UART_5 = (uint32_t)UART5,
#endif
  UART_END//占位,没有用
} UART_enum;

2.函数接口
2.1 void uart_init(UART_enum uart, uint32_t baudrate):串口初始化

/*************************************************************************
 * @brief   初始化串口
 * @param[in]	uart 要初始化的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] baudrate 串口通信波特率
 * @return 无
 * @note  该函数默认使用 8N1(8数据位,无校验位,1位停止位)模式,可在 my_uart.h中
 *        对应宏进行修改
 * @example uart_init(UART1, 115200) 初始化 UART1 并使能,波特率为115200
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
void uart_init(UART_enum uart, uint32_t baudrate);

2,2 void uart_write_byte(UART_enum uart, uint8_t data):串口输出一个字节

/*************************************************************************
 * @brief   串口输出一个字节数据
 * @param[in]	uart 要输出字节的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] data 输出的字节数据
 * @return 无
 * @note  调用前应先对串口进行初始化
 * @example uart_write_byte(UART1, 'a') 串口1输出字节数据'a'
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
inline void uart_write_byte(UART_enum uart, uint8_t data);

2.3 void uart_write_buffer(UART_enum uart, const uint8_t *buf, int len) 串口输出二进制数据

/*************************************************************************
 * @brief   串口输出二进制数据(如输出结构体、二进制数据)
 * @param[in]	uart 要输出字节的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] buf 二进制数据指针
 * @param[in] len 二进制数据长度
 * @return 无
 * @note  调用前应先对串口进行初始化,调用时应注意二进制数据长度,不要越界!
 * @example uart_write_buffer(UART1, buf, 10)
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
void uart_write_buffer(UART_enum uart, const uint8_t *buf, int len);

2.4 void uart_write_string(UART_enum uart, const char *str):串口输出C语言字符串

/*************************************************************************
 * @brief   串口输出字符串
 * @param[in]	uart 要输出字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] str 要输出的字符串
 * @return 无
 * @note  调用前应先对串口进行初始化
 * @example uart_write_string(UART_1, "hello world");串口1打印 hello world
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
void uart_write_string(UART_enum uart, const char *str);

三、串口接收、接收中断和缓冲区管理

1 缓冲区结构 : 串口接收缓冲区大小为256个字节,读指针和写指针为uint8_t类型,所以当读写指针移动到缓冲区末尾后就会自动回到缓冲区头部,形成循环队列,如果缓冲区满了,串口接收中断就会忽略新收到的数据,直到将缓冲区的数据读出。每个串口都有一个接收缓冲区,由串口接收中断服务函数进行管理。串口接收的读取接口实际上就是读取缓冲区中的内容,对中断服务函数的进行了屏蔽。

typedef struct
{
    volatile uint8_t buf[256];      //接收缓冲区
    volatile uint8_t write_index;   //写指针
    volatile uint8_t read_index;    //读指针
    volatile uint16_t data_size;    //缓冲区接收到的数据长度
    /* data */
}__rec_buf;

2.串口接收接口
2.1 uint16_t uart_rec_size(UART_enum uart) 获取串口缓冲区接收数据长度

/*************************************************************************
 * @brief   获取串口缓冲区接收数据长度
 * @param[in]	uart 要接收字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @return 串口缓冲区接收到数据的长度
 * @note   串口缓冲区最大为256个字节
 * @history 2021-12-2:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
uint16_t uart_rec_size(UART_enum uart)

2.2 uint8_t uart_read_byte(UART_enum uart) 从串口缓冲区读取一个数据。该函数会读取串口缓冲区的接收长度,如果缓冲区长度为0就会等待直到缓冲区收到数据。读取数据后,会更新长度和读指针。该函数可以配合 uart_rec_size(~)使用, 通过判断缓冲区接收长度,来防止函数阻滞,类似于Windows控制台中的_kbhit()和getch()的配合使用。

/*************************************************************************
 * @brief   从串口缓冲区读取一个数据
 * @param[in]	uart 要接收字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @return 读取到的值
 * @note   该函数为阻滞函数
 * @history 2021-12-2:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
uint8_t uart_read_byte(UART_enum uart)

3.串口接收中断(以串口1为例)
上面已经说过,串口接收中断用于管理串口接收缓冲区,因此在串口初始化后,串口接收完全自动进行,不需要代码进行干预,从而实现了中断函数的屏蔽。对于上层的接口看来,似乎不存在中断函数,串口的读取就是对缓冲区的读取。

#ifdef HAVE_SERIAL1
__rec_buf UART1_recbuf;
void USART1_IRQHandler(void)
{
  if (USART_GetITStatus(USART1, USART_IT_RXNE))
  {
    if (UART1_recbuf.data_size >= 256)
    {
      // uart_write_string(UART_1, "UART1 recbuf fill!\r\n");
      USART_ClearITPendingBit(USART1, USART_IT_RXNE);
      return;
    }
    uint16_t recdata = USART_ReceiveData(USART1);
    UART1_recbuf.buf[UART1_recbuf.write_index++] = (uint8_t)recdata;
    UART1_recbuf.data_size++;
  }
  USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
#endif

附:完整代码

/*file:resources.h*/
#ifndef __RESOURCES_H
#define __RESOURCES_H

#ifdef __cplusplus
 extern "C" {
#endif

#include "stm32f10x.h"	

/**
* @brief GPIO口枚举 \n
* A0:GPIOA,P0口,其他以此类推
*/
typedef enum
{
    A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,
    B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12,B13,B14,B15,
    C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,
    D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,
    E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,E10,E11,E12,E13,E14,E15,
    F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13,F14,F15,
    G0,G1,G2,G3,G4,G5,G6,G7,G8,G9,G10,G11,G12,G13,G14,G15,
    Pin_null
}Pin_enum;


typedef struct
{
    volatile uint8_t buf[256];      //接收缓冲区
    volatile uint8_t write_index;   //写指针
    volatile uint8_t read_index;    //读指针
    volatile uint16_t data_size;    //缓冲区接收到的数据长度
    /* data */
}__rec_buf;

#ifdef STM32F10X_HD
#define HAVE_SERIAL1
#define HAVE_SERIAL2
#define HAVE_SERIAL3
#define HAVE_SERIAL4
#define HAVE_SERIAL5
#define HAVE_I2C1
#define HAVE_I2C2
#define HAVE_SPI1
#define HAVE_SPI2
#define HAVE_SPI3
#elif STM32F10X_MD
#define HAVE_SERIAL1
#define HAVE_SERIAL2
#define HAVE_SERIAL3
#define HAVE_I2C1
#define HAVE_I2C2
#define HAVE_SPI1
#define HAVE_SPI2
#elif STM32F10X_LD
#define HAVE_SERIAL1
#define HAVE_SERIAL2
#define HAVE_I2C1
#define HAVE_SPI1
#endif

#ifdef __cplusplus
 }
#endif

#endif

/*file:my_usart.h*/
/**************************************************************************
 * @brief       : STM32 USART
 * @author      : 龚为玮(1461041096)
 * @copyright   : 版权信息
 * @version     : v1.0
 * @note        : 无
 * @history     : 2021年11月20日:创建文件
 *                2021年11月22日:完成串口初始化功能、串口基础write功能
 *                               并对UART1进行了输出测试,测试通过
 *                2021年11月22日:添加注释
 *                2021年11月23日:对UART2~UART5进行了输出测试,测试通过
 *                2021年12月3日: 完成了串口接收相关接口,对UART1进行了测试
 *                2021年12月13日:发现UART4和UART5无法接收,原因不明
 *                2021年12月14日:解决了13日发现的问题,目前所有串口经过测试输入输
 *                               出可用
 ***************************************************************************/

#ifndef __MY_USART_H
#define __MY_USART_H

#ifdef __cplusplus
 extern "C" {
#endif

#include "stm32f10x_usart.h"
#include "my_afio.h"
#include "my_gpio.h"

/**
* @brief 串口枚举 \n
* UART_1 串口1,以此类推
*/
typedef enum
{
#ifdef HAVE_SERIAL1
  UART_1 = (uint32_t)USART1,
#endif
#ifdef HAVE_SERIAL2
  UART_2 = (uint32_t)USART2,
#endif
#ifdef HAVE_SERIAL3
  UART_3 = (uint32_t)USART3,
#endif
#ifdef HAVE_SERIAL4
  UART_4 = (uint32_t)UART4,
#endif
#ifdef HAVE_SERIAL5
  UART_5 = (uint32_t)UART5,
#endif
  UART_END//占位,没有用
} UART_enum;

#define DEFAULT_UART_WORDLENGTH     USART_WordLength_8b             //默认8位数据位
#define DEFAULT_UART_STOPBITS       USART_StopBits_1                //默认1位停止位
#define DEFAULT_UART_PARITY         USART_Parity_No                 //默认无校验位
#define DEFAULT_UART_FLOWCONTROL    USART_HardwareFlowControl_None  //默认无硬件流控

#ifdef HAVE_SERIAL1
extern __rec_buf UART1_recbuf;
#endif
#ifdef HAVE_SERIAL2
extern __rec_buf UART2_recbuf;
#endif
#ifdef HAVE_SERIAL3
extern __rec_buf UART3_recbuf;
#endif
#ifdef HAVE_SERIAL4
extern __rec_buf UART4_recbuf;
#endif
#ifdef HAVE_SERIAL5
extern __rec_buf UART5_recbuf;
#endif

void uart_init(UART_enum uart, uint32_t baudrate);
void uart_write_byte(UART_enum uart, uint8_t data);
void uart_write_buffer(UART_enum uart, const uint8_t *buf, int len);
void uart_write_string(UART_enum uart, const char *str);

uint16_t uart_rec_size(UART_enum uart);
uint8_t uart_read_byte(UART_enum uart);

#ifdef __cplusplus
 }
#endif

#endif

/*file:my_usart.c*/
/**************************************************************************
 * @brief       : STM32 USART
 * @author      : 龚为玮(1461041096)
 * @copyright   : 版权信息
 * @version     : v1.0
 * @note        : 无
 * @history     : 2021年11月20日:创建文件
 *                2021年11月22日:完成串口初始化功能、串口基础write功能
 *                               并对UART1进行了输出测试,测试通过
 *                2021年11月22日:添加注释
 *                2021年11月23日:对UART2~UART5进行了输出测试,测试通过
 *                2021年12月3日: 完成了串口接收相关接口,对UART1进行了测试
 *                2021年12月13日:发现UART4和UART5无法接收,原因不明
 *                2021年12月14日:解决了13日发现的问题,目前所有串口经过测试输入输
 *                               出可用
 ***************************************************************************/
#include "my_usart.h"
#include "string.h"

/**
 * @brief 串口默认引脚 \n
 *UART1_TX:串口1TX引脚,UART1_RX:串口1RX引脚,以此类推
 */
typedef enum
{
#ifdef HAVE_SERIAL1
  UART1_TX = A9,
  UART1_RX = A10,
#endif
#ifdef HAVE_SERIAL2
  UART2_TX = A2,
  UART2_RX = A3,
#endif
#ifdef HAVE_SERIAL3
  UART3_TX = B10,
  UART3_RX = B11,
#endif
#ifdef HAVE_SERIAL4
  UART4_TX = C10,
  UART4_RX = C11,
#endif
#ifdef HAVE_SERIAL5
  UART5_TX = C12,
  UART5_RX = D2,
#endif
  UARTn_Pin_End //占位,没用
} UART_pin;

/*************************************************************************
 * @brief   初始化串口
 * @param[in]	uart 要初始化的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] baudrate 串口通信波特率
 * @return 无
 * @note  该函数默认使用 8N1(8数据位,无校验位,1位停止位)模式,可在 my_uart.h中
 *        对应宏进行修改
 * @example uart_init(UART1, 115200) 初始化 UART1 并使能,波特率为115200
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
void uart_init(UART_enum uart, uint32_t baudrate)
{
  Pin_enum uart_tx, uart_rx;
  uint8_t USARTx_IRQn;
  switch (uart)
  {
#ifdef HAVE_SERIAL1
  case UART_1:
    uart_tx = (Pin_enum)UART1_TX, uart_rx = (Pin_enum)UART1_RX;
    memset((void *)&UART1_recbuf, 0, sizeof(UART1_recbuf));
    USARTx_IRQn = USART1_IRQn;
    break;
#endif
#ifdef HAVE_SERIAL2
  case UART_2:
    uart_tx = (Pin_enum)UART2_TX, uart_rx = (Pin_enum)UART2_RX;
    memset((void *)&UART2_recbuf, 0, sizeof(UART2_recbuf));
    USARTx_IRQn = USART2_IRQn;
    break;
#endif
#ifdef HAVE_SERIAL3
  case UART_3:
    uart_tx = (Pin_enum)UART3_TX, uart_rx = (Pin_enum)UART3_RX;
    memset((void *)&UART3_recbuf, 0, sizeof(UART3_recbuf));
    USARTx_IRQn = USART3_IRQn;
    break;
#endif
#ifdef HAVE_SERIAL4
  case UART_4:
    uart_tx = (Pin_enum)UART4_TX, uart_rx = (Pin_enum)UART4_RX;
    memset((void *)&UART4_recbuf, 0, sizeof(UART4_recbuf));
    USARTx_IRQn = UART4_IRQn;
    break;
#endif
#ifdef HAVE_SERIAL5
  case UART_5:
    uart_tx = (Pin_enum)UART5_TX, uart_rx = (Pin_enum)UART5_RX;
    memset((void *)&UART5_recbuf, 0, sizeof(UART5_recbuf));
    USARTx_IRQn = UART5_IRQn;
    break;
#endif
  default:
    return;
  }
  //获取UART对应引脚

  gpio_init(uart_rx, INPUT);
  afio_init(uart_tx, OUT_PP_AF);
  //初始化UART RX、TX引脚

  if (uart == UART_1)
  {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  }
  else
  {
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 << (((uint32_t)uart - (uint32_t)UART_2) / 0x0400), ENABLE);
  }
  //使能UART时钟

  USART_InitTypeDef uart_inittype;
  uart_inittype.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;           //开启TX、RX模式
  uart_inittype.USART_BaudRate = baudrate;                            //设置波特率
  uart_inittype.USART_StopBits = DEFAULT_UART_STOPBITS;               //设置停止位
  uart_inittype.USART_Parity = DEFAULT_UART_PARITY;                   //设置校验位
  uart_inittype.USART_WordLength = DEFAULT_UART_WORDLENGTH;           //设置数据位长度
  uart_inittype.USART_HardwareFlowControl = DEFAULT_UART_FLOWCONTROL; //设置硬件流控

  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // IRQ通道使能

  USART_Init((USART_TypeDef *)uart, &uart_inittype);            //初始化UART
  USART_Cmd((USART_TypeDef *)uart, ENABLE);                     //使能UART
  USART_ITConfig((USART_TypeDef *)uart, USART_IT_RXNE, ENABLE); //开启ENABLE/关闭DISABLE中断
  NVIC_Init(&NVIC_InitStructure);                               //根据指定的参数初始化VIC寄存器

  USART_ClearFlag((USART_TypeDef *)uart, USART_FLAG_TC);
  uart_write_byte(uart,0);
}

/*****************************串口输出相关接口*****************************/

/*************************************************************************
 * @brief   串口输出一个字节数据
 * @param[in]	uart 要输出字节的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] data 输出的字节数据
 * @return 无
 * @note  调用前应先对串口进行初始化
 * @example uart_write_byte(UART1, 'a') 串口1输出字节数据'a'
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
inline void uart_write_byte(UART_enum uart, uint8_t data)
{
  USART_SendData((USART_TypeDef *)uart, (uint16_t)data);
  while (USART_GetFlagStatus((USART_TypeDef *)uart, USART_FLAG_TC) == RESET)
    ;
}

/*************************************************************************
 * @brief   串口输出二进制数据(如输出结构体、二进制数据)
 * @param[in]	uart 要输出字节的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] buf 二进制数据指针
 * @param[in] len 二进制数据长度
 * @return 无
 * @note  调用前应先对串口进行初始化,调用时应注意二进制数据长度,不要越界!
 * @example uart_write_buffer(UART1, buf, 10)
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
void uart_write_buffer(UART_enum uart, const uint8_t *buf, int len)
{
  for (int i = 0; i < len; i++)
  {
    uart_write_byte(uart, (uint16_t)buf[i]);
  }
}

/*************************************************************************
 * @brief   串口输出字符串
 * @param[in]	uart 要输出字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @param[in] str 要输出的字符串
 * @return 无
 * @note  调用前应先对串口进行初始化
 * @example uart_write_string(UART_1, "hello world");串口1打印 hello world
 * @history 2021-11-22:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
void uart_write_string(UART_enum uart, const char *str)
{
  int len = strlen(str);
  for (int i = 0; i < len; i++)
  {
    uart_write_byte(uart, (uint16_t)str[i]);
  }
}

/*****************************串口接收相关接口*****************************/

/*************************************************************************
 * @brief   选择串口接收对应的缓冲区
 * @param[in]	uart 要接收字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @return 串口接收缓冲区指针
 * @note  内部调用
 * @history 2021-12-2:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
__rec_buf *select_buf(UART_enum uart)
{
  switch (uart)
  {
#ifdef HAVE_SERIAL1
  case UART_1:
    return &UART1_recbuf;
#endif
#ifdef HAVE_SERIAL2
  case UART_2:
    return &UART2_recbuf;
#endif
#ifdef HAVE_SERIAL3
  case UART_3:
    return &UART3_recbuf;
#endif
#ifdef HAVE_SERIAL4
  case UART_4:
    return &UART4_recbuf;
#endif
#ifdef HAVE_SERIAL5
  case UART_5:
    return &UART5_recbuf;
#endif
  default:
    return 0;
  }
}

/*************************************************************************
 * @brief   获取串口缓冲区接收数据长度
 * @param[in]	uart 要接收字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @return 串口缓冲区接收到数据的长度
 * @note   串口缓冲区最大为256个字节
 * @history 2021-12-2:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
uint16_t uart_rec_size(UART_enum uart)
{
  __rec_buf *uart_recbuf = select_buf(uart);
  return uart_recbuf->data_size;
}

/*************************************************************************
 * @brief   从串口缓冲区读取一个数据
 * @param[in]	uart 要接收字符串的串口 (可选择的值在 my_uart.h UART_enum枚举中)
 *            此参数可以是以下值之一:
 *              UART1 UART2 UART3 UART4 UART5
 * @return 读取到的值
 * @note   该函数为阻滞函数
 * @history 2021-12-2:创建,完成功能并使用 USART1 进行测试,测试通过
 ************************************************************************/
uint8_t uart_read_byte(UART_enum uart)
{
  __rec_buf *uart_recbuf = select_buf(uart);
  while (uart_recbuf->data_size == 0) //等待串口缓冲区接收到数据
    ;
  uint8_t res = uart_recbuf->buf[uart_recbuf->read_index++];
  uart_recbuf->data_size--;
  return res;
}

/***********************串口接收中断***************************************/
#ifdef HAVE_SERIAL1
__rec_buf UART1_recbuf;
void USART1_IRQHandler(void)
{
  if (USART_GetITStatus(USART1, USART_IT_RXNE))
  {
    if (UART1_recbuf.data_size >= 256)
    {
      // uart_write_string(UART_1, "UART1 recbuf fill!\r\n");
      USART_ClearITPendingBit(USART1, USART_IT_RXNE);
      return;
    }
    uint16_t recdata = USART_ReceiveData(USART1);
    UART1_recbuf.buf[UART1_recbuf.write_index++] = (uint8_t)recdata;
    UART1_recbuf.data_size++;
  }
  USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
#endif

#ifdef HAVE_SERIAL2
__rec_buf UART2_recbuf;
void USART2_IRQHandler(void)
{
  if (USART_GetITStatus(USART2, USART_IT_RXNE))
  {
    uint16_t recdata = USART_ReceiveData(USART2);
    if (UART2_recbuf.data_size >= 256)
    {
      // uart_write_string(UART_2, "UART2 recbuf fill!\r\n");
      USART_ClearITPendingBit(USART2, USART_IT_RXNE);
      return;
    }
    UART2_recbuf.buf[UART2_recbuf.write_index++] = (uint8_t)recdata;
    UART2_recbuf.data_size++;
  }
  USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
#endif

#ifdef HAVE_SERIAL3
__rec_buf UART3_recbuf;
void USART3_IRQHandler(void)
{
  if (USART_GetITStatus(USART3, USART_IT_RXNE))
  {
    uint16_t recdata = USART_ReceiveData(USART3);
    if (UART3_recbuf.data_size >= 256)
    {
      // uart_write_string(UART_3, "UART3 recbuf fill!\r\n");
      USART_ClearITPendingBit(USART3, USART_IT_RXNE);
      return;
    }
    UART3_recbuf.buf[UART3_recbuf.write_index++] = (uint8_t)recdata;
    UART3_recbuf.data_size++;
  }
  USART_ClearITPendingBit(USART3, USART_IT_RXNE);
}
#endif

#ifdef HAVE_SERIAL4
__rec_buf UART4_recbuf;
void UART4_IRQHandler(void)
{
  if (USART_GetITStatus(UART4, USART_IT_RXNE))
  {
    uint16_t recdata = USART_ReceiveData(UART4);
    if (UART4_recbuf.data_size >= 256)
    {
      // uart_write_string(UART_4, "UART1 recbuf fill!\r\n");
      USART_ClearITPendingBit(UART4, USART_IT_RXNE);
      return;
    }
    UART4_recbuf.buf[UART4_recbuf.write_index++] = (uint8_t)recdata;
    UART4_recbuf.data_size++;
  }
  USART_ClearITPendingBit(UART4, USART_IT_RXNE);
}
#endif

#ifdef HAVE_SERIAL5
__rec_buf UART5_recbuf;
void UART5_IRQHandler(void)
{
  if (USART_GetITStatus(UART5, USART_IT_RXNE))
  {
    uint16_t recdata = USART_ReceiveData(UART5);
    if (UART5_recbuf.data_size >= 256)
    {
      // uart_write_string(UART_5, "UART1 recbuf fill!\r\n");
      USART_ClearITPendingBit(UART5, USART_IT_RXNE);
      return;
    }
    UART5_recbuf.buf[UART5_recbuf.write_index++] = (uint8_t)recdata;
    UART5_recbuf.data_size++;
  }
  USART_ClearITPendingBit(UART5, USART_IT_RXNE);
}
#endif

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值