hal库 uart

基本概念:
同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。
同步是阻塞模式,异步是非阻塞模式。
UART是异步全双工。

实际看代码是会发现,UART的收发寄存器是同一个名字DR,这样看UART似乎是半双工的,但实际上收发是使用不同的寄存器,但是我们使用的是同一个名字。所以它是异步全双工的。

UART是如何初始化的

 515 typedef struct                                                                                                                                                                                          516 {                                                                                                                                 517   __IO uint32_t SR;         /*!< USART Status register,                   Address offset: 0x00 */   518   __IO uint32_t DR;         /*!< USART Data register,                     Address offset: 0x04 */   519   __IO uint32_t BRR;        /*!< USART Baud rate register,                Address offset: 0x08 */   520   __IO uint32_t CR1;        /*!< USART Control register 1,                Address offset: 0x0C */   521   __IO uint32_t CR2;        /*!< USART Control register 2,                Address offset: 0x10 */   522   __IO uint32_t CR3;        /*!< USART Control register 3,                Address offset: 0x14 */   523   __IO uint32_t GTPR;       /*!< USART Guard time and prescaler register, Address offset: 0x18 */   524 } USART_TypeDef;  

可以看到的是hal库根据寄存器手册的UART的寄存器,将UART定义成了,相应的结构体。然后将对应的地址指针,按照结构体类型进行强制转换,这样就可以使用这个结构体来操作对应的寄存器了。

  988 #define USART2              ((USART_TypeDef *) USART2_BASE)                                         989 #define USART3              ((USART_TypeDef *) USART3_BASE)  

可以看到,对应的寄存器的地址

  870 #define USART2_BASE           (APB1PERIPH_BASE + 0x4400U)                                                                                                                                              871 #define USART3_BASE           (APB1PERIPH_BASE + 0x4800U) 

最后将这个结构体,赋值实例化,就可以了。

158 typedef struct
159 {
160   USART_TypeDef                 *Instance;        /*!< UART registers base address        */
161
162   UART_InitTypeDef              Init;             /*!< UART communication parameters      */
163
164   uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
165
166   uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
167
168   __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */
169
170   uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
171
172   uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
173
174   __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */
175
176   DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */
177
178   DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
179
180   HAL_LockTypeDef               Lock;             /*!< Locking object                     */
181
182   __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management
183                                                        and also related to Tx operations.
184                                                        This parameter can be a value of @ref HAL_UART_StateTypeDef */
185
186   __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations.
187                                                        This parameter can be a value of @ref HAL_UART_StateTypeDef */
188
189   __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
190
191 }UART_HandleTypeDef;

简单看一下这个重要结构体的成员:
instance:这个是最重要的,拿到的是,UART外设的寄存器的地址。
init:这个记录的是用户初始化串口的配置信息,初始化就是通过将init里面的配置信息,来配置instance里面的寄存器
pTxBuffPtr:这类似的几个结构体就是用作临时存放用户传进来的信息的。
Lock:上锁的标志位,这里根本没有上锁的这个寄存器,只是使用一个全局变量,来进行互斥使用的。

阻塞发送(非中断方式)

