stm32 hal库分析之uart

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 } 
  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值