正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-19.1讲 串口格式化输出printf

news2024/12/23 9:15:53

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第19 讲” 的读书笔记。第19讲主要是介绍I.MX6U处理器的UART串口并实现串口UART的字符格式化打印实验。本节将参考正点原子的视频教程第18讲和配套的正点原子开发指南文档进行学习。

0. 概述

上一章实验我们实现了 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. 实验程序编写

本章实验所需要移植的源码已经放到了开发板光盘中,路径为: 1、例程源码->5、模块驱动源码->2、格式化函数源码->stdio,文件夹 stdio 里面的文件就是我们要移植的源码文件。本章实验在上一章例程的基础上完成,将 stdio 文件夹复制到实验工程根目录中,如图 22.3.1 所示:

stdio 里面有两个文件夹: include 和 lib,这两个文件夹里面的内容如图 22.3.2 所示:

图 22.3.2 就是 stdio 里面的所有文件, stdio 里面的文件其实是从 uboot 里面移植过来的。后面学习 uboot 以后大家有兴趣的话可以自行从 uboot 源码里面“扣”出相应的文件,完成格式化函数的移植。这里要注意一点, stdio 中并没有实现完全版的格式化函数,比如 printf 函数并不支持浮点数,但是基本够我们使用了。

将正点原子提供的示例源码中的"stdio"文件夹放到本实验的 "14_printf" 目录中,然后修改Makefile 将移植的"stdio"目录放到编译源文件里。

3.1 Makefile编译错误1

执行 "make" 命令进行编译,此时编译器报如下错误提示:

 在正点原子的视频教程和指导文档里说明了解决此编译错误的方法是修改Makefile,在Makefile编译命令里加上如下编译选项 "-Wa,-mimplicit-it=thumb"【ARM 嵌入式 编译系列 2.3 -- GCC 编译参数学习 -Wa,-mimplicit-it=thumb 使用介绍】-CSDN博客文章浏览阅读750次,点赞12次,收藏8次。在使用编译 ARM 架构代码时,你可能会碰到一些控制汇编器行为的编译器选项。-wa是一个 GCC 编译器选项,用于向汇编器传递参数。-wa。_-wa,-mimplicit-it=thumbhttps://blog.csdn.net/sinat_32960911/article/details/135645189

$(COBJS) : obj/%.o : %.c
	$(CC) -Wall -nostdlib -fno-builtin -Wa,-mimplicit-it=thumb $(INCLUDE) -O2 -c -o $@ $<

 3.2 Makefile编译错误2

执行 "make" 命令进行编译,此时编译器报如下错误提示:

"__aeabi_uidiv" 用来实现ARM无符号数除法,编译链接器报错的是因为 ARM 是RISC精简指令集没有算术除法指令,所以在ARM裸机开发(也包括Uboot)里面的除法运算需要使用到 GCC 编译器提供的 libgcc.a 库里提供的ARM汇编除法函数实现。一般从uboot或者Kernel内核里能够找到ARM汇编除法函数的实现 "__aeabi_uidiv" 。

LIBPATH		:= -lgcc -L /home/dimon/I.MX6U/tool/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4/
#LIBGCCA		:= /home/dimon/I.MX6U/tool/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4/libgcc.a


$(TARGET).bin : $(OBJS)
	echo $(LD) $(TARGET).elf
#	$(LD) -Timx6u.lds  $(LIBPATH) -o $(TARGET).elf $^ $(LIBGCCA) 
	$(LD) -Timx6u.lds  -o $(TARGET).elf $^ $(LIBGCCA) $(LIBPATH)
	$(OBJCOPY) -O binary -S $(TARGET).elf $(TARGET).bin
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
#	$(OBJDUMP) -d -s -m arm $(TARGET).elf > $(TARGET).dis

注意这里经过我的测试发现 "$(LIBPATH)" 需要写在链接命令的最后,刚开始我将"$(LIBPATH)" 写在了链接命令的中间部分链接的时候编译器一直报错,即使我们修改Makefiel指定了链接路径。

