打印
[应用相关]

STM32 CubeMx 串口输出乱码问题总结

[复制链接]
157|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
  笔者最近在拿到了个新的板子,MCU是意法半导体的STM32H723VGT6,板载晶振是24MHz。个人习惯拿到新板子先打印个hello world,于是CubeMx启动。

        配置串口1异步模式,波特率115200,其余保持默认。



        Debug选SW,RCC用外部高速时钟HSE,接着配置时钟树如下。



        为了方便进行串口重定向,使用ARM-MDK工具链,接着是Keil 磺ision5启动。首先在点击魔术棒,勾选使用微库以便对printf重定向至串口。



        接着打开 usart.c,在最后面添加将 fputc 重定向至串口。并在 usart.h 中将 stdio.h 头文件包含进来(对应位置看注释)。

/*        uart.h        */
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */



/*        uart.c        */
/* USER CODE BEGIN 1 */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
    return ch;
}
/* USER CODE END 1 */



        接着便可以直接使用 printf 打印并用串口助手查看了。

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    printf("hello world\r\n");
    HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */



        事与愿违,打开串口助手查看结果如下。



        如图所示收到了乱码,那么显然波特率应该是哪里有点问题,但是我们CubeMx配置的明明是115200,从 usart.c 中也可以看到,波特率确确实实是 115200。



        究竟是哪里有问题呢?我们需要先想明白问题是什么,接着再找是什么的问题。为了方便排查,我们打印十六进制数据看看。我们修改代码输出个0x01和0x11。

  /* USER CODE BEGIN WHILE */
  uint8_t data[] = {0x01};
  while (1)
  {
//          printf("hello world\r\n");
        HAL_UART_Transmit(&huart1, data, 1, HAL_MAX_DELAY);
        HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */



        串口助手输出结果如下,01输出结果为80,由于上面已经推测出波特率有问题,我们这个数据又比较特殊。根据串口低位先行,盯帧一下可以做出猜想,是不是实际波特率减半了?



        于是开个逻辑分析仪看看数字波形,如下所示,可以看到开始位后,确确实实是发了个高电平1,符合低位先行。可以看到高电平持续时间大概是17.35us,换算比特率就是57636,接近57600,好像符合我们猜想?



        那么,我们直接将波特率设置为57600,可以看到逻辑分析仪的数据也对上了。



        接着使用 printf 输出字符串继续验证。将串口助手的波特率改为 57600,终于正确打印出了我们预期的字符串。



        于是我们弄清楚了问题:实际波特率和设置的波特率差了一半。为什么呢?通过查找手册,可以找到串口1挂载在 APB2 总线上。



        查看CubeMX时钟树也可以看见,USART1、6、9、10这里都用的是 PCLK2,根据配置是120MHz。



         我们检查一下串口的时钟源对不对。

  /* USER CODE BEGIN WHILE */
  printf("hello world\r\n");
  while (1)
  {
          uint32_t uart_clk_source = __HAL_RCC_GET_USART1_SOURCE();
          switch(uart_clk_source)
                {
                        case RCC_USART1CLKSOURCE_D2PCLK2:
                                printf("USART1 clock source: PCLK2\n");
                                break;
                        case RCC_USART1CLKSOURCE_PLL2:
                                printf("USART1 clock source: PLL2\n");
                                break;
                        case RCC_USART1CLKSOURCE_PLL3:
                                printf("USART1 clock source: PLL3\n");
                                break;
                        case RCC_USART1CLKSOURCE_HSI:
                                printf("USART1 clock source: HSI\n");
                                break;
                        case RCC_USART1CLKSOURCE_CSI:
                                printf("USART1 clock source: CSI\n");
                                break;
                        case RCC_USART1CLKSOURCE_LSE:
                                printf("USART1 clock source: LSE\n");
                                break;
                        default:
                                printf("USART1 clock source: unknown\n");
                }
          HAL_Delay(2000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}



        输出结果如下,可以看到确实是PCLK2。



        接着我们检查一下各个时钟的频率是否正确。

  /* USER CODE BEGIN WHILE */
  printf("hello world\r\n");
  while (1)
  {
        uint32_t sysclk = HAL_RCC_GetSysClockFreq();
        uint32_t hclk = HAL_RCC_GetHCLKFreq();
        uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();

        printf("SYSCLK: %d MHz\n", sysclk/1000000);
        printf("HCLK:         %d MHz\n", hclk/1000000);
        printf("PCLK2:         %d MHz\n", pclk2/1000000);
          
        HAL_Delay(2000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }



      ​​​​

        可以看到,SYSCLK和HCLK均一致,但是PCLK2明明我们配置的是120MHz,而获取到的却是240MHz。为什么呢?对于波特率 Baud = f_PCLK2 / 16 x div,div的值分别以整数和小数部分存储在BRR的低十六位中,通过Debug设断点查看BRR的值。



        可以看到BRR=0x823,其中0x82是整数部分,0x3是小数部分,所以 div = 130.1875。按照获取到的时钟频率 240 MHz计算得波特率为115200,但是实际的波特率却是115200/2=57600;按照设置的时钟频率 120 MHz计算可得波特率为57600,但是实际获取的时钟频率却是240MHz。

        加之笔者的CubeMx是刚更新的6.13.0(本来更新的是最新版的6.14.0因为不能联网而回退到1.13),至此开始怀疑是CubeMx生成的代码有问题(试过FW使用1.11.2和1.12.0均有问题),可能其中有几步并没有正确配置到。

        于是换回低版本的6.10.0,FW使用1.11.1,按照最开始的流程,运行结果如下,一切顺利。



        此外,还试了一下用6.13的cubemx和1.11.1的FW包生成代码,问题同前面所述。
        综上,新版本的CubeMx(6.13)可能不太稳定,想要稳定运行的话可以用稍微旧一些版本的CubeMx,但是旧版本的CubeMx又不支持CMake工具链,新版本又不稳定。也是陷入死循环了。。。

        至于前面所说问题的深层次原因,笔者水平有限无法给出进一步解答,欢迎大家指正。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_63034630/article/details/148452069

652726847c8b36a0eb.png (308.81 KB )

652726847c8b36a0eb.png

使用特权

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

本版积分规则

53

主题

150

帖子

0

粉丝