Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2120122
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2012-06-13 10:28:12

     最近正在学习usb,用的书是《圈圈教你玩USB》,发现上面实现的串口打印太麻烦了,打印个东东还要写好几行,受不了。所以觉定自己实现一个简单的printf,现在还没有弄清楚,单片机最大支持多大的hex,所以这个printf越简单越好,只需要包含必需的%x %d就可以了。

点击(此处)折叠或打开

  1. #include
  2. #include "UART.h"
  3. #define uint8 unsigned char
  4. #define uint16 unsigned short int
  5. #define Fclk 22118400UL         /*使用22.1184M晶体*/
  6. #define BitRate 9600UL         /*波特率定义为9600*/
  7. xdata uint8 buf[32];
  8. volatile uint8 Sending;
  9. //串口初始化
  10. void InitUART(void)
  11. {
  12.     EA=0;             //暂时关闭中断
  13.     TMOD&=0x0F;     //定时器1模式控制在高4位
  14.     TMOD|=0x20;     //定时器1工作在模式2,自动重装模式
  15.     SCON=0x50;     //串口工作在模式1
  16.     TH1=256-Fclk/(BitRate*12*16); //计算定时器重装值
  17.     TL1=256-Fclk/(BitRate*12*16);
  18.     PCON|=0x80;     //串口波特率加倍
  19.     ES=1;     //串行中断允许
  20.     TR1=1;     //启动定时器1
  21.     REN=1;     //允许接收
  22.     EA=1;     //允许中断
  23. }

  24. void UartPutChar(uint8 d)
  25. {
  26.     SBUF=d; //将数据写入到串口缓冲
  27.     Sending=1;     //设置发送标志
  28.     while(Sending); //等待发送完毕
  29.     if( d == '\n')
  30.         UartPutChar('\r');
  31. }
  32. //将数n,按radix进制进行转换
  33. char* itoa(uint8 n, uint8 *str,uint8 radix)
  34. {
  35.     static uint8 X[16]={'0','1',
  36.         '2','3',
  37.         '4','5',
  38.         '6','7',
  39.         '8','9',
  40.         'A','B',
  41.         'C','D',
  42.         'E','F'
  43.     };
  44.     uint8 i=0;
  45.     uint8 j;
  46.     while(1)
  47.     {
  48.         if(radix==16)
  49.             str[i]=X[n%radix];
  50.         else
  51.             str[i]=n%radix+'0';

  52.         if((n/=radix)==0)
  53.             break;
  54.         ++i;
  55.     }
  56.     for(j=0;j<(i+1)/2;++j)
  57.     {
  58.         char c=str[j];
  59.         str[j]=str[i-j];
  60.         str[i-j]=c;
  61.     }
  62.     return str;
  63. }
  64. //一个简单的printf
  65. void my_printf(uint8 * fmt, ...)
  66. {
  67.     uint8 d;
  68.     uint8 *s;
  69.     uint8 i;
  70.     va_list ap;

  71.     for(i=0; i<32;i++) //这儿先初始化然后再用,51不知道有没有直接定义在bss段的东东?
  72.         buf[i] = '\0';
  73.     va_start(ap, fmt);
  74.     while(*fmt)
  75.     {
  76.         if(*fmt != '%')
  77.         {
  78.             UartPutChar(*fmt++);
  79.             continue;
  80.         }
  81.         switch(*++fmt)
  82.         {
  83.             case 'x':
  84.                 d = va_arg(ap, uint8);
  85.                 itoa(d, buf, 16);
  86.                 for(s=buf; *s; s++)
  87.                     UartPutChar(*s);
  88.                 break;
  89.             case 'd':
  90.                 d = va_arg(ap, uint8);
  91.                 itoa(d, buf, 10);
  92.                 for(s=buf; *s; s++)
  93.                     UartPutChar(*s);
  94.                 break;
  95.             default:
  96.                 break;
  97.         }
  98.         fmt++;
  99.     }
  100.     va_end(ap);
  101. }

  102. void UartISR(void) interrupt 4
  103. {
  104.     if(RI) //收到数据
  105.     {
  106.         RI=0; //清中断请求
  107.     }
  108.     else //发送完一字节数据
  109.     {
  110.         TI=0;
  111.         Sending=0; //清正在发送标志
  112.     }
  113. }
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的定义如下:

点击(此处)折叠或打开

  1. typedef char *va_list;

  2. #define va_start(ap,v) ap = (va_list)&v + sizeof(v)
  3. #define va_arg(ap,t) (((t *)ap)++[0])
  4. #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作准备

阅读(7251) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~