你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32L0xx_HAL_Driver库的使用——UART

[复制链接]
STMCU小助手 发布时间:2021-11-18 22:00
单片机型号:STM32L051C8T6

开发环境MDK5.12

库版本:STM32L0xx_HAL_Driver V1.1.0

主机环境:Windows XP

之前一直使用的STM32F030C8T6单片机来做开发,因需求更改更换了一个新型号STM32L051C8T6,主要是用到了其低功耗特性,本以为直接把代码拷贝一下就可以使用了,结果是太天真了,STM32F030C8T6使用的库是STM32F0_StdPeriph_Lib而STM32L051C8T6使用的库是STM32L0xx_HAL_Driver两者的差别还是很大的,而且官方也推荐使用后者,没办法,重新学习一下吧。。。参考其例程磕磕绊绊的勉强可以写一个工程了,这里写一下有关UART的调试。

参考的程序是STM32L053R8-Nucleo例程中的UART_TwoBoards_ComIT工程,采用中断方式来进行两个单片机之间的通信。STM32L0xx_HAL_Driver库的分层更加明显,板极初始化代码如下


  1. void HAL_UART_MspInit(UART_HandleTypeDef *huart)
  2. {  
  3.   GPIO_InitTypeDef  GPIO_InitStruct;

  4.   /*##-1- Enable peripherals and GPIO Clocks #################################*/
  5.   /* Enable GPIO TX/RX clock */
  6.   USARTx_TX_GPIO_CLK_ENABLE();
  7.   USARTx_RX_GPIO_CLK_ENABLE();
  8.   /* Enable USART1 clock */
  9.   USARTx_CLK_ENABLE();

  10.   /*##-2- Configure peripheral GPIO ##########################################*/  
  11.   /* UART TX GPIO pin configuration  */
  12.   GPIO_InitStruct.Pin       = USARTx_TX_PIN;
  13.   GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  14.   GPIO_InitStruct.Pull      = GPIO_NOPULL;
  15.   GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  16.   GPIO_InitStruct.Alternate = USARTx_TX_AF;

  17.   HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

  18.   /* UART RX GPIO pin configuration  */
  19.   GPIO_InitStruct.Pin = USARTx_RX_PIN;
  20.   GPIO_InitStruct.Alternate = USARTx_RX_AF;

  21.   HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);

  22.   /*##-3- Configure the NVIC for UART ########################################*/
  23.   /* NVIC for USART1 */
  24.   HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);
  25.   HAL_NVIC_EnableIRQ(USARTx_IRQn);
  26. }

  27. /**
  28.   * @brief UART MSP De-Initialization
  29.   *        This function frees the hardware resources used in this example:
  30.   *          - Disable the Peripheral's clock
  31.   *          - Revert GPIO and NVIC configuration to their default state
  32.   * @param huart: UART handle pointer
  33.   * @retval None
  34.   */
  35. void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
  36. {
  37.   /*##-1- Reset peripherals ##################################################*/
  38.   USARTx_FORCE_RESET();
  39.   USARTx_RELEASE_RESET();

  40.   /*##-2- Disable peripherals and GPIO Clocks #################################*/
  41.   /* Configure UART Tx as alternate function  */
  42.   HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);
  43.   /* Configure UART Rx as alternate function  */
  44.   HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  45.   /*##-3- Disable the NVIC for UART ##########################################*/
  46.   HAL_NVIC_DisableIRQ(USARTx_IRQn);
  47. }
复制代码


