[smart210] 裸板移植printf()与scanf()的步骤

发布者:CelestialMagic最新更新时间:2024-12-12 来源: cnblogs关键字:smart210  printf()  scanf() 手机看文章 扫描二维码
随时随地手机看文章

平台:smart210


CPU:S5PV210


目标:在smart210裸板上移植stdio(标准输入输出)的两个核心函数,printf()与scanf()。


知识储备:


1.这里我们直接从主目录下的Makefile分析移植所需要的一系列操作


CC      = arm-linux-gcc

LD      = arm-linux-ld

AR      = arm-linux-ar

OBJCOPY = arm-linux-objcopy

OBJDUMP = arm-linux-objdump


INCLUDEDIR     := $(shell pwd)/include

CFLAGS         := -Wall -O2 -fno-builtin

CPPFLAGS       := -nostdinc -I$(INCLUDEDIR)


export     CC AR LD OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS 


objs := start.o main.o uart.o clock.o lib/libc.a


stdio.bin: $(objs)

    ${LD} -Tstdio.lds -o stdio.elf $^

    ${OBJCOPY} -O binary -S stdio.elf $@

    ${OBJDUMP} -D stdio.elf > stdio.dis


.PHONY : lib/libc.a

lib/libc.a:

    cd lib; make; cd ..

    

%.o:%.c

    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<


%.o:%.S

    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<


clean:

    make clean -C lib

    rm -f *.bin *.elf *.dis *.o


关键点在于stdio.bin,是我们最终生成的二进制文件,它依赖于start.o,main.o,uart.o,clock.o与lib/libc.a这些文件,其中.o的来源是经过arm-linux-gcc -c -o 命令生成的,libc.a是通过进入lib目录下静态编译生成的库文件,为什么要使用静态编译,主要是因为我们所需要的printf()和scanf()移植依赖于linux内核提供的内核函数,而我们现在是属于裸板无操作系统的状态下,即使采用动态编译成功生成了.bin文件,也无法在裸板开发板上运行。所以,我们需要手动建一个库,把linux内核支持的printk()函数的相关.c .h文件经过修改后都移植过来,于是我们采用了静态编译的方法生成libc.a库(可以注意到CPPFLAGS带了-nostdinc选项的意思就是不使用标准库,即不动态链接标准库,而是采用当前主目录下的include文件夹里面的.h)。在main.c程序里面包含的“stdio.h'文件里,我们能发现如下代码


extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);

extern int snprintf(char * buf, size_t size, const char *fmt, ...);

extern int vsprintf(char *buf, const char *fmt, va_list args);

extern int sprintf(char * buf, const char *fmt, ...);

extern int vsscanf(const char * buf, const char * fmt, va_list args);

extern int sscanf(const char * buf, const char * fmt, ...);


extern void putc(unsigned char c);

extern unsigned char getc(void);


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

int scanf(const char * fmt, ...);


这说明了一系列与printf()和scanf()相关的子函数都是外部函数,在编译器在链接的时候,就能把libc.a里面的各.o文件内的相关函数链接过来。强大的链接器帮我们把各个独立的.o文件根据函数名(地址)链接起来,生成链接文件elf,该文件又可以进一步改造成适用于开发板使用.bin文件!

2.从/lib/Makefile分析lib/libc.a库文件的生成


objs := div64.o lib1funcs.o ctype.o muldi3.o printf.o string.o vsprintf.o


libc.a: $(objs)

    ${AR} -r -o $@ $^

    

%.o:%.c

    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<


%.o:%.S

    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<


clean:

    rm -f libc.a *.o


可知,libc.a文件依赖于div64.o lib1funcs.o ctype.o muldi3.o printf.o string.o vsprintf.o ,由于采用了主目录下的Makefile所输出的CPPFLAGS与CFLAGS配置,届时arm-linux-cpp在编译.c文件的时候,就会自动跑去主目录的include库下去找需要的函数了。这些.o文件中,最核心的是printf.o,对应的.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;

}




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

{

    int i = 0;

    unsigned char c;

    va_list args;

    

    while(1)

    {

        c = getc();

        putc(c);

        if((c == 0x0d) || (c == 0x0a))

        {

            g_pcInBuf[i] = '';

            break;

        }

        else

        {

            g_pcInBuf[i++] = c;

        }

    }

    

    va_start(args,fmt);

    i = vsscanf(g_pcInBuf,fmt,args);

    va_end(args);


    return i;

}


拿printf()做分析,我们能发现程序内容先对变参数进行处理,把我们输入给printf的每一个参数都做字符串分析,比如%d和数字之类的,然后拷贝对应参数变量的值结合第一个字符串参数里的指令输出到g_pcOutBuf这个字符缓冲区里面,最后循环调用我们的串口单字符打印函数putc()来输出。最终我们就达到了printf()的使用效果了!而scanf()也是类似的!


关键字:smart210  printf()  scanf() 引用地址:[smart210] 裸板移植printf()与scanf()的步骤

上一篇:[smart210] Nand Flash K9F4G08U0B 的配置与读写控制(一)
下一篇:[smart210] UART设置与编程

推荐阅读最新更新时间:2026-03-21 11:34

