给嵌入式ARM+Linux的初学者

时间:2021-02-03 19:10:30
本文写给已经听过或接触过嵌入式并对此产生兴趣,可是对于嵌入式觉得无从下手的初学者。
 
0. 为什么要写这篇
   我以前读研的时候选过一门嵌入式ARM的选修课,课程在实验室中进行,每个同学一个ARM开发板,老师一边讲,学生一边进行操作。课程的内容大致有,硬件、ARM和linux简介,编写并编译一个C文件,下载到开发板中运行,搭建qt开发环境,编写一个qt的程序,下载到开发板上运行。期末的时候再*发挥,设计一个小游戏或者计算器之类的小工具。
   这个流程的设计实际上是很合理的,符合由浅入深的认知过程。然而我自己在学这门课的时候,却学得很迷茫,对于很多操作觉得很费解。最让我觉得难以忍受的地方就是linux的指令。老师把指令写在黑板上,我们照着黑板在键盘上输入,然后看结果。问题是,我既不知道指令的作用,也不知道执行结果是什么意思,虽然英语早就过了六级(由此证明,六级真是扯,和英语能力一点关系也没有),孤立的单词也能看懂,可是除了明显的successfully和failed,其它一概看不懂。更要命的是,我完全不知道指令中哪里需要加空格,哪里不能加空格,有时指令中还多出来一个”-“,更让我费解了。
   那时课堂上不能上网,有了疑问也先憋着,因为课堂节奏实在太快了,我仅仅来得及输入指令并抄在笔记上,字迹挺潦草,等到下课了我再想去查指令,发现我自己也认不得我写的到底是什么了。就这样糊里糊涂的过了这门课。但是有几个关键词在我脑中留下了深刻印象:linux,arm,交叉编译,QT,超级终端,虽然不甚了解,但终于面熟了。心中留下了对嵌入式的征服欲望还有一丢丢的畏惧感。
   后来经历了一些机缘巧合(和武侠小说或者RPG游戏差不多:捡到本书,接了个小任务,初出江湖,巴拉巴拉。。。),一年后的某一天,顿悟了。现在嵌入式的学习资料唾手可得,可是我依然看到很多嵌入式初学者遇到了和我当初一样的困惑,为什么觉得困惑,很大一部分原因,就是看不懂(也有可能是文章太长有畏惧感)。我想以初学者的视角来介绍我们即将涉及的内容。不要期望本文成为一篇技术资料。本文的目的是帮助初学者理解嵌入式ARM,解除一些疑惑,能看懂别的技术资料。 
1. 什么是ARM
   一种微处理器的简称,从早期的ARM1系列发展到ARM11,ARM11以后的产品用Coretex命名。ARM也是一个公司的名称,ARM公司既不生产也不销售芯片,它只出售芯片技术授权。
   摩托罗拉、飞利浦、三星等等公司都生产ARM系列芯片,三星公司的S3C6410(ARM11)和S5PV210等(Coretex-A8)在国内的开发板领域(当然还有手机、平板领域)得到了最广泛的应用。
2. 什么是Linux和Ubuntu
   Linux是一套开源的免费使用和*传播的类Unix操作系统,它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。
   Linux操作系统存在着许多不同的版本,比如大家比较熟悉的Ubuntu、RedHat、Fedora等,但它们都使用了Linux内核。Linux可安装在各种计算机硬件设备中,比如手机、平板电脑、路由器、视频游戏控制台、台式计算机、大型机和超级计算机。
   严格来讲,Linux这个词本身只表示Linux内核,但实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 各种工具和数据库的操作系统。 
3. 交叉编译工具arm-linux-gcc
3.1 什么是交叉编译
   这里又要引入两个名词:宿主机(Host),和目标机(Target)。开发板由于硬件所限不能直接在本地建立起开发环境,需要在配置高的个人电脑上开发完软件后再移植到开发板上运行。此处的开发板就是Target,个人电脑就是Host。
   简单来说,交叉编译就是在一个平台上生成另一个平台上的可执行代码。由于Target和Host的平台不一样(平台包括体系结构,最直观的就是CPU不一样,一个是x86,另一个是ARM,使用的汇编语言都不一样),不能使用Host的编译工具,而需要在Host中安装Target的编译工具链(cross compilation tool chain),来编译得到的运行于Target上的可执行代码。