这两个函数没什么可说的跟开发板对应修改即可,这样使得串口初始化更加的简洁只需要进行逻辑上的初始化即可

  1. /**********************************************************************
  2. 函数:uart_init()
  3. 函数作用:串口初始化
  4. 参数:
  5.         uint32_t BaudRate=========================串口波特率
  6. 返回值:无
  7. 上一版本:无
  8. 当前版本:1.0
  9. 作者:
  10. 最后修改时间:2015-04-02
  11. 说明:
  12. **********************************************************************/
  13. void uart_init(uint32_t BaudRate)
  14. {

  15.     UartHandle.Instance        = USARTx;
  16.     UartHandle.Init.BaudRate   = BaudRate;
  17.     UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  18.     UartHandle.Init.StopBits   = UART_STOPBITS_1;
  19.     UartHandle.Init.Parity     = UART_PARITY_NONE;
  20.     UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  21.     UartHandle.Init.Mode       = UART_MODE_TX_RX;

  22.     if(HAL_UART_Init(&UartHandle) != HAL_OK)
  23.     {
  24.         Error_Handler();
  25.     }
  26.         __HAL_UART_ENABLE(&UartHandle);

  27.         NVIC_SetPriority(USARTx_IRQn,0);
  28.         NVIC_EnableIRQ(USARTx_IRQn);
  29.         uart_rev.front = aRxBuffer;
  30.         uart_rev.rear = aRxBuffer;        //两个指针指向相同的地址空间
  31.         if(HAL_UART_Receive_IT(&UartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK)
  32.         {
  33.                 Error_Handler();
  34.         }
  35. }
复制代码

这里为串口的接收开辟了500个字节的缓冲区aRxBuffer使用首尾指针来进行数据的接收和存取,即单缓冲机制。

  1. struct uart
  2. {
  3.         uint8_t *rear;                        //在中断函数中更改
  4.         uint8_t *front;                        //在主循环中更改
  5. };
复制代码

由于STM32L0xx_Hal_Driver库的使用串口底层分为了3种:查询方式、中断方式、DMA方式,都是使用HAL函数来实现,因此我们使用中断方式接收不能自动开启,必须使用函数HAL_UART_Receive_IT来打开接收中断,这里我们每接收一个字节就进入中断。STM32L0xx_Hal_Driver库的使用使得中断函数也十分简洁一句话搞定,采用回调函数机制来处理中断

  1. void USARTx_IRQHandler(void)
  2. {
  3.           HAL_UART_IRQHandler(& UartHandle);
  4. }
  5. 在HAL_UART_IRQHandler()中会自动调用串口接收中断的回调函数

  6. /**
  7.   * @brief  Rx Transfer completed callback
  8.   * @param  UartHandle: UART handle
  9.   * @note   This example shows a simple way to report end of IT Rx transfer, and
  10.   *         you can add your own implementation.
  11.   * @retval None
  12.   */
  13. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
  14. {
  15.         uint8_t ret = HAL_OK;
  16.         /* Set transmission flag: trasfer complete*/
  17.         uart_rev.rear++;        //更新rear指针
  18.         if(uart_rev.rear >= (aRxBuffer + BUFFSIZE))
  19.                 uart_rev.rear = aRxBuffer;
  20.         do
  21.         {
  22.                 ret = HAL_UART_Receive_IT(UartHandle,uart_rev.rear,1);
  23.         }while(ret != HAL_OK);
  24. }
复制代码

每次把接收到的数据存入rear所指向的地址空间,存入数据只更新rear指针,同时开启请求下一个数据的到来。在主函数中调用uart_read函数来取出数据

  1. /**********************************************************************
  2. 函数:uart_read()
  3. 函数作用:从接收缓冲区中读取数据
  4. 参数:
  5.         uint8_t *fmt--------------------------------接收到的数据
  6.         uint16_t time_out---------------------------超时时间
  7. 返回值:0:读取到数据-1:没有读取到数据
  8. 上一版本:无
  9. 当前版本:1.0
  10. 作者:
  11. 最后修改时间:2015-04-08
  12. 说明:
  13. **********************************************************************/
  14. int8_t uart_read(uint8_t *fmt, uint16_t time_out)
  15. {
  16.         while(time_out)
  17.         {
  18.                 if(uart_rev.front != uart_rev.rear)
  19.                 {
  20.                         //如果队首指针和队尾指针不同表明缓冲区中有数据还未收取
  21.                         *fmt=*uart_rev.front;
  22.                
  23.                         uart_rev.front++;

  24.                         if (uart_rev.front >= (aRxBuffer+BUFFSIZE))
  25.                                 uart_rev.front = aRxBuffer;

  26.                         return 0;
  27.                 }
  28.                 time_out--;
  29.         }
  30.         return (int8_t)-1;
  31. }
复制代码


取数据只更新front指针,这里有个不足的地方是如果一直不取数据或者取数据速度较慢而接收的数据很多会造成数据覆盖即出现数据丢失的情况,不过一般很少会有这种情发生(对于我来说是在主循环中不停地进行读取操作,所以没事啦),整个文件如下

  1. #include "UART.h"
  2. #include "stm32l0xx_hal_def.h"
  3. #include "utils.h"

  4. UART_HandleTypeDef UartHandle;
  5. uint8_t aRxBuffer[BUFFSIZE];
  6. struct uart uart_rev;

  7. void HAL_UART_MspInit(UART_HandleTypeDef *huart)
  8. {  
  9.   GPIO_InitTypeDef  GPIO_InitStruct;

  10.   /*##-1- Enable peripherals and GPIO Clocks #################################*/
  11.   /* Enable GPIO TX/RX clock */
  12.   USARTx_TX_GPIO_CLK_ENABLE();
  13.   USARTx_RX_GPIO_CLK_ENABLE();
  14.   /* Enable USART1 clock */
  15.   USARTx_CLK_ENABLE();

  16.   /*##-2- Configure peripheral GPIO ##########################################*/  
  17.   /* UART TX GPIO pin configuration  */
  18.   GPIO_InitStruct.Pin       = USARTx_TX_PIN;
  19.   GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  20.   GPIO_InitStruct.Pull      = GPIO_NOPULL;
  21.   GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
  22.   GPIO_InitStruct.Alternate = USARTx_TX_AF;

  23.   HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);

  24.   /* UART RX GPIO pin configuration  */
  25.   GPIO_InitStruct.Pin = USARTx_RX_PIN;
  26.   GPIO_InitStruct.Alternate = USARTx_RX_AF;

  27.   HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);

  28.   /*##-3- Configure the NVIC for UART ########################################*/
  29.   /* NVIC for USART1 */
  30.   HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1);
  31.   HAL_NVIC_EnableIRQ(USARTx_IRQn);
  32. }

  33. /**
  34.   * @brief UART MSP De-Initialization
  35.   *        This function frees the hardware resources used in this example:
  36.   *          - Disable the Peripheral's clock
  37.   *          - Revert GPIO and NVIC configuration to their default state
  38.   * @param huart: UART handle pointer
  39.   * @retval None
  40.   */
  41. void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
  42. {
  43.   /*##-1- Reset peripherals ##################################################*/
  44.   USARTx_FORCE_RESET();
  45.   USARTx_RELEASE_RESET();

  46.   /*##-2- Disable peripherals and GPIO Clocks #################################*/
  47.   /* Configure UART Tx as alternate function  */
  48.   HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN);
  49.   /* Configure UART Rx as alternate function  */
  50.   HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN);

  51.   /*##-3- Disable the NVIC for UART ##########################################*/
  52.   HAL_NVIC_DisableIRQ(USARTx_IRQn);
  53. }

  54. /**********************************************************************
  55. 函数:uart_init()
  56. 函数作用:串口初始化
  57. 参数:
  58.         uint32_t BaudRate=========================串口波特率
  59. 返回值:无
  60. 上一版本:无
  61. 当前版本:1.0
  62. 作者:
  63. 最后修改时间:2015-04-02
  64. 说明:
  65. **********************************************************************/
  66. void uart_init(uint32_t BaudRate)
  67. {

  68.     UartHandle.Instance        = USARTx;
  69.     UartHandle.Init.BaudRate   = BaudRate;
  70.     UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  71.     UartHandle.Init.StopBits   = UART_STOPBITS_1;
  72.     UartHandle.Init.Parity     = UART_PARITY_NONE;
  73.     UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  74.     UartHandle.Init.Mode       = UART_MODE_TX_RX;

  75.     if(HAL_UART_Init(&UartHandle) != HAL_OK)
  76.     {
  77.         Error_Handler();
  78.     }
  79.         __HAL_UART_ENABLE(&UartHandle);

  80.         NVIC_SetPriority(USARTx_IRQn,0);
  81.         NVIC_EnableIRQ(USARTx_IRQn);
  82.         uart_rev.front = aRxBuffer;
  83.         uart_rev.rear = aRxBuffer;        //两个指针指向相同的地址空间
  84.         if(HAL_UART_Receive_IT(&UartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK)
  85.         {
  86.                 Error_Handler();
  87.         }
  88. }
  89. void Error_Handler(void)
  90. {
  91.     while(1)
  92.     {

  93.     }
  94. }

  95. /**********************************************************************
  96. 函数:uart_read()
  97. 函数作用:从接收缓冲区中读取数据
  98. 参数:
  99.         uint8_t *fmt--------------------------------接收到的数据
  100.         uint16_t time_out---------------------------超时时间
  101. 返回值:0:读取到数据-1:没有读取到数据
  102. 上一版本:无
  103. 当前版本:1.0
  104. 作者:
  105. 最后修改时间:2015-04-08
  106. 说明:
  107. **********************************************************************/
  108. int8_t uart_read(uint8_t *fmt, uint16_t time_out)
  109. {
  110.         while(time_out)
  111.         {
  112.                 if(uart_rev.front != uart_rev.rear)
  113.                 {
  114.                         //如果队首指针和队尾指针不同表明缓冲区中有数据还未收取
  115.                         *fmt=*uart_rev.front;
  116.                
  117.                         uart_rev.front++;

  118.                         if (uart_rev.front >= (aRxBuffer+BUFFSIZE))
  119.                                 uart_rev.front = aRxBuffer;

  120.                         return 0;
  121.                 }
  122.                 time_out--;
  123.         }
  124.         return (int8_t)-1;
  125. }

  126. int8_t uart_send(uint8_t *fmt, uint8_t len)
  127. {
  128.         while(len)
  129.         {
  130.                 printf("%c",*fmt);
  131.                 fmt++;
  132.                 len--;
  133.         }

  134.         return 0;
  135. }

  136. #ifdef UART_DEBUG
  137. int fputc(int ch, FILE *f)
  138. {
  139.     USART1->TDR = ch;
  140.     while(!(USART1->ISR & USART_ISR_TXE));
  141.     return(ch);
  142. }
  143. #endif

  144. /**
  145.   * @brief  Tx Transfer completed callback
  146.   * @param  UartHandle: UART handle.
  147.   * @note   This example shows a simple way to report end of IT Tx transfer, and
  148.   *         you can add your own implementation.
  149.   * @retval None
  150.   */
  151. void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart)
  152. {
  153.         uint8_t ret = HAL_OK;
  154.         UartReady = SET;
  155.         #if 1
  156.         uart_snd.front++;        //更新rear指针
  157.         if(uart_snd.front >= (aTxBuffer + BUFFSIZE))
  158.                 uart_snd.front = aTxBuffer;
  159.         if(uart_snd.front != uart_snd.rear)
  160.         {
  161.                 //如果队首指针和队尾指针不同表明缓冲区中有数据还未发送
  162.                 do
  163.                 {
  164.                         ret = HAL_UART_Transmit_IT(&UartHandle,uart_snd.front,1);//请求发送下一个数据
  165.                 }while(ret != HAL_OK);
  166.         }
  167.         #endif
  168. }
  169. /**
  170.   * @brief  Rx Transfer completed callback
  171.   * @param  UartHandle: UART handle
  172.   * @note   This example shows a simple way to report end of IT Rx transfer, and
  173.   *         you can add your own implementation.
  174.   * @retval None
  175.   */
  176. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
  177. {
  178.         uint8_t ret = HAL_OK;
  179.         /* Set transmission flag: trasfer complete*/
  180.         uart_rev.rear++;        //更新rear指针
  181.         if(uart_rev.rear >= (aRxBuffer + BUFFSIZE))
  182.                 uart_rev.rear = aRxBuffer;
  183.         do
  184.         {
  185.                 ret = HAL_UART_Receive_IT(UartHandle,uart_rev.rear,1);
  186.         }while(ret != HAL_OK);
  187. }
  188. /******************************************************************************/
  189. /*                 STM32L0xx Peripherals Interrupt Handlers                   */
  190. /*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
  191. /*  available peripheral interrupt handler's name please refer to the startup */
  192. /*  file (startup_stm32l0xx.s).                                               */
  193. /******************************************************************************/
  194. /**
  195.   * @brief  This function handles UART interrupt request.  
  196.   * @param  None
  197.   * @retval None
  198.   * @Note   This function is redefined in "main.h" and related to DMA stream
  199.   *         used for USART data transmission     
  200.   */
  201. void USARTx_IRQHandler(void)
  202. {
  203.           HAL_UART_IRQHandler(& UartHandle);
  204. }
复制代码


在实际测试中也没有问题,当单缓冲机制可用时,就会考虑使用双缓冲机制即为串口发送也开辟一个缓冲区。


收藏 评论0 发布时间:2021-11-18 22:00

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版