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

  • 相关阅读:
    在线api文档
    Android Studio 快捷键
    AtomicBoolean运用
    ubuntu下Pycharm安装及配置
    Pycharm Professional Edition 激活码(license)
    opengl中对glOrtho()函数的理解
    附加作业
    个人最终总结
    mysql
    创建数据库
  • 原文地址:https://www.cnblogs.com/stupidpeng/p/13169422.html
Copyright © 2020-2023  润新知