607 /**                                                                                                 608   * @brief  Sends an amount of data in blocking mode.                                                                                                                                                   609   * @param  huart pointer to a UART_HandleTypeDef structure that contains                           610   *                the configuration information for the specified UART module.                     611   * @param  pData Pointer to data buffer                                                            612   * @param  Size Amount of data to be sent                                                          613   * @param  Timeout Timeout duration                                                                614   * @retval HAL status                                                                              615   */                                                                                                616 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)617 {                                                                                                   618   uint16_t* tmp;                                                                                    619   uint32_t tickstart = 0U;                                                                          620                                                                                                     621   /* Check that a Tx process is not already ongoing */                                              622   if(huart->gState == HAL_UART_STATE_READY)                                                         623   {                                                                                                 624     if((pData == NULL ) || (Size == 0))                                                             625     {                                                                                               626       return  HAL_ERROR;                                                                            627     }                                                                                               628                                                                                                     629     /* Process Locked */                                                                            630     __HAL_LOCK(huart);                                                                              631                                                                                                     632     huart->ErrorCode = HAL_UART_ERROR_NONE;                                                         633     huart->gState = HAL_UART_STATE_BUSY_TX;                                                         634                                                                                                     635     /* Init tickstart for timeout managment */                                                      636     tickstart = HAL_GetTick();                                                                      637                                                                                                     638     huart->TxXferSize = Size;                                                                       639     huart->TxXferCount = Size;                                                                      640     while(huart->TxXferCount > 0U)                                                                  641     {                                                                                               642       huart->TxXferCount--;                                                                         643       if(huart->Init.WordLength == UART_WORDLENGTH_9B)                                              644       {                                                                                             645         if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)  646         {                                                                                           647           return HAL_TIMEOUT;                                                                       648         }                                                                                           649         tmp = (uint16_t*) pData;                                                                    650         huart->Instance->DR = (*tmp & (uint16_t)0x01FF);                                            651         if(huart->Init.Parity == UART_PARITY_NONE)                                                  652         {                                                                                           653           pData +=2U;                                                                               654         }                                                                                           655         else                                                                                        656         {                                                                                           657           pData +=1U;    658         }                                                                                           659       }                                                                                             660       else                                                                                          661       {                                                                                             662         if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)  663         {                                                                                           664           return HAL_TIMEOUT;                                                                       665         }                                                                                           666         huart->Instance->DR = (*pData++ & (uint8_t)0xFF);                                           667       }                                                                                             668     }                                                                                               669                                                                                                     670     if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)       671     {                                                                                               672       return HAL_TIMEOUT;                                                                           673     }                                                                                               674                                                                                                     675     /* At end of Tx process, restore huart->gState to Ready */                                      676       huart->gState = HAL_UART_STATE_READY;                                                         677                                                                                                     678     /* Process Unlocked */                                                                          679     __HAL_UNLOCK(huart);                                                                            680                                                                                                     681     return HAL_OK;                                                                                  682   }                                                                                                 683   else                                                                                              684   {                                                                                                 685     return HAL_BUSY;                                                                                                                                                                                    686   }                                                                                                 687 }               

分析以上的代码:

  1. 确认uart的状态
  2. uart加锁,更新初始化的时间,更改初始化的状态
  3. 根据配置数据位是8为还是9位,进行逐一发送
    1. 因为DR数据寄存器最大为9位,因此必须逐一发送
    2. 注意函数UART_WaitOnFlagUntilTimeout,每发完一个字节,就会去检查状态寄存器UART_FLAG_TXE,判断是否发完并且检查等待发送的过程中是否超时
  4. 所有的数据都发完了,解锁,返回状态。

    无阻塞的发送(中断方式)

    778 /**
    779   * @brief  Sends an amount of data in non blocking mode.
    780   * @param  huart pointer to a UART_HandleTypeDef structure that contains
    781   *                the configuration information for the specified UART module.
    782   * @param  pData Pointer to data buffer
    783   * @param  Size Amount of data to be sent
    784   * @retval HAL status
    785   */
    786 HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    787 {
    788   /* Check that a Tx process is not already ongoing */
    789   if(huart->gState == HAL_UART_STATE_READY)
    790   {
    791     if((pData == NULL ) || (Size == 0))
    792     {
    793       return HAL_ERROR;
    794     }
    795
    796     /* Process Locked */
    797     __HAL_LOCK(huart);
    798
    799     huart->pTxBuffPtr = pData;
    800     huart->TxXferSize = Size;
    801     huart->TxXferCount = Size;
    802
    803     huart->ErrorCode = HAL_UART_ERROR_NONE;
    804     huart->gState = HAL_UART_STATE_BUSY_TX;
    805
    806     /* Process Unlocked */
    807     __HAL_UNLOCK(huart);
    808
    809     /* Enable the UART Transmit data register empty Interrupt */
    810     SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
    811
    812     return HAL_OK;
    813   }
    814   else
    815   {
    816     return HAL_BUSY;
    817   }
    818 }

代码分析:
无阻塞发送的代码看起来是简单了很多,但是分析起来看实际上,也是差不多的,整体过程比无阻塞发送还要复杂一点。

  1. 锁定串口,更新状态
  2. 结构体赋值,数据段的地址,长度。
  3. 锁定串口,开启串口中断USART_CR1_TXEIE。
    当sr寄存器中的,TXE=1时,生成uart中断。
    TXE = 0,数据未传输到移位寄存器 ,TXE = 1,数据传输到移位寄存器
  4. 结束返回

