stm32cubemx 串口(详细)
完整的工程已上传到码云:
gitee(码云)
一、软件配置
1、将串口1配置为异步模式,并使能中断。
2、USART1配置窗口介绍
Mode | 描述 | 硬件引脚 | 支持外设 |
---|
Asynchronous | 异步模式 | TXD、RXD | USART、UART | Synchronous | 同步模式 | TXD、RXD、CK | USART | Single Wire (Half-Duplex) | 半双工单线模式 | TXD | USART、UART | Multiprocessor Communication | 多处理器通讯模式 | TXD、RXD | USART、UART | IrDA | 红外解码通信 | TXD、RXD | USART、UART | LIN | 总线通信 | TXD、RXD | USART、UART | SmartCard | 智能卡模式 | TXD | USART、UART | SmartCard with Card Clock | 带时钟智能卡模式 | TXD、CK | USART |
其中UART(Universal Asynchronous Receiver/Transmitter)为通用异步收发器
USART:(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收/发送器USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备。
二、HAL库串口相关的函数
串口的发送和接收函数:
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
函数相关的参数具体的意思在函数原型中有官方的注释,这里简单的介绍一下:
huart: 这个参数用来选择具体要使用的串口
pData: 这个参数是要发送的数据或是接受数据缓存区
size: 发送\接受数据的长度
Timeout: 设置发送\接收超时的时间
串口相关的回调函数:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
若要使用回调函数,需要自己重写,不会自动生成。
以上的函数都在官方库stm32f4xx_hal_uart.c里面。
三、重定向printf
在cubemx生成的代码usrat.c中加入如下函数,并包含头文件stdio.h就可实现printf的使用。
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
四、串口中断回调函数的使用
在上面说到,要使用回调函数需要我们自己重写,因此,我们在usrat.c中重写串口接收中断回调函数,函数中的参数uart1_txbuf是接收缓存区,接受到的数据将保存在这个数组中,大小自己定义,是全局变量。usart2_rxbuf一样。函数如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
HAL_UART_Transmit(&huart1, uart1_rxbuf, 10, 100);
HAL_UART_Receive_IT(&huart1, uart1_rxbuf, 10);
}
else if(huart->Instance == USART2)
{
HAL_UART_Transmit(&huart2, uart2_rxbuf, 10, 100);
HAL_UART_Receive_IT(&huart2, uart2_rxbuf, 10);
}
}
回调函数中,将接受到的数据打印出来。
由于所有串口共用一个中断回调函数,因此在回调函数判断具体是那个串口使用的回调函数,再执行其相应的代码。
在能正常使用之前,需要在串口初始化函数中加入HAL_UART_Receive_IT(&huart2, uart2_rxbuf, 10);
注意: HAL_UART_Receive_IT(&huart2, uart2_rxbuf, 10); 这个函数后的10,的意思是,当给对应的串口发送满10个字符时,才会进入一次这个回调函数。如果你改写成其他的,就是发送满你改的数量的字符才会进入该函数。
在主函数中可以将接收缓存区(usart1_printf)打印出来。
主函数如下:
在这里还要对keil5 进行一下设置,打开Use MicroLIB,不然程序会卡死。具体如下:
当串口助手发送“12345”,字符串不满足10个,将不会进入到回调函数中,主函数将打印接受接受缓存区中数据“12345”.
当我们再发送”789“时,数据会继续往接受缓存区中保存,在主函数中将缓存区的数据打印出来,“123456789”。
此时,字符总书含没有满足我们所设定的10个,因此还不会进入回调函数总,我们再发送一个字符"a",将进入回调函数,回调函数将被执行,回调函数中将输出缓存区的数据,即再串口助手中一行将输出俩次缓存区的数据,一次主函数,一次回调函数。
之后继续给串口一发送数据,数据会依次覆盖缓存区的数据,直到第10个,再进入回调函数。
五、多个串口同时使用printf
先对TXBUF_SIZE_MAX进行宏定义,这个是发送最大字符串长度的定义,可以定义位100。
之后再uart.c中加入如下代码,就可实现串口1,2的类似printf的效果,只是函数是uart1_printf和uart2_printf这个函数的名字可以自己定义,也可以继续添加。还需要加入头文件“stdarg.h”和“string.h”
void uart1_printf(const char *format, ...)
{
va_list args;
uint32_t length;
uint8_t txbuf[TXBUF_SIZE_MAX] = {0};
va_start(args, format);
length = vsnprintf((char *)txbuf, sizeof(txbuf), (char *)format, args);
va_end(args);
HAL_UART_Transmit(&huart1, (uint8_t *)txbuf, length, HAL_MAX_DELAY);
memset(txbuf, 0, TXBUF_SIZE_MAX);
}
void uart2_printf(const char *format, ...)
{
va_list args;
uint32_t length;
uint8_t txbuf[TXBUF_SIZE_MAX] = {0};
va_start(args, format);
length = vsnprintf((char *)txbuf, sizeof(txbuf), (char *)format, args);
va_end(args);
HAL_UART_Transmit(&huart2, (uint8_t *)txbuf, length, HAL_MAX_DELAY);
memset(txbuf, 0, TXBUF_SIZE_MAX);
}
|