之前学习用的是Alientek MiniSTM32开发板,使用的开发环境可以通过特殊的配置集成printf函数,调试程序的时候不大喜欢用仿真器,最近项目开始使用单片机,只能够用UART1_Send(uint8_t * const tx_buf,uint16_t tx_num),真心有点不习惯没有printf函数的日子,程序调试的话最方便莫过于printf函数,于是开始研究如何在单片机中加入printf函数。
跟串口驱动相关的函数put_char(uint8_t data),需要根据不同的嵌入式平台做出相应的变动,因为put_char()函数只是发送一个字节的串口操作函数,所以基本原则是发送新的data字节A1之前需要检查该串口前一个发送字节A0是否已经发送完毕,只有A0已经发送完毕,才能够将新的字节数据A1写入串口发送寄存器中,同样A2的发送也需要等待A1发送完毕。
va_start()等定义在头文件stdarg.h、stdio.h、stdlib.h中,所以需要添加这些头文件,这些头文件均是编译器include路径下的,我这里使用的是IAR开发环境,一般情况下使用<>包含头文件,编译器时软件会自动在其安装目录下去搜索这些头文件,如果使用"x.h"则是在工程路径下去查找x.h文件
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdarg.h> 4 5 static void put_char(uint8_t data) 6 { 7 if (data == ‘/r‘) 8 put_char(0x09); 9 while ( !(UCSRA & (1<<UDRE)) ) // 不为空,等之 10 ; 11 UDR = data; //将数据传给串口发送寄存器 12 } 13 14 void my_printf(const char* fmt,...) 15 { 16 const char* s; 17 int d; 18 char buf[16]; 19 va_list ap; 20 va_start(ap,fmt); // 将ap指向fmt(即可变参数的第一个?下一个?) 21 while (*fmt) 22 { 23 if (*fmt != ‘%‘) 24 { 25 put_char(*fmt++); // 正常发送 26 continue; 27 } 28 switch (*++fmt) // next % 29 { 30 case ‘s‘: 31 s = va_arg(ap,const char*); // 将ap指向者转成char*型,并返回之 32 for (; *s; s++) 33 put_char(*s); 34 break; 35 case ‘x‘: 36 d = va_arg(ap,int); // 将ap指向者转成int型,并返回之 37 itoa(d,buf,16); // 将整型d以16进制转到buf中 38 for (s = buf; *s; s++) 39 put_char(*s); 40 break; 41 case ‘d‘: 42 d = va_arg(ap,int); 43 itoa(d,buf,10); // 将整型d以10进制转到buf中 44 for (s = buf; *s; s++) 45 put_char(*s); 46 break; 47 default: 48 put_char(*fmt); 49 break; 50 } 51 fmt++; 52 } 53 va_end(ap); 54 }
部分开发环境可能没有itoa()函数,这里从阿莫论坛找到了itoa()函数的原型,如果编译器提示找不到itoa函数,可以将下面的代码拷贝到上述printf函数所在的文件当中,该函数经测试可用。
1 char *itoa(int num,char *str,int radix) 2 { 3 /* 索引表*/ 4 char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 5 unsigned unum; /* 中间变量 */ 6 int i=0,j,k; /* 确定unum的值 */ 7 if(radix==10&&num<0) /* 十进制负数 */ 8 { 9 unum=(unsigned)-num; 10 str[i++]=‘-‘; 11 } 12 else 13 unum=(unsigned)num; /* 其他情况 */ /* 逆序 */ 14 do{ 15 str[i++]=index[unum%(unsigned)radix]; 16 unum/=radix; 17 }while(unum); 18 str[i]=‘\0‘; /* 转换 */ 19 if(str[0]==‘-‘) 20 k=1; /* 十进制负数 */ 21 else 22 k=0; 23 char temp; 24 for(j=k;j<=(i-1)/2;j++) 25 { 26 temp=str[j]; 27 str[j] = str[i-1+k-j]; 28 str[i-1+k-j] = temp; 29 } 30 return str; 31 }
最后就可以在主函数中,加入代码进行测试
uint8_t buffer[]="hello world";
uint8_t x=0x64;
my_printf("test %s,%d,0x%x\r\n",buffer,x,x);
最终输出结果是
test hello world,100,0x64
时间: 2024-10-29 19:34:18