×
单片机 > 单片机程序设计 > 详情

stm32 hal库分析之uart

发布时间:2020-06-05 发布时间:
|

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 }               


分析以上的代码:


确认uart的状态

uart加锁,更新初始化的时间,更改初始化的状态

根据配置数据位是8为还是9位,进行逐一发送 

因为DR数据寄存器最大为9位,因此必须逐一发送

注意函数UART_WaitOnFlagUntilTimeout,每发完一个字节,就会去检查状态寄存器UART_FLAG_TXE,判断是否发完并且检查等待发送的过程中是否超时

所有的数据都发完了,解锁,返回状态。


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

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 }



代码分析: 

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


锁定串口,更新状态

结构体赋值,数据段的地址,长度。

锁定串口,开启串口中断USART_CR1_TXEIE。 

当sr寄存器中的,TXE=1时,生成uart中断。 

TXE = 0,数据未传输到移位寄存器 ,TXE = 1,数据传输到移位寄存器

结束返回

接下来时中断程序:


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内存和片外设的地址都是设置成自增加的

1

114   hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;                                                                             

115   hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;   


清除传输完成中断

打开串口,初始化DMA

返回值 

接下来就是等待传输中断完成。 

需要注意的是: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 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/2019/ic-news031143442.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机中断源的扩展方法