接下来时中断程序:

1629   /* UART in mode Transmitter ------------------------------------------------*/
1630   if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
1631   {
1632     UART_Transmit_IT(huart);
1633     return;
1634   }
1635
1636   /* UART in mode Transmitter end --------------------------------------------*/
1637   if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
1638   {
1639     UART_EndTransmit_IT(huart);
1640     return;
1641   }   

进入第一个中断,判断 USART_SR_TXE和 USART_CR1_TXEIE被置位,其中TXEIE代表开启UART的中断,TXE就表示数据发送完成, 当TXE被硬件置位时,就会进入中断,之后我们将新的的数据放到DR寄存器重视这个位就会被再次清零,等待下一次发送数据完成之后,再次进入中断。

2304 static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
2305 {
2306   uint16_t* tmp;
2307
2308   /* Check that a Tx process is ongoing */
2309   if(huart->gState == HAL_UART_STATE_BUSY_TX)
2310   {
2311     if(huart->Init.WordLength == UART_WORDLENGTH_9B)
2312     {
2313       tmp = (uint16_t*) huart->pTxBuffPtr;
2314       huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
2315       if(huart->Init.Parity == UART_PARITY_NONE)
2316       {
2317         huart->pTxBuffPtr += 2U;
2318       }
2319       else
2320       {
2321         huart->pTxBuffPtr += 1U;
2322       }
2323     }
2324     else
2325     {
2326       huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);
2327     }
2328
2329     if(--huart->TxXferCount == 0U)
2330     {
2331       /* Disable the UART Transmit Complete Interrupt */
2332       CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
2333
2334       /* Enable the UART Transmit Complete Interrupt */
2335       SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
2336     }
2337     return HAL_OK;
2338   }
2339   else
2340   {
2341     return HAL_BUSY;
2342   }
2343 } 

分析代码:
1. 根据数据段是8位还是9位,对DR寄存器进行置位
2. 判断最后一个字节是否发送完成,如果最后一位也已经将数据放到移位寄存器中去了,就disable中断USART_CR1_TXEIE,初始化中断USART_CR1_TCIE
USART_CR1_TCIE: 传输完成中断,有软件置位和清零,置位是会触发中断。

2351 static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)
2352 {
2353   /* Disable the UART Transmit Complete Interrupt */
2354   CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE);
2355
2356   /* Tx process is ended, restore huart->gState to Ready */
2357   huart->gState = HAL_UART_STATE_READY;
2358
2359   HAL_UART_TxCpltCallback(huart);
2360
2361   return HAL_OK;
2362 } 

代码分析:
到这里中断方式发送数据就完成了,接着就是调用用户的回调函数。
注意这里,所有的数据,都是在中断里面发送的
我们发现只有在发送的时候才会将TCIE,TXEIE这两个位置位,开启中断。平常的时候中断都是关闭的。

DMA方式发送(无阻塞方式发送)

 873 HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)   874 {                                                                                                                                 875   uint32_t *tmp;                                                                                                                  876                                                                                                                                   877   /* Check that a Tx process is not already ongoing */                                                                            878   if(huart->gState == HAL_UART_STATE_READY)                                                                                       879   {                                                                                                                               880     if((pData == NULL ) || (Size == 0))                                                                                           881     {                                                                                                                             882       return HAL_ERROR;                                                                                                                                                                                 883     }                                                                                                                             884                                                                                                                                   885     /* Process Locked */                                                                                                          886     __HAL_LOCK(huart);                                                                                                            887                                                                                                                                   888     huart->pTxBuffPtr = pData;                                                                                                    889     huart->TxXferSize = Size;                                                                                                     890     huart->TxXferCount = Size;                                                                                                    891                                                                                                                                   892     huart->ErrorCode = HAL_UART_ERROR_NONE;                                                                                       893     huart->gState = HAL_UART_STATE_BUSY_TX;                                                                                       894                                                                                                                                   895     /* Set the UART DMA transfer complete callback */                                                                             896     huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;                                                                       897                                                                                                                                   898     /* Set the UART DMA Half transfer complete callback */                                                                        899     huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;                                                                     900                                                                                                                                   901     /* Set the DMA error callback */                                                                                              902     huart->hdmatx->XferErrorCallback = UART_DMAError;                                                                             903                                                                                                                                   904     /* Set the DMA abort callback */                                                                                              905     huart->hdmatx->XferAbortCallback = NULL;                                                                                      906                                                                                                                                   907     /* Enable the UART transmit DMA Stream */                                                                                     908     tmp = (uint32_t*)&pData;                                                                                                      909     HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t*)tmp, (uint32_t)&huart->Instance->DR, Size);         910                                                                                                                                   911     /* Clear the TC flag in the SR register by writing 0 to it */                                                                 912     __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);                                                                                   913                                                                                                                                   914     /* Process Unlocked */                                                                                                        915     __HAL_UNLOCK(huart);                                                                                                          916                                                                                                                                   917     /* Enable the DMA transfer for transmit request by setting the DMAT bit                         918        in the UART CR3 register */                                                                                                919     SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);                                                                                920                                                                                                                                   921     return HAL_OK;                                                                                                                922   }                                                                                                                               923   else                                                                                                                            924   {                                                                                                                               925     return HAL_BUSY;                                                                                                              926   }                                                                                                                               927 } 