STM32重定向C库printf/scanf
参考例程 ///重定向c库函数printf到串口,重定向后可使用printf函数 int fputc(int ch, FILE *f) { /* 发送一个字节数据到串口 */ USART_SendData(DEBUG_USART, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return (ch); } ///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数 int fgetc(FILE *f) { /* 等待串口输入数据
[单片机]
Smart210学习记录-------linux驱动中断
Linux中断 Linux 的中断处理分为两个半部,顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操 作。tasklet 和工作队列都是调度中断底半部的良好机制,tasklet 基于软中断实现。内核定时器也 依靠软中断实现。 1.申请和释放中断 申请中断 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) irq 是要申请的硬件中断号。 handler 是向系统登记的中断处理函数(顶半部),是一个回调函数,中断发生时,系统调用 这个函数, dev_i
[单片机]
Smart210学习记录------paltform总线
1、概述: 通常在Linux中,把SoC系统中集成的独立外设单元(如:I2C、IIS、RTC、看门狗等)都被当作平台设备来处理。 从Linux2.6起,引入了一套新的驱动管理和注册机制:Platform_device和Platform_driver,来管理相应设备。 Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver进行注册。 Linux platform driver机制和传统的device_driver机制相比,一个十分明显的优势在于platform机制将本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform_devic
[单片机]
Smart210学习记录----nand flash驱动
当读写文件请求到来的时候,流程如下   1.通过vfs进入文件系统,   2.文件系统把文件读写转换为块设备读写,其中有运用算法对读写操作进行合并,排序等,最后把块设备读写放进队列   3.循环从队列中取出读写要求,然后用处理函数(blk_init_queue设置)进行处理。    这个函数就是连接上层(IO调度)跟底层(硬件操作)的桥梁,当我们调用add_mtd_partitions的时候,就建立了上下层的联系。   4.对不同的处理要求,调用不同的nand的底层处理函数 nand flash驱动代码: #include linux/module.h #include linux/types.h #in
[单片机]
<font color='red'>Smart210</font>学习记录----nand flash驱动
[smart210] 通过PLL设置各时钟频率的方法以及代码注释
平台:smart210(tiny210v2) CPU:S5PV210 目标: 设置APLL (提供MSYS domain 与DSYS domain 下各时钟的来源,最高1Ghz) 设置MPLL(提供MSYS domain 与DSYS domain 下各时钟的来源,最高2Ghz) 设置EPLL(Audio相关时钟) 设置VPLL(Video相关时钟,54Mhz) 知识储备: 1. MSYS主要为CPU,DRAM控制器,3D,IRAM,IROM,中断控制器等提供时钟 DSYS主要为显示相关部件FIMC,FIMD,JPEG,Multimedia IPs提供时钟 PSYS为外设I2S,SPI,I2C,UART等提供时钟 2.
[单片机]
[<font color='red'>smart210</font>] 通过PLL设置各时钟频率的方法以及代码注释
[smart210] UART设置与编程
平台:smart210 CPU:S5PV210 目标:通过官方文档【S5PV210_UM_REV1.1.pdf】,获取UART设置的相关信息,进一步学习UART编程 1.通过搜索UART,在P853找到该芯片的串口功能介绍 1. 摘取关键点,我们能够知道,210提供了4个UART接口,支持中断模式或者DMA(直接存储器访问)模式,每个UART包含有两个FIFO缓冲区(读与写),当然每个UART通道所支持的最大FIFO缓冲区也是有限制的,其中UART0支持256字节,UART1支持64字节,UART2与UART3各支持16字节的缓冲区。 2. 然后就是串口常见的波特率、停止位、校验位、帧宽、等设置,其中波特率来源于PCLK
[单片机]
[<font color='red'>smart210</font>] UART设置与编程
[smart210] 定时器与PWM
平台:smart210 CPU:s5pv210 目标:学习如何配置定时器timer,实现PWM输出功能以及利用定时器产生中断 知识储备:s5pv210有5个定时器,其中定时器0,1,2,3具有PWM输出功能,均有专门的引脚作为输出。而定时器4是内部定时器,不具备输出引脚。 该CPU的定时器,所需要配置的寄存器并不多,主要有TCON(Timer Control),TCFG0(Timer Configuration 0),TCFG1(Timer Configuration 1),TCNTBn(Timer n Counter Buffer),TCMPB(Timer n Compare Buffer),TCNTOn(Timer n Cou
[单片机]
[<font color='red'>smart210</font>] 定时器与PWM
基于clion的野火stm32标准库开发(printf打印已解决)
1、教程说明 最近花了一些时间,重新学习野火stm32f4的1.8标准库视频,跟着火哥一起用keil5软件敲代码,还是用不习惯,就想着用clion折腾下标准库开发,顺便学习下重温cmake的用法。 这里只说明基于nucleo f4板子标准库开发的一些注意事项,使用野火教程的模板。 下面是成品图: 1_成品图 2、教程准备 这里参考稚晖君的教程,把clion的环境配好。 配置CLion用于STM32开发 【优雅の嵌入式开发】 以及 网页链接 up主的标准库 网页链接 3、注意使用 (1)外设驱动库文件 这里我们参考标准外设库STM32F4xx_DSP_Std
[单片机]
基于clion的野火stm32标准库开发(<font color='red'>printf</font>打印已解决)
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved