打印
[应用相关]

STM32的HAL库学习-串口

[复制链接]
1037|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
小灵通2018|  楼主 | 2018-11-6 16:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
实现功能:回显串口助手发送的数据,数据结束符为‘a’。

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

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

实现过程:

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

2.全局变量声明
uint16_t i;
uint16_t Rx_Len = 0;
uint8_t Rx_Flag = 0;
uint8_t Rx_Buffer[20];
uint8_t Dat_Buffer[1024];
3.在主循环前,使能串口接收
HAL_UART_Receive_IT(&usart1, (uint8_t *)Rx_Buffer, 1);
4.主循环
while(1)
{
        if(Rx_Flag == 1)
        {
                for(i = 0; i < Rx_Len; i++)
                {
                        printf("%c",Dat_Buffer[i]);                               
                }
                printf("\r\n");       
                Rx_Flag = 0;
                Rx_Len = 0;
                memset(&Dat_Buffrt,0,sizeof(Dat_Buffrt));                                       
        }
}


沙发
小灵通2018|  楼主 | 2018-11-6 16:21 | 只看该作者
5.回调函数的重定义
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)  //接收处理函数-存数据
{
       
                UNUSED(usart1);
                Dat_Buffer[Rx_Len] = (*((uint8_t *)Rx_Buffer));               
                if(Dat_Buffer[Rx_Len] == 'a')
                {
                        Rx_Flag = 1;
                }
                Rx_Len++;
                HAL_UART_Receive_IT(&usart1, (uint8_t *)Rx_Buffer, 1);
}

使用特权

评论回复
板凳
小灵通2018|  楼主 | 2018-11-6 16:23 | 只看该作者
调试中遇到的问题:使用串口助手快速发送大数据时,会发现串口回显的数据变少,
且继续用串口助手发送2字节数据时,发现串口不会回显,于是增加串口故障回调函数如下:
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)   //故障回调-查看故障状态
{
                printf("\r\n uart_status  %x\r\n",HAL_UART_GetState(&usart1));       
                printf("\r\n uart_error  %x\r\n",HAL_UART_GetError(&usart1));       
}

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

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

使用特权

评论回复
地板
小灵通2018|  楼主 | 2018-11-6 16:28 | 只看该作者
  HAL_UART_STATE_READY             = 0x20U,   /*!< Peripheral Initialized and ready for use
                                                   Value is allowed for gState and RxState */
  HAL_UART_ERROR_ORE       = 0x08U,    /*!< Overrun error       */

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

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

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

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

于是去看了中断函数HAL_UART_IRQHandler,发现
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  End ongoing Rx transfer on UART peripheral (following error detection or Reception completion).
  * @param huart UART handle.
  * @retval None
  */
static void UART_EndRxTransfer(UART_HandleTypeDef *huart)
{
  /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
#if defined(USART_CR1_FIFOEN)
  CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE));
#else
  CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
#endif
  CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

  /* At end of Rx process, restore huart->RxState to Ready */
  huart->RxState = HAL_UART_STATE_READY;
  
  /* Reset RxIsr function pointer */
  huart->RxISR = NULL;
}

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

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

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

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

使用特权

评论回复
5
八层楼| | 2018-11-7 10:08 | 只看该作者
很详细 排版很好

使用特权

评论回复
6
天灵灵地灵灵| | 2018-11-7 11:50 | 只看该作者
研究例程和手册就好懂了。

使用特权

评论回复
7
wakayi| | 2018-11-7 13:02 | 只看该作者
我也喜欢用hal库函数

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

116

主题

1442

帖子

4

粉丝