注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
q2113435929的个人空间 https://home.eeworld.com.cn/space-uid-650223.html [收藏] [复制] [分享] [RSS]
日志

Linux平台下UT4412BV03裸机开发指南(七)

已有 721 次阅读2015-10-16 15:16 |个人分类:开发板| Linux 开发, 4412, 开发板, arm

Linux平台下UT4412BV03裸机开发指南(七)

 

第一章 移植printfscanf功能第一节 移植的途径

对于如何移植printfscanf,我们有许多选择:

1) 移植linuxprintk功能,版本越新越难移植,但是功能也越强大;

2) 移植ubootprintfscanf功能,实际uboot也是从linux内核中移植而来的;

3) 完全自己编写,但是功能比较弱;

 

在保证整个裸机其他代码部分没有任何问题,且编译器也没有任何问题的情况下,上述三种方法都是可行的。下面我们只是直接利用网友从linux中移植好的printk,为我们的裸机代码增加上该部分功能。

第二节 移植步骤

第一步解压printf.rar6.uart_stdio目录,解压成功后会多出include lib两个目录,其中include放的是相关头文件,lib放的是printfscanf相关的代码。

第二步修改6.uart_stdio目录下的makefile,将lib目录下的代码编译链接成lib.a,然后将lib.a编译进bin中,具体修改见源码。

第三步编写main函数进行测试。

第三节 程序相关讲解

完整代码见目录6.uart_stdio,与前一章的代码相比,代码多了includelib目录以及main.c的内容被修改了。

1. main.c

int main (void)

{

int a = 0;

int b = 0;

char *str = "Hello World";

uart_init();

printf("%s\n\r", str);

 

while(1)

{

printf("Please enter two number: \r\n");

scanf("%d %d",&a, &b);

printf("\r\n");

printf("The sum is: %d\r\n", a+b);

}

return 0;

}

main函数先打印出"Hello World"接着打印Please enter two number:然后接受输入2个数值,最后将两个数值的和输出PC机。

2. lib/printf.c

int printf(const char *fmt, ...)

{

int i;

int len;

va_list args;

 

va_start(args, fmt);

len = vsprintf(g_pcOutBuf,fmt,args);

va_end(args);

for (i = 0; i < strlen(g_pcOutBuf); i++)

{

putc(g_pcOutBuf[i]);

}

return len;

}

 

<2>printf函数是个变参函数,什么是变参函数

可变参数函数的原型声明为type VAFunction(type arg1, type arg2,  ); 参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,声明时用"..."表示。固定参数和可选参数公同构成一个函数的参数列表。

 

<3> printf函数涉及了3个十分重要的宏:

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

 

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

 

3: #define va_end(ap) (void) 0 

在这些宏中,va 就是 variable argument(可变参数)的意思; ap:是指向可变参数表的指针; A:指可变参数表的前一个固定参数; T:可变参数的类型。 va_list 也是一个宏,其定义为 typedef char * va_list,实质上是一char型指针。

 

<4>三个宏的作用:

1) va_start 宏作用

根据v取得可变参数表的首指针并赋值给ap,方法:最后一个固定参数A的地址 + 第一个变参对A的偏移地址,然后赋值给 ap,这样 ap 就是可变参数表的首地址。

举例:

 

如果有变参函数的声明是 void va_test(char a, char b,char c, ),则它的固定参数依次是 a,b,c,最后一个固定参数为 c,因此就是 va_start(ap, c)

2) va_arg 宏作用

指取出当前 ap 所指的可变参数并将 ap 指针指向下一可变参数。

3) va_end 宏作用

结束可变参数的获取。va_end ( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与 va_start 对应。

 

<5>得到可变参数个数的三种办法:

1) 函数的第一个参数,指定后续的参数个数, func(int num,...)

2) 根据隐含参数,判断参数个数, printf 系列的,通过字符串中%的个数判断;

3) 特殊情况下(如参数都是不大于 0xFFFF  int),可以一直向低处访问堆栈,直到返回地址。

 

有了上述知识我们就可以看懂printf()函数的内容了,首先va_start(args, fmt);会将可变参数的首地址保存在args中,然后调用vsprintf(g_PCOutBuf,fmt,args)进行处理,在vsprintf()中,会调用va_arg()逐个的取出变参,然后进行解析。如果是普通字符则无须转换,直接保存在g_PCOutBuf;如果是字符串,则从可变参数表中拿到指向字符串的指针,将字符串的内容拷贝到g_PCOutBuf;如果是数字,则调用number函数进行处理,并把解析的结果存放在g_PCOutBuf。所有,最后只调用putC函数把g_PCOutBuf里的字符一个个的打印出来就可以了。scanf函数的原理和printf类似,这里不再进行解释

第四节 编译代码和烧写运行

sd卡插入PCUbuntu终端执行如下命令:

#cd 6.uart_stdio

#make

# sudo ./sd_fusing.sh /dev/sdb bl2.bin

第五节 实验现象

sd卡插入UT4412BV03中,选择sd卡启动,然后上电。

我们输入7和8

按下Enter键

 

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章