栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

从新建工程开始使用C++开发单片机(以STM32为例):五、C语言接口层之串口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.枚举:

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):串口初始化

void uart_init(UART_enum uart, uint32_t baudrate);

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

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) 串口输出二进制数据

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语言字符串

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;    //缓冲区接收到的数据长度
    
}__rec_buf;

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

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()的配合使用。

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!rn");
      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
附:完整代码
#ifndef __RESOURCES_H
#define __RESOURCES_H

#ifdef __cplusplus
 extern "C" {
#endif

#include "stm32f10x.h"	


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;    //缓冲区接收到的数据长度
    
}__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



#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"


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


#include "my_usart.h"
#include "string.h"


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;


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);
}




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)
    ;
}


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]);
  }
}


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]);
  }
}




__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;
  }
}


uint16_t uart_rec_size(UART_enum uart)
{
  __rec_buf *uart_recbuf = select_buf(uart);
  return uart_recbuf->data_size;
}


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!rn");
      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!rn");
      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!rn");
      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!rn");
      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!rn");
      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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/690695.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号