返回列表 发新帖我要提问本帖赏金: 20.00元(功能说明)

[MM32软件] IAR使用printf函数后MCU挂掉了,看我如何解决的^^

[复制链接]
2312|17
 楼主| xld0932 发表于 2023-2-21 09:59 | 显示全部楼层 |阅读模式
本帖最后由 xld0932 于 2023-2-21 10:01 编辑

#申请原创#   @21小跑堂

做嵌入式(MCU)软件开发的小伙伴,对IAR的EWARM集成开发环境都不陌生,我之前都是使用的IAR EWARM 8.32版本的,使用也一直很稳定,有好长时间没有去关注和更新新的IAR EWARM版本了……最近突然心血来潮,更新到IAR EWARM 9.30.1版本,发现之前的项目工程突然都不灵了!!!咋回事呢???

回退到IAR EWARM 8.32版本,原先的项目工程依旧可以正常运行,但切换到IAR EWARM 9.30.1版本后,程序就卡在一半不执行了;经过一点一点的分析(在线调试、单步运行)后,发现竟然卡在了最常用的printf函数这里了……

对于要实现printf函数的功能,除了在工程配置时,需要增加_DLIB_FILE_DESCRIPTOR这个宏定义之外还需要重载一下fputc这个底层函数,当然也要初始化对应的打印串口参数哈:
  1. /***********************************************************************************************************************
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Initialize console for printf
  3.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]   none
  4.   * @param  Baudrate : UART2 communication baudrate
  5.   * @retval none
  6.   *********************************************************************************************************************/
  7. void PLATFORM_InitConsole(uint32_t Baudrate)
  8. {
  9.     GPIO_InitTypeDef GPIO_InitStruct;
  10.     UART_InitTypeDef UART_InitStruct;

  11.     RCC_APB1PeriphClockCmd(RCC_APB1ENR_UART2, ENABLE);

  12.     UART_StructInit(&UART_InitStruct);
  13.     UART_InitStruct.BaudRate      = Baudrate;
  14.     UART_InitStruct.WordLength    = UART_WordLength_8b;
  15.     UART_InitStruct.StopBits      = UART_StopBits_1;
  16.     UART_InitStruct.Parity        = UART_Parity_No;
  17.     UART_InitStruct.HWFlowControl = UART_HWFlowControl_None;
  18.     UART_InitStruct.Mode          = UART_Mode_Tx;
  19.     UART_Init(UART2, &UART_InitStruct);

  20.     UART_Cmd(UART2, ENABLE);

  21.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  22.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_1);

  23.     GPIO_StructInit(&GPIO_InitStruct);
  24.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_2;
  25.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  26.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
  27.     GPIO_Init(GPIOA, &GPIO_InitStruct);
  28. }

  29. /***********************************************************************************************************************
  30.   * @brief  Redefine fputc function
  31.   * @note   For printf
  32.   * @param  ch
  33.   * @param  f
  34.   * @retval ch
  35.   *********************************************************************************************************************/
  36. int fputc(int ch, FILE *f)
  37. {
  38.     UART_SendData(UART2, (uint8_t)ch);

  39.     while (RESET == UART_GetFlagStatus(UART2, UART_FLAG_TXEPT))
  40.     {
  41.     }

  42.     return (ch);
  43. }

代码一丝丝都没修改过,不可能会有问题哈……

