最近正在学习usb,用的书是《圈圈教你玩USB》,发现上面实现的串口打印太麻烦了,打印个东东还要写好几行,受不了。所以觉定自己实现一个简单的printf,现在还没有弄清楚,单片机最大支持多大的hex,所以这个printf越简单越好,只需要包含必需的%x %d就可以了。
-
#include
-
#include "UART.h"
-
#define uint8 unsigned char
-
#define uint16 unsigned short int
-
#define Fclk 22118400UL /*使用22.1184M晶体*/
-
#define BitRate 9600UL /*波特率定义为9600*/
-
xdata uint8 buf[32];
-
volatile uint8 Sending;
-
//串口初始化
-
void InitUART(void)
-
{
-
EA=0; //暂时关闭中断
-
TMOD&=0x0F; //定时器1模式控制在高4位
-
TMOD|=0x20; //定时器1工作在模式2,自动重装模式
-
SCON=0x50; //串口工作在模式1
-
TH1=256-Fclk/(BitRate*12*16); //计算定时器重装值
-
TL1=256-Fclk/(BitRate*12*16);
-
PCON|=0x80; //串口波特率加倍
-
ES=1; //串行中断允许
-
TR1=1; //启动定时器1
-
REN=1; //允许接收
-
EA=1; //允许中断
-
}
-
-
void UartPutChar(uint8 d)
-
{
-
SBUF=d; //将数据写入到串口缓冲
-
Sending=1; //设置发送标志
-
while(Sending); //等待发送完毕
-
if( d == '\n')
-
UartPutChar('\r');
-
}
-
//将数n,按radix进制进行转换
-
char* itoa(uint8 n, uint8 *str,uint8 radix)
-
{
-
static uint8 X[16]={'0','1',
-
'2','3',
-
'4','5',
-
'6','7',
-
'8','9',
-
'A','B',
-
'C','D',
-
'E','F'
-
};
-
uint8 i=0;
-
uint8 j;
-
while(1)
-
{
-
if(radix==16)
-
str[i]=X[n%radix];
-
else
-
str[i]=n%radix+'0';
-
-
if((n/=radix)==0)
-
break;
-
++i;
-
}
-
for(j=0;j<(i+1)/2;++j)
-
{
-
char c=str[j];
-
str[j]=str[i-j];
-
str[i-j]=c;
-
}
-
return str;
-
}
-
//一个简单的printf
-
void my_printf(uint8 * fmt, ...)
-
{
-
uint8 d;
-
uint8 *s;
-
uint8 i;
-
va_list ap;
-
-
for(i=0; i<32;i++) //这儿先初始化然后再用,51不知道有没有直接定义在bss段的东东?
-
buf[i] = '\0';
-
va_start(ap, fmt);
-
while(*fmt)
-
{
-
if(*fmt != '%')
-
{
-
UartPutChar(*fmt++);
-
continue;
-
}
-
switch(*++fmt)
-
{
-
case 'x':
-
d = va_arg(ap, uint8);
-
itoa(d, buf, 16);
-
for(s=buf; *s; s++)
-
UartPutChar(*s);
-
break;
-
case 'd':
-
d = va_arg(ap, uint8);
-
itoa(d, buf, 10);
-
for(s=buf; *s; s++)
-
UartPutChar(*s);
-
break;
-
default:
-
break;
-
}
-
fmt++;
-
}
-
va_end(ap);
-
}
-
-
void UartISR(void) interrupt 4
-
{
-
if(RI) //收到数据
-
{
-
RI=0; //清中断请求
-
}
-
else //发送完一字节数据
-
{
-
TI=0;
-
Sending=0; //清正在发送标志
-
}
-
}
2. main.c
在main函数中加上打印 D12的chip_id
my_printf("my_printf ID 10 is %d\n", id);
my_printf("my_printf ID 16 is %x\n", id);
嗯,还不错,将就着用。
注意: my_printf中打印的buf 是这样定义的xdata uint8 buf[32];
如果不这样定义,就有可能会出现如下错误:
*** ERROR L107: ADDRESS SPACE OVERFLOW
SPACE: DATA
SEGMENT: ?DT?KEY
LENGTH: 0001H
*** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
SYMBOL: KEYCANCHANGE
SEGMENT: ?DT?KEY
Program Size: data=137.0 xdata=0 code=1178
原因应该是:51的ram最大支持128,刚学单片机,不太确定。
3. stdarg.h中对va_list的定义如下:
-
typedef char *va_list;
-
-
#define va_start(ap,v) ap = (va_list)&v + sizeof(v)
-
#define va_arg(ap,t) (((t *)ap)++[0])
-
#define va_end(ap)
这个va_list看起来就相当的简单明了,
3.1 a.(va_list)&v -- 取arg1在栈中的地址
b.(va_list)&v + sizeof(v) --- arg2=arg1+sizeof(v)
c 执行va_start 后ap指向了arg2
3.2 va_arg 做两步操作,
a. 返回当前所指的参数的值 (t*)ap[0]
b. ap移动指向下一个参数 ap++, 为下一次调用va_arg作准备
阅读(7356) | 评论(0) | 转发(0) |