0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式系统简易版本的printf满足自己的需要

电子设计 来源:博客园 作者:佚名 2020-09-03 17:37 次阅读

嵌入式中,调试手段通常有两种,一是远程gdb,一是直接printf。如果是调试自己玩的小板子,用gdb有点大张旗鼓了,大多数情况下printf就可以搞定。不过printf的问题是stdiolib的size太大,稍微有点程序,加上几个常用的库,比如stdio和string,超过16k甚至32k(已经大于一些低端芯片的flash容量了)是很正常的事情,而且通常比较慢,程序越多,越麻烦。道理很简单,标准C语言库的规范中,Printf()必须处理大量的数据格式,包括字符串、字符、(各种长度的有符号和无符号)数字,以及浮点值。而且格式字符串还要包括用于更改文本对齐、基数、间距、字段宽度和精度的调节器和指示器。符合这个规范的代码必然会是冗长和繁重的。一些嵌入式系统库倒是提供了一些之针对整数的printf,但还是有问题,首先是还是太大,其次是你没有自己的调整权限。

其实printf也就是IO的调用包装而已,我们完全可以自己写一个简易版本的printf满足自己的需要,并随时根据需要裁剪。具体来说,printf在这里要起的作用就是将调试字符串从嵌入式目标空闲的串口压出,并在运行于宿主工作站的终端模拟器上显示结果。下面就简单介绍一下,如何来自己写一个简易printf函数。

要写printf,首先要知道什么是可变参数传递,我们来看看标准库里面,是如何定义可变参数实现的:

#define _AUPBND (sizeof (acpi_native_int) - 1)

#define _ADNBND (sizeof (acpi_native_int) - 1)

#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))

#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T,_AUPBND))) - (_bnd (T,_ADNBND))))

#define va_end(ap) (void) 0

#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) +(_bnd(A,_AUPBND))))

关于可变参数的原理,网上有一些文章,总结来说,就是我们可以通过Intel80×86机器的对齐特性来获得所有的参数,因为在Intel80×86机器上,每个变量的地址都要是sizeof(int)的倍数,这样能提升CPU运行的效率。也就是说,所有参数的首地址都要是4的倍数,就算你是char型的,那浪费3个byte也要安排你占第四个坑。

好,由于C语言传递参数时是用push指令从右到左将参数逐个压栈,因此我们通过栈指针跳4n格来访问第n个参数,不要忘了,参数的地址都是字对齐的。这里,我们用#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) &(~(bnd)))来计算类型为X的参数在栈中占据的字对齐后的字节数。bnd是sizeof (acpi_native_int) –1,acpi_native_unit在32位机的定义是:

typedef u32 acpi_native_uint;

所以( ~(bnd))就是0xfffffffc 。 因此,_bnd(X,bnd) 宏在32位机下就是

( (sizeof(X) + 3)&0xfffffffc )

很明显,其作用是–倘若sizeof(X)不是4的整数倍,将其变为4的整数倍。

va_start(ap,A) 负责初始化参数指针ap,将函数参数A右边第一个参数的地址赋给ap,这个第一个参数通常就是printf里面的”%x%d%f%d”。

va_arg(ap,T) 可以获得ap指向参数的值,并使ap指向下一个参数,T用来指明当前参数类型。

在这里,上述代码还是麻烦,而且sizeof我们也不能直接用,所以我们不如干脆直接写一个不那么麻烦而有针对性的可变参数操作定义:

有了这几个定义,print函数就好写了,为了节省空间,这个简单的print()只支持“%s”,“%d”和”%c”格式的分类符,暂时不需要其他功能,比如格式对齐之类的,当然,可以根据自己的需要扩展这个函数。

int print( const char *fmt, 。.. )

{

const char *s;

char c;

int d;

va_list ap;

va_start(ap, fmt);

while( *fmt != ‘\0’ )

{

if( *fmt != ‘%’ )

{

uart_putc(*fmt++);

continue;

}

switch(*++fmt)

{

case ‘s’:

{

s = va_arg(ap, const char *);

uart_puts(s);

break;

}

case ‘d’:

{

d = va_arg(ap, int);

uart_putints(d, 10);

break;

}

case ‘c’:

{

c = va_arg(ap, char);

uart_putc(c);

break;

}

default:

uart_putc(*fmt);

}

fmt++;

}

va_end(ap);

return 1;

}

这里面有一些函数,uart_putc是串口驱动程序,给串口送东西的,uart_puts是简单的多重putc包装。uart_putints则需要做一些atoi的转换,一个比较简单但是有效的atoi程序宏定义如下:

#define ATOI(X, result) \

