从keil的帮助文档里我们可以看到,printf
是基于putchar
实现的,所以我们只要重新实现putchar
,就可以实现printf
的重定向,即可以将printf
用在其他串口上。
putchar
的函数实现在…/C51/LIB下可以找到。
#include <reg51.h>
#define XON 0x11
#define XOFF 0x13
/*
* putchar (full version): expands '\n' into CR LF and handles
* XON/XOFF (Ctrl+S/Ctrl+Q) protocol
*/
char putchar (char c) {
if (c == '\n') {
if (RI) {
if (SBUF == XOFF) {
do {
RI = 0;
while (!RI);
}
while (SBUF != XON);
RI = 0;
}
}
while (!TI);
TI = 0;
SBUF = 0x0d; /* output CR */
}
if (RI) {
if (SBUF == XOFF) {
do {
RI = 0;
while (!RI);
}
while (SBUF != XON);
RI = 0;
}
}
while (!TI);
TI = 0;
return (SBUF = c);
}
我们来分析一下代码,首先我们先不管那两个if
判断,putchar
函数总是要执行的语句其实只有三句,首先先等待上一个数据发送完毕,将标志位置零以后,再发送下一个数据。这也解释了为什么我们在第一次调用printf
函数时要先把TI
置1,因为STC单片机复位以后TI
的值为0,直接调用printf
函数就会一直卡死在while(!TI)
里面了。
while(!TI);
TI = 0;
return (SBUF = c);
if(c == '\n')
部分是判断是否接收到换行符,如果接收到换行符以后,就会输出CR+LF。SBUF = 0X0d
是在输出CR,推测LF是在putchar
函数之外输出的。
最后if(RI)
部分是软件流控制。当接收端数据缓存区满了以后,就会向发送端发送XOFF
标志,发送端接收到XOFF
以后停止发送数据。接收端处理完数据以后,会向发送端发送XON
标志,表示可以继续发送数据。
使用流控制可以有效的防止数据传输过程中的丢失情况。
分析完官方的putchar
函数以后,我们需要自己写一个putchar
函数来调用串口3,这里要说明一下,如果我们的工程中包含了putchar
函数,编译器会优先使用我们所定义的函数,而不会去使用…/C51/LIB下的putchar
函数。
下面是我写的putchar
函数,因为没有那么高的要求,所以我并没有使用流控制,其次我的代码是先发送数据,再检测标志位,我认为这样做更符合我们平时的使用习惯。
char putchar(char c)
{
if (c == '\n')
{
S3BUF = 0x0d;
while (!(S3CON & S3TI)); //等待发送成功
S3CON &= ~S3TI;
/* output CR */
}
S3BUF = c;
while (!(S3CON & S3TI)); //等待发送成功
S3CON &= ~S3TI; //清除发送中断标志
return c;
}
我们只需要将这个putchar
函数包含在工程中,然后初始化串口3,便可以利用printf
打印串口了。