串口通信应该是单片机应用中用的最多的输出方式,具体的传输协议内容就不进行介绍了,各位大佬应该都会。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