代码分析:
1. 锁定串口,初始化结构体变量
2. 初始化所有的回调函数
3. 开启DMA中断传输,这种传输方式是从内存拷贝数据到外设寄存器。

 451 /**                                                                                                                               452   * @brief  Start the DMA Transfer with interrupt enabled.                                                                        453   * @param  hdma       pointer to a DMA_HandleTypeDef structure that contains                       454   *                     the configuration information for the specified DMA Stream.                 455   * @param  SrcAddress The source memory Buffer address                                                                                                                                                 456   * @param  DstAddress The destination memory Buffer address                                                                      457   * @param  DataLength The length of data to be transferred from source to destination              458   * @retval HAL status                                                                                                            459   */                                                                                                                              460 HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
在这里DMA内存和片外设的地址都是设置成自增加的
114   hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
115   hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;   
  1. 清除传输完成中断
  2. 打开串口,初始化DMA
  3. 返回值
    接下来就是等待传输中断完成。
    需要注意的是:DMA的工作是不需要cpu来参与的,连续使用DMA来进行发送或接受数据时,我们需要判断上次的数据发送是否发送完成。
138   /*##-5- Send the received Buffer ###########################################*/
139   if(HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)aRxBuffer, RXBUFFERSIZE)!= HAL_OK)
140   {
141     /* Transfer error in transmission process */
142     Error_Handler();
143   }
144
145   /*##-6- Wait for the end of the transfer ###################################*/
146   while (HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY)
147   {
148   }
149
150   /*##-7- Send the End Message ###############################################*/
151   if(HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)aTxEndMessage, TXENDMESSAGESIZE)!= HAL_OK)
152   {
153     /* Turn LED3 on: Transfer error in transmission process */
154     BSP_LED_On(LED3);
155     while(1)
156     {
157     }
158   } 

因为第一句发送数据完成时,数据实际上可能没有发送完成,因为这是无阻塞的。因此发新的数据之前我们要确保上次的数据是否已经发送完成。否则的话会造成数据的丢失。

无阻塞方式接收,阻塞方式接受和发送的逻辑大同小异,这里就不再一一列举了。

需要注意的是,我们这里使用HAL_UART_Receive,还是使用HAL_UART_Receive_IT都可以接受多个字节这个都是由hal库已经做好了的。但是这样做的话接收到指定字节的数据之后,就没有办法继续接受数据。在实际的工程里,我们可能需要一直接收数据,通常的做法是,接受一定量的数据之后,在中断里面开启下一次的就收数据。
以下是简单的实例

190 void USART1_IRQHandler()
191 {
192     OSIntEnter();
193     HAL_UART_IRQHandler(&UART_Handler[UART_DEV1]);
194     HAL_UART_Receive_IT(&UART_Handler[UART_DEV1], (u8 *)&s_byUartRxdBuf[UART_DEV1][0], USART_RECLEN_TRIG_HOOK);
195     OSIntExit();
196 } 

