Linux学习笔记18---串口格式化函数移植实验
上一章实验我们实现了 UART1
基本的数据收发功能,虽然可以用来调试程序,但是功能太单一了,只能输出字符。如果需要输出数字的时候就需要我们自己先将数字转换为字符,非常的不方便。学习 STM32
串口的时候我们都会将
printf
函数映射到串口上,这样就可以使用printf 函数来完成格式化输出了,使用非常方便。本章我们就来学习如何将
printf
这样的格式化函数移植到 I.MX6U-ALPHA
开发板上。
1、串口格式化函数简介
格式化函数说的是
printf
、
sprintf
和
scanf
这样的函数,分为格式化输入和格式化输出两类
函数。学习
C
语言的时候常常通过
printf
函数在屏幕上显示字符串,通过
scanf
函数从键盘获取
输入。这样就有了输入和输出了,实现了最基本的人机交互。学习
STM32
的时候会将
printf
映
射到串口上,这样即使没有屏幕,也可以通过串口来和开发板进行交互。在
I.MX6U-ALPHA
开
发板上也可以使用此方法,将
printf
和
scanf
映射到串口上,这样就可以使用
SecureCRT
作为开
发板的终端,完成与开发板的交互。也可以使用
printf
和
sprintf
来实现各种各样的格式化字符
串,方便我们后续的开发。串口驱动我们上一章已经编写完成了,而且实现了最基本的字节收
发,本章我们就通过移植网上别人已经做好的文件来实现格式化函数。
2、硬件原理分析
本章所需的硬件和上一章相同
3、实验程序编写
在网上下载好stdio文件,stdio
里面有两个文件夹:
include
和
lib
,这两个文件夹里面的内容如图
22.3.2
所示:
图 22.3.2
就是
stdio
里面的所有文件,
stdio
里面的文件其实是从
uboot
里面移植过来的。后面学习 uboot
以后大家有兴趣的话可以自行从
uboot
源码里面“扣”出相应的文件,完成格式化函数的移植。这里要注意一点,stdio
中并没有实现完全版的格式化函数,比如
printf
函数并不支持浮点数,但是基本够我们使用了。
移植好以后就要测试相应的函数工作是否正常,我们使用 scanf
函数等待键盘输入两个整数,然后将两个整数进行相加并使用 printf
函数输出结果。在
main.c
里面输入如下内容:
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "stdio.h"
/*
* @description : main函数
* @param : 无
* @return : 无
*/
int main(void)
{
unsigned char state = OFF;
int a , b;
int_init(); /* 初始化中断(一定要最先调用!) */
imx6u_clkinit(); /* 初始化系统时钟 */
delay_init(); /* 初始化延时 */
clk_enable(); /* 使能所有的时钟 */
led_init(); /* 初始化led */
beep_init(); /* 初始化beep */
uart_init(); /* 初始化串口,波特率115200 */
while(1)
{
printf("输入两个整数,使用空格隔开:");
scanf("%d %d", &a, &b); /* 输入两个整数 */
printf("\r\n数据%d + %d = %d\r\n\r\n", a, b, a+b); /* 输出两个数相加的和 */
state = !state;
led_switch(LED0,state);
}
return 0;
}
第
30
行使用
printf
函数输出一段提示信息,第
31
行使用函数
scanf
等待键盘输入两个整数。第 32
行使用
printf
函数输出两个整数的和。程序很简单,但是可以验证
printf
和
scanf
这两个函数是否正常工作。
4、编写 Makefile 和链接脚本
修改
Makefile
中的
TARGET
为
printf
,在
INCDIRS
中加入“
stdio/include
”,在
SRCDIRS中加入“stdio/lib
”,修改后的
Makefile
如下:
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= printf
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
LIBPATH := -lgcc -L /usr/lib/gcc-cross/arm-linux-gnueabihf/11
INCDIRS := imx6ul \
stdio/include \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep \
bsp/gpio \
bsp/key \
bsp/exit \
bsp/int \
bsp/epittimer \
bsp/keyfilter \
bsp/uart
SRCDIRS := project \
stdio/lib \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep \
bsp/gpio \
bsp/key \
bsp/exit \
bsp/int \
bsp/epittimer \
bsp/keyfilter \
bsp/uart
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
VPATH := $(SRCDIRS)
.PHONY: clean
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(LIBPATH)
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
$(SOBJS) : obj/%.o : %.S
$(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)
第
2
行修改变量
TARGET
为“
printf
”,也就是目标名称为“
printf
”。
第
7
行在变量
INCDIRS
中添加
stdio
相关头文件
(.h)
路径。
第
28
行在变量
SRCDIRS
中添加
stdio
相关文件
(.c)
路径。
第
37
行在编译
C
文件的时候添加了选项“
-Wa,-mimplicit-it=thumb
”,否则的话会有如下类似的错误提示:
thumb conditional instruction should be in IT block -- `addcs r5,r5,#65536'
链接脚本保持不变。
5、编译下载
使用 Make 命令编译代码,编译成功以后使用软件 imxdownload2 将编译完成的 printf.bin 文件生成可执行的img文件,命令如下:
make
./imxdownload2 printf.bin
如果 imxdownload2无权限,可用以下命令添加权限
chmod 777 imxdownload2
编译如图:

利用Win32DiskImager软件将load.img执行文件写入SD卡,SD卡插入开发板上即可正常运行。
烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板。打开一个串口助手,设置好相应的串口参数,连接上,根据提示
输入两个整数,使用空格隔开,输入完成以后按下“回车键”,结果如图
所示:

可以看出,输入了
23
和256
,这两个整数,然后计算出
23+256=279
。计算和显示都正确,说明格式化函数移植成功,以后我们就可以使用 printf
来调试程序了。
6、例程
【免费】Linux学习笔记18-串口格式化函数移植实验资源-CSDN文库