IAR中文网站 > 热门推荐 > IAR库函数重定向怎么实现 IAR库函数重定向后打印输出为什么异常
IAR库函数重定向怎么实现 IAR库函数重定向后打印输出为什么异常
发布时间:2026/06/04 13:39:48

  在嵌入式工程里,经常得把printf打印的信息送到串口、调试终端或者日志缓存区里去,而不是让它留在控制台上。那么,IAR里面的库函数重定向到底该怎么实现,还有重定向之后打印输出为什么会出问题,这些事的关键,就是先要搞清楚工程用的是哪一个运行库,然后再把底层的输出接口给补上。在IAR的DLIB运行环境下,标准的输入和输出都会被交给一组底层的函数去处理,也就是说,printf和fputc这两个函数,到了最后都会去调用__write这个函数,把字符一个一个地发出去。

  一、IAR库函数重定向怎么实现

 

  给库函数做重定向,是用不着去动printf源代码的。平常比较常见的做法,就是在工程里头新加一个专门负责串口重定向的文件,在这个文件里面把__write函数给写好,这样一来,所有标准输出要打印的东西,都会被转发到已经配置好的串口上面去。

 

  1、先确认工程用的是DLIB运行库

 

  要到工程的设置界面里面,去查一下当前选的是什么样的运行库。IAR提供了一套叫DLIB的运行环境,并且还允许按照项目的实际需要,去配置文件描述符、多字节字符,还有其他一些功能。如果只是想做普通的串口日志,其实是没必要去重新编译完整的运行库的,只要把最底层用来输出的那个函数给替换掉就行了。

 

  2、在工程里新加一个底层的输出函数

 

  往工程里面放一个专门用来重定向的文件,在里头把__write这个函数给实现出来。这个函数会接收三个参数,一个是文件句柄,一个是装着字符的缓冲区,还有一个就是缓冲区的长度,收到这些参数之后,再挨个字节地去调用串口的发送函数,把数据送出去。通常情况下,标准输出和标准错误这两个路径,都可以被指向同一个串口,如果后面需要把不同级别的日志分开来,也只要在上层多做一些处理就好。

 

  3、万一要用到输入功能,就要再补上__read函数

 

  要是整个工程不光要打印日志,还打算用上scanf、getchar,或者搞一些命令行的交互功能,那就还得接着去实现一个__read函数,这个函数的作用,就是把从串口那边接收到的数据,再传回给程序的标准输入。如果工程目前只是用来往外打印信息的,那输入这部分可以先放在一边,暂时不用去管它。

 

  4、一定要先把串口配置好,然后才能去做打印

 

  跟串口有关的那些时钟、引脚的复用关系、通信的波特率,还有发送状态的寄存器,这些全都得在第一次调用printf之前就准备好。要是程序在一开始启动的阶段就需要打印一些日志,那就应该去确认一下,串口初始化的顺序,是不是排在了业务模块初始化的前头。

 

  二、IAR库函数重定向后打印输出为什么异常

 

  把重定向做完以后,如果发现打印完全没有输出、打出来的字符全是乱码、换行的效果看起来不对劲,或者整个程序直接就卡在那里不动了,一般都不是printf函数自己坏掉了,而是因为底层发送数据的方式、调试环境里的配置,又或者是串口的参数不太对。

 

  1、检查一下是不是还在用C-SPY那种模拟输出的方式

 

  IAR本身是支持由C-SPY这个调试工具在电脑主机这一头,来模拟标准的输入和输出的,一旦开了这个功能,打印的内容就会跑到调试终端里面去。官方文档里面也说过,如果用户自己已经写了一个__write函数,那原来那种通过C-SPY Terminal I/O来输出的办法,就不会再照着以前的方式工作了。因此,如果想要看到串口吐出来的信息,就应该去接上一个真实的串口终端,不要光盯着IDE里面的那个窗口看。

  2、仔细核对一下波特率和系统的时钟

 

  当串口里面跑出来的是乱码的时候,最先要去看的,就是双方约定好的波特率、每一个数据帧里面的数据位、停止位,还有整个系统的主时钟频率,这些参数是不是都能对得上。如果在程序运行的过程当中,主频被调整过了,而负责给串口分频的那个参数却没有跟着一起更新,那么打印出来的内容马上就会乱掉。

 

  3、留意一下__write函数的返回值

 

  底层的发送操作全部完成以后,需要往上层返回一个数字,告诉它这次到底成功写出去了多少个字节。要是这个返回值一直给的是零,或者是一个负数,又或者跟实际传出去的长度对不上,那么标准库那边就很可能会认为这次的输出动作已经失败了,这样一来,后面的内容再送过来,也就都会跟着一起出问题。

 

  4、看看换行符的处理是不是合适

 

  有一些串口的终端工具,在只收到一个换行符的情况下,是不会自动把光标挪回这一行的最开头的。如果发现打印出来的文字在屏幕上形成了一种像楼梯一样的排列,那就可以在发送那个换行符之前,再额外多发一个回车符,让输出的时候统一采用回车加上换行的这种格式。

 

  三、IAR打印输出异常怎么继续排查

 

  打印的功能倒是能出来一些东西,但偶尔会丢掉几个字符、卡住一下,或者浮点数的显示不正常的时候,就还得再往下看一看发送的机制、调用的位置,还有运行库本身的一些配置。

 

  1、尽量不要在中断服务函数里面做大量的打印

 

  用那种阻塞方式的串口来发送数据,本身就会吃掉不少执行的时间,要是在中断里面连续地去调用printf,甚至还有可能会影响到那些对实时性要求很高的任务。IAR的文档里面也提醒过,标准库里的一部分功能,其实是不适合被并发着来调用的。相比之下,更加稳妥的一种办法,就是先把需要输出的日志写到一块环形的缓冲区里面去,然后再由后台的一个任务,找机会慢慢地往外发送。

 

  2、区分一下阻塞式发送和非阻塞式发送

 

  如果串口的发送函数是靠着中断或者DMA的方式来跑的,那就得去确认一下,在数据还没有被彻底发送完之前,发送用的那块缓冲区有没有被别的地方给提前改写掉。要是底层的发送函数刚刚把数据提交出去,就立刻返回了,而上层的那块缓冲区紧跟着又被写进了新的内容,那么串口上打出去的东西,就会出现缺字,或者内容串在一块儿的现象。

 

  3、检查一下库对格式化的支持程度

 

  如果打印整数的时候一切正常,偏偏只有浮点数死活都显示不出来,那就要去查一下运行库的配置、它对格式化的支持选项,还有链接的时候有没有漏掉什么东西。另外,像%d、%f这些格式占位符,也要跟后面跟着的那个变量的类型保持一致,不要到头来把类型不对的问题,错当成了是串口出了毛病。

 

  4、不妨先拿一个最小的测试来试一试

 

  刚开始的时候,可以先只输出一行很简单又不会变动的字符串,等这一步成功了以后,再依次去试整数、换行、比较长的字符串,还有连续不停地往外打印。每一次只多增加一种情况,这样就能比较快地判断出来,问题到底是出在串口的初始化上头、__write这个函数的实现里面,还是因为多个任务抢着调用造成的。

  总结

 

  IAR里面库函数的重定向到底是怎么做出来的,以及重定向做完了之后打印输出为什么还是会不正常,这里面最关键的一点,就是要靠__write这个函数,把标准的输出通道,给对接到真实的硬件接口上去。在把重定向实现了以后,应该按着顺序去检查运行库的配置、C-SPY模拟输出、串口的各项参数、函数的返回值、换行符的格式,还有数据发送的时机这些地方。等到系统里面的日志量慢慢变大了以后,再去考虑加上缓冲区和后台发送的机制,这样就能防止打印功能反过来去干扰主程序本身的运行。

135 2431 0251