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

二、中断模式(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的进出操作,使数据在很短的时间从设备的代码提取出来,而不影响设备的接收与发送,可以防止数据丢失的发生。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值