单片机工程加入printf函数

之前学习用的是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-08-29 07:15:02

单片机工程加入printf函数的相关文章

IAR瑞萨单片机开发加入printf调试函数

IAR开发环境,没有printf函数,自己百度加入了一个(http://www.cnblogs.com/codecamel/p/4686437.html),但是还是有一些问题,特别是打印多个变量时,只能够打印字符串时比较稳定,原因是因为va_arg()给了错误的返回值,故只能找寻其他的方法,今天测试了一下,新的办法步骤如下 1.关键之处,否则会出现PUTCHAR函数未定义现象. 右键点击工程选择option-> General Option->ibrary configuration中libr

在C++工程中main函数之前跑代码的廉价方法(使用全局变量和全局函数)

[cpp] view plain copy // test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <crtdbg.h> /// 在C++工程中main函数之前跑代码的廉价方法 /// 利用全局变量可以赋可变初值的事实 /// mainCRTStartup() => _cin

DSP:CCS V6 TMS320F2812 使用printf函数

使用Code Composer Studio  Version: 6.1.1.00022,建立TMS320F2812工程. 1 /* 2 * main.c 3 */ 4 #include <stdio.h> 5 6 int main(void) { 7 printf("Hello DSP!\r\n"); 8 return 0; 9 } 添加了printf函数想测试一下,然后编译出错. 1 #10099-D</a> program will not fit int

【转】用宏定义代替printf函数

问题提出 有时候我们想用宏定义来决定是编译debug版本的代码还是release的代码,dubug版本的代码会通过printf打印调试信息,release版本的代码则不会.我们总不能对每一条printf都这样写: 1 #if _DEBUG_ 2 printf("hello world!"); 3 #endif 这样子实在是太麻烦了!万一要各个地方都要打印,会使版面看起来很乱. 解决方法 我后来想到一个方法,可以使用宏定义代替printf函数,由于printf是可变参数的函数,这里就要用

STM32 的 printf() 函数串口重定向(HAL库标准库都适用)

1.建立工程 2.核心:添加新文件usar_fputc.c (名字随便自己命名),把文件添加到项目中去 #include "stdio.h" #include "stm32f1xx_hal.h" extern UART_HandleTypeDef huart1; uint8_t ch; uint8_t ch_r; //重写这个函数,重定向printf函数到串口 /*fputc*/ int fputc(int c, FILE * f) { ch=c; HAL_UART

trueStudio中使用printf函数

1.通过printf输出浮点数需要如下设置: 在工程属性下找到C/C++ build->Settings->Tool Settings->C Linker->Miscellaneous->Other options 选项空中填写:-u_printf_float即可.到此为止TrueStudio即可支持printf的所有数据类型输出 2.在usart.c中添加如下函数即可让TrueStudio支持printf输出注意代码必须添加在USER CODEBEGIN x和USER CO

printf函数重定向

printf函数底层会调用fputc函数 /*重定向c库函数printf到USART1*/ int fputc(int ch, FILE *f) { /*发送一个字节数据USART1 */ USART_SendData(DEBUG_USART, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET); return (ch); }

对于printf函数和C语言编程的初步拓展

前面说过了,任何程序都要有输出,所以printf函数是一个很重要的函数,所以有必要在学变量之前先拓展一下. 其实编程就是用计算机语言说话,一句一句地说,只要语法没错就能运行,至于能实现什么功能,就看编程者的水平了. 那么看一下下面的代码 #include<stdio.h> int main(void) { printf("hello world"); printf("hello world"); return 0; } 你觉得运行的结果在屏幕上会显示什么

C的第一课printf函数的基本用法

printf函数: printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息. printf()函数的调用格式为: printf("<格式化字符串>", <参量表>). #include <stdio.h> /* printf函数 printf("<格式化字符串>", <参量表>) */ int main() { int i=8,j=6; int *p=NULL; char *nam