stm32cubemx 串口(详细)

完整的工程已上传到码云:

gitee(码云)

一、软件配置

1、将串口1配置为异步模式,并使能中断。

在这里插入图片描述

2、USART1配置窗口介绍

在这里插入图片描述

Mode描述硬件引脚支持外设
Asynchronous异步模式TXD、RXDUSART、UART
Synchronous同步模式TXD、RXD、CKUSART
Single Wire (Half-Duplex)半双工单线模式TXDUSART、UART
Multiprocessor Communication多处理器通讯模式TXD、RXDUSART、UART
IrDA红外解码通信TXD、RXDUSART、UART
LIN总线通信TXD、RXDUSART、UART
SmartCard智能卡模式TXDUSART、UART
SmartCard with Card Clock带时钟智能卡模式TXD、CKUSART

其中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);

//串口DMA模式发送
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

//串口DMA模式接收
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

/**
  * @param  huart Pointer to a UART_HandleTypeDef structure that contains
  *               the configuration information for the specified UART module.
  * @param  pData Pointer to data buffer (u8 or u16 data elements).
  * @param  Size  Amount of data elements (u8 or u16) to be received.
  * @param  Timeout Timeout duration
  * @retval HAL status
  */

函数相关的参数具体的意思在函数原型中有官方的注释,这里简单的介绍一下:

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的使用。

/**
  * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
 
/**
  * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
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);
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