do{ \

char *lptr = X; \

result = 0; \

while (1) \

{ \

if ((*lptr 》= ‘0’) && (*lptr 《= ‘9’)) \

{ \

result *= 10; \

result += *lptr - ‘0’; \

lptr++; \

} \

else \

{ \

break; \

} \

} \

}while(0)

责任编辑:gt

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    4981

    文章

    18274

    浏览量

    288351
  • C语言
    +关注

    关注

    180

    文章

    7528

    浏览量

    128428
收藏 人收藏

    评论

    相关推荐

    信号处理原理-简易版

    信号处理原理-简易版主要内容信号的分类与定义随机信号与确定性信号连续信号与离散信号周期信号与非周期信号确定性信号的特性时间特性频率特性时间与频率的联系确定性信号分析时域分析频域分析随机信号特性及分析 [hide][/hide]
    发表于 11-04 10:16

    什么是嵌入式系统

    ,尤其是用于便携的无线及移动的计算和通信设备中靠电池供电的嵌入式系统更是如此,如需要功耗只有mW甚至μW级。
    发表于 08-12 14:37

    在STM32F107上编写自己嵌入式系统需要学习哪些资料

    要求在STM32F107上编写自己嵌入式操作系统,想问问大家需要学习哪些资料,不知道哪些资料最适合自己编写
    发表于 01-31 10:12

    嵌入式小白怎么学嵌入式嵌入式入门需要哪些基础?

    LINUX和C了,有时一个产品里,这几种嵌入式系统同时存在,综合的组成一个完整的产品。如果自学可以看朱有鹏的视频,在学嵌入式之前,先全面的了解嵌入式,找准
    发表于 03-29 17:23

    嵌入式系统是什么 什么叫嵌入式系统

    技术密集、资金密集、高度分散、不断创新的知识集成系统。  3、嵌入式系统必须根据应用需求对软硬件进行裁减.满足应用系统的功能、可靠性、成本和
    发表于 04-20 14:13

    嵌入式系统是什么 什么叫嵌入式系统

    对软硬件进行裁减.满足应用系统的功能、可靠性、成本和体积等要求。为了提高执行速度和系统可靠性,嵌入式系统中的软件一般都固化在存储器芯片或微处
    发表于 06-29 15:55

    如何学习嵌入式系统

    这段时间很多关注者问起怎样学习嵌入式,对于一个刚开始接触嵌入式的朋友来说,这的确是个问题。在这里笔者就给大家讲讲怎样利用【IT指路灯】来学习嵌入式系统。  学习
    发表于 08-17 10:18

    FAT精减版(嵌入式应用的版本)--嵌入式FAT文件系统源码免费下载

    FAT精减版(嵌入式应用的版本)--嵌入式FAT文件系统源码免费下载本文件系统代码兼容FAT16/FAT32两种文件
    发表于 08-02 07:45

    嵌入式操作系统有哪些

    自己需要嵌入式系统。  其次,Linux具有强大的网络支持功能。Linux诞生于因特网并具有UNIX的特性,这就保证了它支持所有标准因特网协议,并且可以利用Linux的网络协议栈开发
    发表于 06-20 15:13

    什么是嵌入式系统

    系统的核心课程,或者就讲一下ARM编程基础;做嵌入式实验大部分也只是教学系统里现有的实验程序调出来运行验证一下结果,属于验证性实验,很多学生做完了实验都不知道自己做了什么。根本就没有机
    发表于 04-17 11:46

    如何满足嵌入式系统的灵活需求?

    嵌入式程序开发基本概念如何满足嵌入式系统的灵活需求开发高效程序的技巧是什么
    发表于 04-28 06:07

    单片机实现简易版shell的方法和原理是什么

    力气将其移植出来.于是我就自己写了一个类似于这样的插件.只需要把一对.c/.h文件加入到你的工程,就可以实现这个简易版的shell.git: https://github.com/KimAlittleS...
    发表于 12-09 07:27

    什么是嵌入式系统?深嵌入式系统又是什么

    和Android的系统也可以称为嵌入式系统。但是通常,这些通用操作系统需要应用程序处理器,并具有其他功能,例如动态应用程序加载。这就是为什么
    发表于 12-21 06:48

    嵌入式Linux中printf重定向到串口

    PC机上,printf输出到显示设备,在嵌入式linux系统,一般利用printf输出调试信息,需要重定向到串口。以AT91RM9200为例
    发表于 11-01 17:22 24次下载
    <b class='flag-5'>嵌入式</b>Linux中<b class='flag-5'>printf</b>重定向到串口

    单片机实现简易版shell的方法和原理

    单片机实现简易版shell的方法和原理
    发表于 11-26 09:36 0次下载
    单片机实现<b class='flag-5'>简易版</b>shell的方法和原理