3.2 arm-linux-gcc的版本
   我们最常用的交叉编译工具就是arm-linux-gcc,和arm-linux-g++,分别用于编译C文件和C++文件。早些年安装arm-linux-gcc交叉编译工具对于一个嵌入式新手来说特别棘手,因为它需要安装多个软件包,每个软件包都有它的依赖关系,安装过程中不能有半点差错(真庆幸我没赶上那些年)。现在我们购买开发板时,厂家都提供对应的交叉编译工具,安装非常方便。
   理论上讲,某一个特定型号的CPU会有特定的arm-linux-gcc与之对应,采用不同CPU的开发板之间的程序是不能用同一个交叉编译工具的(比如全志A20开发板的工具编译得到的程序就不能在S3C6410开发板上执行)。但是也有特殊情况,前两天就发现了一个。友善之臂S3C6410(ARM11)开发板提供的编译工具编译的一个小程序可以在S5PV210 (Coretex-A8)开发板上运行。不过反过来S5PV210开发板提供的编译工具编译的小程序就不能在S3C6410开发板上运行。
   这个现象倒是挺好解释,学过51单片机的同学可能有体会,用51编译的程序可以在52单片机上执行,但是52编译的程序在51上就不一定能执行(尤其当使用了52特有的寄存器时在51上执行肯定不能有预期结果)。
   CPU不是唯一影响arm-linux-gcc版本使用的,linux内核也可能有一定影响。比如天嵌的6410CoreA开发板和6410CoreB开发板,两者的CPU都是S3C6410(尾缀不一样),但是采用的linux内核版本不一样,用CoreA的编译工具编译CoreB的linux内核的时候就会出错(这些错误提示一度把我的方向带偏,google了大量文章去试验都没能解决,想想这些都是厂家提供的应该不会有问题呀,最后忽然想到换个厂家最近更新的编译工具试试,成功了)。
   所以我推测,目前网络上常见的arm-linux-gcc版本,比如4.5,4.7还有早期的3.3什么的,实际上是开发板厂家针对自己特定CPU、linux内核版本的开发板制作出来的,对于库有一定的依赖关系,严格来讲是不能任意跨开发板使用的。至于为什么友善之臂、天嵌、飞凌的编译工具(甚至包括QT在内的整个开发环境)都能在某些开发板上无差别使用,那就太好理解了,友善之臂、天嵌、飞凌之类的先头部队做完了攻坚任务,其他的厂家把软件包弄到手,再抄个板还不容易吗?一样一样的。
   最后总结一句,建议所有打算长期做嵌入式的初学者,每当换一个开发板,就要从头开始搭建开发环境,包括交叉编译工具,linux内核,qt等等,不要让这些版本问题成为你以后的隐患。磨刀不误砍柴功,相信我,没错的。
4. 超级终端和SecureCRT
   接触了Ubuntu的同学应该知道,linux中的操作大多是命令行的,这些命令输入到终端(Terminal)窗口,并在终端的窗口中显示结果。(终端和控制台差不多一个意思)
   开发板的LCD默认是不作为终端的显示窗口的,终端的信息通过COM0(串口0)来输出,需要借助Host(个人电脑)来进行人机交互。将开发板的COM0通过串口线连接到Host的串口上,打开Host机上的超级终端,在它们的窗口中会显示终端信息,并且可以在超级终端中键入指令。从用户体验上来讲,超级终端除了窗口粗糙了点外,使用起来和Ubuntu中的Terminal差不多。(开发板借了Host的屏幕来显示自己的信息,所以说超级终端这个名字起的挺对路的)
   SecureCRT和超级终端都是串口工具,一样的作用。XP自带超级终端,WIN7没有。
