STM32HAL库UART的使用

编程

初始化

首先讲下UART的初始化

1.声明UART的初始化结构体,并赋值

2.MX生成的代码会调用HAL_UART_MspInit();来初始化UART,当然这个代码也是自动生成,不过用户可以在这个函数里面添加自己想要添加的操作,时面包括了NVIC_Configuration,DMA_Configuration等,也可以添加一些置位操作如__HAL_UART_ENABLE,__HAL_UART_ENABLE_IT等等

3.在HAL_UART_MspDeInit()中添加一些与HAL_UART_MspInit相反的操作来完成UART的重置操作

对于以上的初始化操作,都可以由stm32cubemx自动生成,无需去具体配置寄存器。

而用户使用HAL库来驱动UART,在初始化好参数之后,

官方提供了三种方式

一、轮询模式(Polling mode IO operation)

使用HAL_UART_Transmit()与HAL_UART_Receive()来配合超时操作来发送与接收数据

以ECHO方式(即收到什么发什么)为例,这种方式进行操作

用轮询方式的代码是比较简短的

      if(HAL_UART_Receive(&huart1, testReceiveData, 10, 1000) == HAL_OK)

{

HAL_UART_Transmit(&huart1, testReceiveData, 10, 1000);

}

以这种方式就可以实现发送接收的数据,不过这种方式来处理的话,长度不定的时候,数据的丢失量会比较大

减少等待超时,与调整BUFFER的长度都还是会有不同程度的数据丢失

如果将BUFFER的长度调整为1,数据丢失量会减少,不过这个时候会出现UART工作一段时间之后就发生异常,因为UART发生ORE错误置位,需要将这个错误置位清除掉才可以再正常接收

代码如下

      if(HAL_UART_Receive(&huart1, testReceiveData, 1, 10) == HAL_OK)

{

HAL_UART_Transmit(&huart1, testReceiveData, 1, 10);

}

else

{

__HAL_UART_CLEAR_OREFLAG(&huart1);

}

如果将发送改为由寄存器直接操作的话

      if(HAL_UART_Receive(&huart1, testReceiveData, 1, 10) == HAL_OK)

{

huart1.Instance->DR = testReceiveData[0];

}

else

{

__HAL_UART_CLEAR_OREFLAG(&huart1);

}

这样测试过来数据就没有丢失。

说明还是在发送API的时候,同时又接收到数据导致的数据丢失,或者说API发送使用时间相对于直接操作寄存器还是要长很多

二、中断模式(Interrupt mode IO operation)

使用HAL_UART_Transmit_IT()与HAL_UART_Receive_IT来发送接收,在发送或接收完之后,再进行函数回调HAL_UART_TxCpltCallback与HAL_UART_RxCpltCallback来进行处理这两个函数都是由用户重新定义的,来实现用户自己的操作

在系统初始化后,直接调用HAL_UART_Receive_IT(&huart1, testReceiveData, 1);即可这个长度可由用户自己定义

当达到接收长度之后,就可以进行cplt完成函数的重构及回调

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)

{

if(uartHandle->Instance == USART1)

{

uartHandle->Instance->DR = testReceiveData[0];

//HAL_UART_Transmit_IT(uartHandle, testReceiveData, 1);

HAL_UART_Receive_IT(uartHandle, testReceiveData, 1);

}

}

使用寄存器直接操作的方式是可以做到数据不丢失,而使用发送函数还是会出现不同程序的数据丢失

数据接收完之后,若要重新开始接收必须重新开启HAL_UART_Receive_IT

三、DMA模式(DMA mode IO operation)

使用HAL_UART_Transmit_DMA()与HAL_UART_Receive_DMA()来发送接收,在发送或接收完之后,也使用HAL_UART_TxCpltCallback与HAL_UART_RxCpltCallback来完成实际操作,同时接收到一半的时候,也可以调用相应的HAL_UART_TxHalfCpltCallback与HAL_UART_RxHalfCpltCallback,如果需要用到这个操作的情况下可以添加自己的操作,当然来还用到一关于DMA的API函数,如HAL_UART_DMAPause,HAL_UART_DMAResume, HAL_UART_DMAStop等

在初始化UART的同时需要初始化相应的DMA,并将DMA与UART进行关联,不过这部分代码都可以自动生成

开始时调用HAL_UART_Receive_DMA(&huart1, uartDeviceRxBuf, UART_BUF_LEN);

在接收到的相应长度的数据之后DMA会产生一个完成的中断,其回调函数与中断模式相同,虽然两者发生中断地方不一致,但是操作是同一个

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)

{

if(uartHandle->Instance == USART1)

{

HAL_UART_Transmit(uartHandle, uartDeviceRxBuf, 100, 1000);

HAL_UART_Receive_DMA(uartHandle, uartDeviceRxBuf, 100);

}

}

同样在接收完成后,要重新开启接收,不然之后的数据就接收不到了

其他

除了上述官方的方式,当然还有一些别的方式,直接操作寄存器肯定也是可以的,而用HAL库时面也有一定宏定义可以直接来操作寄存器

      __HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_RXNE);

__HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE);

可以使用这些定义来直接操作寄存器,初化接收中断

在中断中也直接操作寄存器来完成接收

/* USER CODE BEGIN USART1_IRQn 0 */

if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)

{

uint8_t tmp;

__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);

tmp = huart1.Instance->DR;

huart1.Instance->DR = tmp;

}

/* USER CODE END USART1_IRQn 0 */

//HAL_UART_IRQHandler(&huart1);

中断中如此操作来完成ECHO操作

对于官方提供的操作方式,无论是哪种方式基本上是不能同时使用Transmit与Receive操作,而且官方提供的这些API,很好用,但是用到实际的应用中,还需要用户写一部分代码来完成整个操作,主要就是一个BUFFER的进出操作,使数据在很短的时间从设备的代码提取出来,而不影响设备的接收与发送,可以防止数据丢失的发生。

原文链接:https://www.cnblogs.com/stupidpeng/archive/2020/06/22/13169422.html

以上是 STM32HAL库UART的使用 的全部内容, 来源链接: utcz.com/z/517753.html

回到顶部