查看: 3133|回复: 1

STM32的HAL库学习挖坑-串口

[复制链接]
  • TA的每日心情
    无聊
    2018-8-15 10:21
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2018-10-15 15:21:53 | 显示全部楼层 |阅读模式
    分享到:
    实现功能:回显串口助手发送的数据,数据结束符为‘a’。

    参考例程:官网串口的printf例程。

    用到的串口函数接口:
    HAL_UART_Init-串口初始化函数
    HAL_UART_Transmit-串口发送函数
    HAL_UART_Receive_IT-使能串口中断接收函数(需每次调用才能持续中断接收)
    HAL_UART_IRQHandler-串口中断处理函数
    HAL_UART_RxCpltCallback-串口接收回调函数
    HAL_UART_ErrorCallback-串口故障回调函数

    实现过程:

    1.初始化函数和串口中断处理函数用STM32CUBEMX搞定,printf函数如下重定义
    1. #ifdef __GNUC__
    2.   /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
    3.      set to 'Yes') calls __io_putchar() */
    4.   #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    5. #else
    6.   #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    7. #endif /* __GNUC__ */
    8. PUTCHAR_PROTOTYPE
    9. {
    10.   /* Place your implementation of fputc here */
    11.   /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
    12.   HAL_UART_Transmit(&usart1, (uint8_t *)&ch, 1, 0xFFFF);
    13.        
    14.   return ch;
    15. }
    复制代码

    2.全局变量声明
    1. uint16_t i;
    2. uint16_t Rx_Len = 0;
    3. uint8_t Rx_Flag = 0;
    4. uint8_t Rx_Buffer[20];
    5. uint8_t Dat_Buffer[1024];
    复制代码

    3.在主循环前,使能串口接收
    1. HAL_UART_Receive_IT(&usart1, (uint8_t *)Rx_Buffer, 1);
    复制代码

    4.主循环
    1. while(1)
    2. {
    3.         if(Rx_Flag == 1)
    4.         {
    5.                 for(i = 0; i < Rx_Len; i++)
    6.                 {
    7.                         printf("%c",Dat_Buffer[i]);                               
    8.                 }
    9.                 printf("\r\n");       
    10.                 Rx_Flag = 0;
    11.                 Rx_Len = 0;
    12.                 memset(&Dat_Buffrt,0,sizeof(Dat_Buffrt));                                       
    13.         }
    14. }
    复制代码

    5.回调函数的重定义
    1. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)  //接收处理函数-存数据
    2. {
    3.        
    4.                 UNUSED(usart1);
    5.                 Dat_Buffer[Rx_Len] = (*((uint8_t *)Rx_Buffer));               
    6.                 if(Dat_Buffer[Rx_Len] == 'a')
    7.                 {
    8.                         Rx_Flag = 1;
    9.                 }
    10.                 Rx_Len++;
    11.                 HAL_UART_Receive_IT(&usart1, (uint8_t *)Rx_Buffer, 1);
    12. }
    复制代码

    调试中遇到的问题:使用串口助手快速发送大数据时,会发现串口回显的数据变少,

    且继续用串口助手发送2字节数据时,发现串口不会回显,于是增加串口故障回调函数如下:
    1. void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)   //故障回调-查看故障状态
    2. {
    3.                 printf("\r\n uart_status  %x\r\n",HAL_UART_GetState(&usart1));       
    4.                 printf("\r\n uart_error  %x\r\n",HAL_UART_GetError(&usart1));       
    5. }
    复制代码

    然后发现staus = 0x20,error = 0x08

    于是根据HAL库的定义发现以下有趣的东西

    1.   HAL_UART_STATE_READY             = 0x20U,   /*!< Peripheral Initialized and ready for use
    2.                                                    Value is allowed for gState and RxState */
    复制代码
    1.   HAL_UART_ERROR_ORE       = 0x08U,    /*!< Overrun error       */
    复制代码

    大体意思是串口处于接收数据状态且溢出故障,表明串口依然是能输出数据的,但是为何会无法接收到数据呢?

    整体程序不大,找问题的地方也就那几个地方,初始化,主循环或者中断

    于是我先将printf内的超时时间改为10,但是结果依旧,排除串口延时导致串口假死

    初始化与之前标准库的初始化样式对比了以下,没啥大关系

    于是去看了中断函数HAL_UART_IRQHandler,发现
    1. /**
    2.   * @brief  End ongoing Rx transfer on UART peripheral (following error detection or Reception completion).
    3.   * @param huart UART handle.
    4.   * @retval None
    5.   */
    6. static void UART_EndRxTransfer(UART_HandleTypeDef *huart)
    7. {
    8.   /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
    9. #if defined(USART_CR1_FIFOEN)
    10.   CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE));
    11. #else
    12.   CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    13. #endif
    14.   CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

    15.   /* At end of Rx process, restore huart->RxState to Ready */
    16.   huart->RxState = HAL_UART_STATE_READY;
    17.   
    18.   /* Reset RxIsr function pointer */
    19.   huart->RxISR = NULL;
    20. }
    复制代码

    该函数大体意思是我已经关闭串口接收了,到此找到串口无法继续接收的原因

    由于放假,没有实际硬件,这里我想到两种解决思路:

    1.将寄存器值复位,重新使能中断接收(具体需要看寄存器手册);

    2.用HAL库重新初始化串口,重新使能中断接收(简单粗暴);



    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-1-16 17:48
  • 签到天数: 592 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2018-10-17 16:11:16 | 显示全部楼层
    串口中断接受,里面有个 size 参数,可以一次接受 size 个字节的长度,调用一次就接受完了。
    其实他也是一个字节一次中断接受的,这个接收完了,是不是最后一个字节,huart 结构体内部判断,不用用户写代码处理,函数自己完成
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-26 09:14 , Processed in 0.124343 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.