最后还是查看IAR的帮助文档,发现从IAR EWARM 9.3版本之后,要实现printf函数不是重载fputc这个函数了,而是需要重载__write这个函数,通过帮助文档里给出的示例代码作参考,尝试了一下:
  1. /* Files include */
  2. #include <stddef.h>
  3. #include <LowLevelIOInterface.h>

  4. /***********************************************************************************************************************
  5.   * @brief  redefine __write function
  6.   * @note   for printf
  7.   * @param  handle
  8.   * @param  *buf
  9.   * @param  bufSize
  10.   * @retval nChars
  11.   *********************************************************************************************************************/
  12. size_t __write(int handle, const unsigned char *buf, size_t bufSize)
  13. {
  14.     size_t nChars = 0;

  15.     /* Check for the command to flush all handles */
  16.     if (-1 == handle)
  17.     {
  18.         return (0);
  19.     }

  20.     /* Check for stdout and stderr (only necessary if FILE descriptors are enabled.) */
  21.     if ((_LLIO_STDOUT != handle) && (_LLIO_STDERR != handle))
  22.     {
  23.         return (-1);
  24.     }

  25.     for (/* Empty */; bufSize > 0; --bufSize)
  26.     {
  27.         UART_SendData(UART2, *buf);

  28.         while (RESET == UART_GetFlagStatus(UART2, UART_FLAG_TXEPT))
  29.         {
  30.         }

  31.         ++buf;
  32.         ++nChars;
  33.     }

  34.     return (nChars);
  35. }

此时再使用IAR EWARM 9.30.1版本软件进行编译、下载后,项目代码终于可以正常运行了……这个printf功能卡脖子有问题终于解决了!!!

那在代码中我如何判断当前IAR的版本是8.32还是9.30呢?在IAR编译器中提供了这样两个宏,一个是__ICCARM__,这个表示当前使用的IAR EWARM编译器环境,另外一个是__VER__,它可以判断当前编译器的软件版本号,这样我们就可以通过这两个宏来判断,我们在实现printf函数时,是需要重载fputc函数还是__write函数了,做到项目工程的兼容,不会再出现上述问题导致的MCU卡住了!


打赏榜单

21小跑堂 打赏了 20.00 元 2023-02-24
理由:恭喜通过原创审核!期待您更多的原创作品~

评论

心思缜密,条分缕析,剖析根源,解决难题  发表于 2023-2-24 10:29
yangxiaor520 发表于 2023-2-22 07:38 来自手机 | 显示全部楼层
不错的经验分享,点个赞。
EPTmachine 发表于 2023-2-24 14:03 | 显示全部楼层
写的很好,以后可以少走一个坑
Innercourage 发表于 2023-2-27 08:55 | 显示全部楼层
不错的经验分享,点个赞
zchong 发表于 2023-2-27 12:34 | 显示全部楼层
也中招了,不晓得iar为啥要改动这个,
tpgf 发表于 2023-3-2 09:25 | 显示全部楼层
为什么高版本的反而不能默认支持这个函数呢
qcliu 发表于 2023-3-2 09:48 | 显示全部楼层
有可能也是习惯问题 不过确实更加喜欢使用低版本的
drer 发表于 2023-3-2 10:10 | 显示全部楼层
大家一直用的很习惯的函数重载 为什么版本更新后就更改了函数了呢
coshi 发表于 2023-3-2 10:47 | 显示全部楼层
看来每个版本更改之后我们有必要看一下相关说明文档啊
kxsi 发表于 2023-3-2 11:10 | 显示全部楼层
我比较发愁的就是 总不能我换版本的时候还都要详细对比一下区别啊
wiba 发表于 2023-3-2 11:23 | 显示全部楼层
kxsi 发表于 2023-3-2 11:10
我比较发愁的就是 总不能我换版本的时候还都要详细对比一下区别啊

这确实是一个问题 好在这个坑楼主已经填上了
10299823 发表于 2023-3-2 16:03 | 显示全部楼层
重新写fput不行吗?              
everyrobin 发表于 2023-3-2 16:12 | 显示全部楼层
IAR和keil的printf不一样 。
geraldbetty 发表于 2023-3-4 21:53 | 显示全部楼层
串口的配置的吗?              
deliahouse887 发表于 2023-3-7 20:18 | 显示全部楼层
单片机怎么会挂掉的?              
mattlincoln 发表于 2023-3-7 20:37 | 显示全部楼层
串口的配置的吗?              
Undshing 发表于 2023-3-9 18:38 | 显示全部楼层
可能高版本;有更好的函数替换了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部