stm32 hal库分析之uart相关推荐

  1. stm32 HAL库分析之CAN

    stm32 HAL库分析之CAN 阻塞发送 HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout) ...

  2. STM32的HAL库分析及使用

    STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直接配 ...

  3. STM32 HAL库 CubeMX教程(五)串口通信基础

    STM32 HAL库 CubeMX教程(五)串口通信基础 串口通信简介 CubeMX配置 初始化程序分析 程序编写 参考文献 STM32 HAL库 CubeMX系列教程 目录 串口通信简介 UART: ...

  4. STM32 HAL库 串口DMA(收发)和STM32串口中断接收(接收时间管理机制)+ESP8266 wifi模组通信问题

    一.HAL库 串口 DMA+ESP8266模组通信问题 用STM32 HAL库串口的DMA发送和空闲中断接收处理数据,单片机发送AT指令给ESP8266 wifi模组问题:单片机连续几次给wifi模组 ...

  5. STM32 HAL库学习笔记1-HAL库简介

    STM32 HAL库学习笔记1-HAL库简介 HAL库 SPL 库 和 HAL 库两者相互独立,互不兼容.几种库的比较如下 目前几种库对不同芯片的支持情况如下 ST 中文官网上有一篇<关于ST库 ...

  6. STM32 HAL库详解

    STM32 HAL库整体总结 STM32 之二 HAL库详解 及 手动移植 本篇博客是对以上参考资源的一个二次总结与整理. 1. HAL库文件结构 对于开发人员而言,首先要清楚 HAL 库的文件结构. ...

  7. STM32 HAL库学习笔记4-SPI

    STM32 HAL库学习笔记4-SPI 前言 一.SPI协议简介 SPI物理层 SPI协议层 1.基本通讯过程 2. 通讯的起始和停止信号 3. 数据有效性 4. CPOL/CPHA 及通讯模式 二. ...

  8. STM32 HAL库组成概述

    STM32 HAL库概述 ## (一)HAL库设计思想 什么是HAL(Hardware Abstraction Layer)? from 百度百科: 硬件抽象层是位于操作系统内核与硬件电路之间的接口层 ...

  9. stm32+HAL库制作转速仪

    stm32+HAL库制作转速仪 前言 电机在运行过程中,需要实时检测其转速的稳定性,有效反映电机的运行情况. 本文介绍了基于stm32的转速仪的设计,可以用光电门传感器和红外对管传感器测量,可以设置选 ...

最新文章

  1. linux服务之rsync
  2. 数据结构树的基本操作_《数据结构》树的基本操作.doc
  3. java集群_JAVA架构师学习:实践ZooKeeper 应用场景与集群管理,辛勤总结
  4. python字符串中find函数_Python之字符串常用花哨玩法
  5. C++ 11 深度学习(五)类型转换:static_cast dynamic_cast const_cast reinterpret_cast
  6. docker安装并运行ElasticSearch-Head插件
  7. 【数据泵】EXPDP导出表结构
  8. Mac目录映射到docker容器ubuntu目录
  9. 程序员的终极幻想(一):像操作数据库那样操作大脑的记忆
  10. par函数的bg参数-控制图片的背景色
  11. Java Hamcrest学习
  12. kindle paperwhite3 拆机越狱
  13. 朋友在B站魔力赏抽到的动漫周边,把我看馋了
  14. 计算机连接网络需要什么,宽带怎么安装需要什么_安装宽带步骤-系统城
  15. 通过“单键锁配置法”实现访问控制
  16. 《青春有你2》选手信息爬取
  17. 全排列【46. 全排列】
  18. Unity3d实现Projector(喷码效果)
  19. 【BW系列】SAP 讲讲BW/4 HANA和BW on HANA的区别
  20. pytorch 实现Faster R-cnn从头开始(一)

热门文章

  1. @keyup.enter失效问题
  2. shell-------数组遍历、切片、替换等操作
  3. 为什么postgresql最大的单表只能是32TB
  4. 自然数的皮亚诺公理系統
  5. Eclipse代码提示和补全
  6. 【学习笔记】《卓有成效的管理者》 第三章 我能贡献什么
  7. VC++游戏编程----游戏画面特效制作2
  8. SQL日期时间转为字符串
  9. [OS-Linux] CentOS 7.x 安全登录策略设置
  10. java实现Word 文档形式的导出功能