div64.c:(.text+0x22): undefined reference to `__aeabi_uidiv'
make: *** [printf.bin] Error 1

 这里"$(LIBPATH)"在链接命令里先后顺序影响到最终链接结果是否成功的原因是和GCC LD 连接器的文件链接顺序机制有关系。在《程序员的自我修养-链接装载与库》中好像介绍过这一部分,印象中好像是先在链接.o文件的时候发现找不到某个符号,然后去搜索 "-Lxx -lxx" 指令的库文件中去搜索未定义的符号,如果先在链接命令里指定了"-Lxx -lxx"此时没有未定义符号的话就忽略掉了,记得号向是这样解释的。

好了,这里注意 "$(LIBPATH)" 需要写在链接命令的最后。

4. prinf格式化源码编写

移植好以后就要测试相应的函数工作是否正常,我们使用 scanf 函数等待键盘输入两个整数,然后将两个整数进行相加并使用 printf 函数输出结果。在 main.c 里面输入如下内容。

#include "cc.h"
#include "bsp_clk.h"
#include "bsp_led.h"
#include "bsp_delay.h"
#include "bsp_beep.h"
#include "bsp_gpio.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_exti.h"
#include "bsp_epittimer.h"
#include "bsp_keyfilter.h"
#include "bsp_delay.h"
#include "bsp_uart.h"
#include "stdio.h"


char *banner = 	"========================================================\r\n"
				"正点原子I.MX6ULL ALPHA/Mini开发板Linux驱动之ARM逻辑开发\r\n" \
				"--Date: 	2024/05/21\r\n" \
				"--Author: 	ChenHaoxu, Dimon.chen, 11813202388@qq.com\r\n" \
				"========================================================\r\n";



int main(void)
{

	static uint8_t led_state = OFF;
	// static uint8_t beep_state = OFF;

	int_init();			/* 中断初始化 */
	imx6u_clkinit();	/* 时钟主频初始化,PLL1, PLL2, PLL3 */
	clk_init();			/* 使能所有外设时钟 */
	led_init();			/* led gpio 初始化 */
	beep_init();		/* beep gpio 初始化 */
	//key_init();			/* key gpio 初始化 */
	exti_init();		/* gpio外设中断初始化 */

	//epittimer_init(0, 0, 33000000);	/* EPIT分频frac=0 1分频,EPIT1时钟源66MHz,EPIT1->LR加载值计数器=33MHz,定时周期为500ms */
	//epittimer_init(1, 0, 66000000/20);	/* EPIT分频frac=0 1分频,EPIT1时钟源66MHz,EPIT1->LR加载值计数器=33MHz,定时周期为1000/20=50ms */

	keyfilter_init();
	delay_init();
	uart_init();		/* UART初始化 */


	led_switch(LED_0, ON);


	beep_switch(ON);
	delay(200);
	beep_switch(OFF);
	delay(200);
	beep_switch(ON);
	delay(200);
	beep_switch(OFF);

	printf("%s", banner);

	unsigned int a = 10;

    while(1){
		led_state = !led_state;
		led_switch(LED_0, led_state);

		printf("Hello World\r\n");
		printf("a=%d hex=%x\r\n", a, a);

		scanf("%u", &a);
    }

    return 0;
}

5. 编译烧写SD卡验证实验结果

译修改主频后源码烧录SD卡验证本节的 I.MX6U UART串口实验。预期烧录SD卡后正点原子I.MX6ULL ALPHA/Mini 开发板后,UART串口可以在串口工具,如SecureCRT或者Xshell上打印字符串输出。

我本地验证的结果是基于GPT定时器的高精度延时实验结果正常,UART串口可以在串口工具XShell上打印字符串。

6. 总结和实验遇到的问题记录

本节移植了正点原子示例源码中的 printf 格式化打印函数,之后就可以在串口中实现字符串格式化打印来调试I.MX6U ARM 裸机开发板了,这样会方便很多。本节实验里遇到的问题主要是移植 printf 函数时的编译报错问题,需要修改Makefile解决,makefile修改方法在正点原子的教程里和网上博客里有多用说明,本文也记录了解决问题的详细步骤。

7. 结束

本文至此结束。


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1704503.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PHP:集成Xunsearch生成前端搜索骨架

如果是安装宝塔&#xff0c;我们在集成xunsearch的时候就会比较简单&#xff0c;后面我们在介绍其他的接入方式&#xff1b; 首先我们进入到宝塔管理后台&#xff1a;【软件商店】-【输入xun】-【点击xunsearch】直接安装即可 安装成功之后&#xff0c;会自动在www/server中创…

(delphi11最新学习资料) Object Pascal 学习笔记---第13章第4节 (内存管理和接口)

13.4 内存管理和接口 ​ 在第11章中&#xff0c;我介绍了接口的内存管理的关键要素。与对象不同&#xff0c;接口是受管理且具有引用计数。如我所提到的&#xff0c;接口引用会增加所引用对象的引用计数&#xff0c;但您可以声明接口引用为弱引用以禁用引用计数&#xff08;但…

Reactor模式Proactor模式

1.Reactor/Dispatcher模式 1.1 概述 Reactor模式下&#xff0c;服务端的构成为Reactor 处理资源池。其中&#xff0c;Reactor负责监听和分发事件&#xff0c;而处理资源池则负责处理事件。 该模式下的组合方案有下面几种(第三种几乎没有被实际应用)&#xff1a; 1 * Reacto…

AURIX TC3xx单片机介绍-启动过程介绍1

从各个域控制器硬件解决方案来看,MPU可能来自多个供应商,有瑞萨,有NXP等,但对于MCU来说,基本都采用英飞凌TC3xx。 今天我们就来看一下TC3xx的启动过程,主要包含如下内容: uC上电过程中,会经过一个上电时序,从复位状态“脱离”出来;Boot Firmware是复位后第一个执行的…

设计模式:原型模式(Prototype)

设计模式&#xff1a;原型模式&#xff08;Prototype&#xff09; 设计模式&#xff1a;原型模式&#xff08;Prototype&#xff09;模式动机模式定义模式结构时序图模式实现在单线程环境下的测试在多线程环境下的测试模式分析优缺点适用场景应用场景模式扩展应用实例实例 1&am…

SecureCRT for Mac注册激活版:专业终端SSH工具

SecureCRT是一款支持SSH&#xff08;SSH1和SSH2&#xff09;的终端仿真程序&#xff0c;简单地说是Windows下登录UNIX或Linux服务器主机的软件。 SecureCRT支持SSH&#xff0c;同时支持Telnet和rlogin协议。SecureCRT是一款用于连接运行包括Windows、UNIX和VMS的理想工具。通过…

user-agents,一个无敌的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个无敌的 Python 库 - user-agents。 Github地址&#xff1a;https://github.com/selwin/python-user-agents 在Web开发和数据分析中&#xff0c;了解用户的设备和浏览器信息是非常重要的。通过…

开发一个comfyui的自定义节点

文章目录 目标功能开发环境comfyui自定义节点的实现原理仓库地址完整代码目标功能 开发一个comfyui的自定义节点,该节点的功能是:可以对comfyui工作流中最终输出的图像添加一些自定义文案,且可以指定文案在图像上的位置、文案的字体样式、字体大小、字体颜色等。最终效果如…

Go语言之GORM框架(三)——Hook(钩子)与Gorm的高级查询

Hook(钩子) 和我们在gin框架中讲解的Hook函数一样&#xff0c;我们也可以在定义Hook结构体&#xff0c;完成一些操作&#xff0c;相关接口声明如下&#xff1a; type CreateUser interface { //创建对象时使用的HookBeforeCreate() errorBeforeSave() errorAfterCreate() …

小识MFC,一套设计优雅与不优雅并存的类库----小话MFC(2)

Q1&#xff1a; CPoint继承于POINT&#xff0c;这样有什么好处&#xff1f; A&#xff1a; 继承的一个最基本的好处当然就是减少代码量。CPoint和POINT内部数据一样&#xff0c;只是一个提供了更多的方法来操作对象。 typedef struct tagPOINT {LONG x;LONG y; } POINT, *P…

ARM IHI0069F GIC architecture specification (7)

3.1 GIC逻辑组件 GICv3体系结构由一组逻辑组件组成&#xff1a; •Distributor。 •每个受支持的PE都有一个Redistributor。 •支持的每个PE都有一个CPU interface。 •中断翻译服务组件&#xff08;ITS&#xff09;&#xff0c;支持将事件翻译为LPI。 Distri…

APM2.8飞控

ArduPilotMega 主控可应用于 固定翼、直升机、多旋翼、地面车辆 APM2.8飞控供电有两种 1.电流计供电&#xff0c; 2.带BEC&#xff08;稳压功能&#xff09;的电调供电 ArduPilotMega 内部的硬件结构图&#xff1a; 调试时&#xff0c;不要使用向导&#xff0c;由于向导功能不…

windows内存管理

一 windows系统的内存管理涉及哪些 1.1 虚拟内存管理机制 windows操作系统使用虚拟内存技术&#xff0c;将磁盘文件&#xff0c;通过映射对象&#xff08;存储在物理内存&#xff09;关联&#xff0c;映射到虚拟内存作为文件试图。即用户操作"虚拟内存中File View Objec…

卷出新高度,直呼太强!时隔三月,YOLO再度进化升级:《YOLOv10—实时端到端目标检测》重磅来袭

真的是不止一次感叹&#xff0c;学习的速度都跟不上发论文出新品的速度。。。。。 继前文YOLOv9发布以来也就不到三个月的时间&#xff0c;YOLOv10就来了&#xff01; 《太卷了&#xff0c;目标检测新成员——YOLOv9: Learning What You Want to LearnUsing Programmable Gra…

openflow协议抓包分析

1、准备实验拓扑&#xff1a; 在Mininet环境中创建一个简单的SDN拓扑&#xff0c;包括控制器、交换机、主机等。 确保拓扑能够正常运行&#xff0c;SDN交换机与控制器建立连接。 采用主机Ubuntu22.04主机&#xff0c;IP地址是192.168.87.130&#xff0c;安装opendaylight控制…

DreamerV3阅读笔记

DreamerV3 文章希望解决的一个挑战是用固定的hyperparameter来同时处理不同domain的任务。文章发现&#xff0c;通过结合KL balancing 和free bits可以使得world model learn without tuning&#xff08;是指上面这件事&#xff0c;即不需要对不同任务改变hyperparameter&#…

力扣239. 滑动窗口最大值

Problem: 239. 滑动窗口最大值 文章目录 题目描述思路复杂度Code 题目描述 思路 1.编写实现优先队列类&#xff1a; 1.1.实现push(int n):将元素n添加到队列尾&#xff0c;同时将n前面大于n的元素删除 1.2.实现int max():将队列头元素取出&#xff08;由于实现了push所以此时队…

【Python性能优化】取最值的差异

取最值的差异 测试Windows 测试结果Linux 测试结果 测试 测试内容&#xff1a;从一组 x, y, z 坐标值中获得每个维度&#xff08;x、y、z&#xff09;的值域范围。此处不考虑将数据临时存放到内存&#xff0c;再整组获取值域的操作&#xff08;因为对单文件这么做问题不大&…

多线程基本常识

多线程的状态 在Java中&#xff0c;一个线程的生命周期有以下几种状态&#xff1a; 新建&#xff08;New&#xff09;&#xff1a;当线程对象被创建时&#xff0c;线程处于新建状态。此时线程对象存在&#xff0c;但还没有调用start()方法启动线程。 运行&#xff08;Runnable…

Prometheus Operator创建告警规则并接入钉钉报警

prometheus之钉钉报警 前言1. 添加prometheus报警规则1.2 添加自定义报警规则文件 2. 配置钉钉报警2.2 部署dingding插件 3. 编写alertmanager配置文件 前言 在kubenetes上安装了kube-promethues&#xff08;包含Prometheus Operator&#xff09;,程序正常跑起来了&#xff0c…