5. 串口传输工具sz和rz
   当在Host中交叉编译完可执行代码之后,需要将其传送到Target(目标板)上来执行。这时就需要用到一个小工具rz。rz是 Receive files by Zmodem,Zmodem是协议。开发板必须安装了这个工具,你才可以使用。如果没有安装,你使用时会提示你找不到命令“Command not found”。
   如果开发板没有安装这个工具,那就需要你安装一下。自己先下载一个rz的源代码,用arm-linux-gcc来编译一下,再拷贝到开发板中的/bin或者/usr/bin下就可以了。(具体方法见串口传输工具sz和rz的安装与使用 )那么问题就来了,rz就是用来将Host中文件传送到开发板中,现在为了能使用rz需要把rz传送到开发板上,那怎么传送rz呢?先用U盘吧(具体方法见U盘中文件复制到ARM开发板 
   用U盘和rz都可以传送文件。U盘的优点是传送速度快,适合传大文件,缺点是每次都要插拔,还要在命令行输入挂载和取消挂载的指令,操作啰嗦。rz的优点是无需另外接线,操作简单,缺点是传送速度慢,尤其是传送几十兆的大文件时真是让人难以忍受。其实另外还有个挂载nfs的方式,需要用到交叉网线,将虚拟机的上网方式改成桥接方式,并且需要开启相关服务,不适合初学者操作,本文就不讲了。
   sz是Send files by Zmodem,这个就无需多言了。
6. Linux常用指令
   Linux中的指令实际上都是可执行程序,这些可执行程序放在某些路径下(Ubuntu中显示的是蓝色的带齿轮的菱形图标),当你使用某个指令的时候,Linux(实际上是shell)就到这些路径下去找对应的程序来执行。这些指令通常放在/bin或者/usr/bin下。通常/bin中放的是基本指令,/usr/bin中放的是你自己make install 或者 apt-get install得到的工具。我们习惯性的把交叉编译工具放在/opt下,shell默认是不会在此路径下寻找arm-linux-gcc的,你需要先设置一下环境变量export PATH=…..(具体见。。。。),shell才知道要到此路径下去找。
6.1 指令格式
   Linux中的指令语法大致为:command  [选项1] [参数1] [选项2] [参数2]
命令、选项和参数之间用空格隔开。
   根据要实现的命令功能不同,选项的个数和内容也不同,大多数命令选项可以组合使用,命令选项有短格式和长格式的。短格式就是单个英文字母,选项是使用“ -”符号(半角减号符)引导开始选项,字母可以是大写也可以是小写。如 ls -a。长格式的命令选项使用英文单词表示,选项前用“--”(两个半角减号符)引导开始的。如 --abc --xyz。
   参数:是命令处理的对象,通常情况可以是文件名、目录、或用户名。
   []表示可选。如果不选,就使用默认的。
6.2 常用指令
6.2.1 解压缩: # tar –xzvf 源文件 -C 路径名
    把源文件用gzip方式解压到-C后面指定的路径下,也可以不写“-C 路径名”,那么就解压到当前路径下。注意压缩包的后缀,是否为.tgz或者.gz,否则不能选项中不能用z。详细参数说明:
  -v 详细报告tar处理的文件信息。如无此选项,tar不报告文件信息。
  -x 从档案文件中释放文件。
  -f 使用档案文件或设备,这个选项通常是必选的。
  -z 用gzip来压缩/解压缩文件,加上该选项后可以将档案文件进行压缩,但还原时也一定要使用该选项进行解压缩。
  -j 代表使用‘bzip2’程序进行文件的压缩。     
6.2.2 列出目录(文件或文件夹):  # ls [路径名]
    列出指定路径下的文件或文件夹。不写路径名的时候就是列出当前路径下的文件和文件夹。
6.2.3 进入目录(文件夹):  # cd 路径名
    退出到上一级目录:  # cd ..   (注意cd后面有空格,后面是两个半角的句号)。    
6.2.4 拷贝:  # cp 路径1/源文件 路径2/目标文件
    将路径1下的源文件复制到路径2下,目标文件名没写的话就和原来名字一样。
6.2.5 执行文件:  # ./文件名
    注意./之后没有空格,这几乎是linux指令中唯一不带空格的
6.2.6 修改权限:  # chmod 777 文件名
6.2.7 建立路径(文件或文件夹):  # mkdir 路径名
6.2.8 编译文件:  # gcc –o 目标文件 源文件
    源文件为.c文件,如果不写“-o 目标文件”则默认编译得到的文件名是a.out