嵌入式开发初探_第1页
嵌入式开发初探_第2页
嵌入式开发初探_第3页
嵌入式开发初探_第4页
嵌入式开发初探_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、3.1 嵌入式Linux软件开发工具下面将介绍开发嵌入式Linux应用软件所用到的一些常用工具,包括编辑工具vi、编译工具gcc、MakeFile文件及调试工具gdb。 使用vi编辑器vi作为UNIX世界里极为普遍的全屏幕文本编辑器,几乎可以说任何一台UNIX机器都会提供这个软。当然作为UNIX家族的一份子的Linux也不会例外。Linux下虽然已经发展处许多更新、更加好用的文本编辑器,但是却不一定每一台机器上都提供了这些额外的安装软件。所以,掌握了vi的编程,那我们可以在各种不同的机器上得心应手的操作。这种编辑器还有一大好处是所有的命令按键都在手指范围内,手不必离开主键盘就可输入所有命令。v

2、i的原意是“Visual”,它是一个立即反应的编辑程序。值简单地执行“vi”指令就可以进入vi的编辑环境。vi有3种状态,即可视命令模式、冒号命令模式及文本编辑模式。一般当进入vi时,会首先进入可视命令方式,这是vi的启动默认模式。在这种模式下用户输入的任何内容都被认为是编辑命令。如按下“i”键就进入插入方式,可从光标左侧输入文本;如按下“a”键就进入添加方式,可以在光标右侧输入文本。在冒号命令方式下,所有命令都要以“:”开始,所输入的字符系统均作命令来处理,如输入“:q”代表退出,“:w”表示存盘。进入文本编辑模式,这时用户可以进行所有文本的编辑操作。在文本编辑模式下,按下Esc键就可以回到

3、命令状态。无论是创建新文件或修改旧文件,都可以使用vi,所需指令为:vi filemane如果文件是新的,就会在屏幕底部看到一个信息,告诉用户正在创建新文件。如输入命令:vi /tmp/test。若是新文件,就应该看到如图所示信息:图 用vi命令创建文件经vi创建的事例文件,一行开始处的波折号“”表示文件这一行是空行。如果文件早已存在,vi则会显示文件的前24行中的内容。这时用户就可以使用下列命令进入编辑模式:² 指令按键“i”:在光标处前面插入正文,光标后的文字随追加的文字向后移动。² 指令按键“I”:在光标所在行开始处插入正文。² 指令按键“a”:在光标所在位

4、置后面追加正文,光标后的文字随追加的文字向后移动。² 指令按键“A”:在光标所在行行尾追加正文。² 指令按键“o”:在光标所在行下面新开一行,并进入编辑状态。² 指令按键“O”:在光标上面新开一行,并进入编辑状态。下面对一些基本命令加以解释:(1)光标命令。² k、i、h、l:上、下、左、右光标移动命令。虽然也可以在L,inux中使用键盘右边的4个光标键,但是这4个命令还是非常有用的,因为这4个键正是右手在键盘上放置的基本位置。 ² nG:跳转命令。n为行数,该命令立即使光标跳到指定行。² Ctrl+g:光标所在位置的行数和列数报告。

5、² w、b:使光标向前或向后跳过一个单词。² O:移动光标到所在行的最前面,相当于功能键Home o² $:移动光标到所在行的最后面,相当于功能键End。² Ctrl+d:光标向下移半页。² Ctrl+f:光标向下移一页。² Ctrl+lu光标向上移半页。² Ctrl+b:光标向上移一页。² H:移动到屏幕的第一行。² M:移动到屏幕的中间行。² L:移动到屏幕的最后行。(2)编辑命令。² i、I、a、A:在说明如何进入编辑模式时已经介绍。² r、R:r修改光标所在字符,r后

6、接要修改的字符。R进入取代状态,新增资料会覆盖原先资料,直到按Esc键回到指令模式下为止。² cw、dw:改变(置换)/删除光标所在处的单词的命令(c=change、d=delete)。² x、x:删除光标所在处后面/前面的字符。² d$、d0:删除光标所在处到行尾/行首的命令。² dd:删除光标所在行。² dw:删除光标处的单词。² nx:删除光标处后n个字符。² nX:删除光标处前n个字符。² ndw:删除光标处后n个单词(word)。² u:恢复前一次所做的操作,相当于Word工具中的undo操作。

7、² y:复制操作(yank)。² p:粘贴操作(普通)。(3)查找/替换命令。² /string、?string:从光标所在处向前或向后查找相应的字符串的命令。² n:同一方向下重复检索。² N:相反方向上重复检索。² rchar:由char代替光标处的字符。² Rtext:由text代替光标处的字符。² Cwtext:由text取代光标处的单词。² Ctext:由text取代光标处至该行结尾处。² CC:使整行空白,但保留光标位置,开始输入。² :s/stringl/string2/

8、g:在整个文件中替换“stringl”成“string2”。² 下面通过实例说明查找替换命令的使用:² /hello:向前查找hello字符。² ?goodbye:向后查找goodbye一词。² /The*foot:向前查找The一词所在的行以及The之后的某一点上的foot词汇。² ?pPrint:向后查找print或Print单词(注意在【,inux中大小写是严格区分的)。² :s/Local/s/Remote/g:用Remote一词替换文件中每一行的Local。(4)存盘/退出命令。在修改文件时,如何存档及退出指定文件都非常重要

9、。在vi内,使用存档或退出的指令时,先按冒号(:),进入冒号命令模式,用户就可以看见在屏幕左下方,出现冒号“:”,这表示vi已经进入冒号命令模式,在此可以完成存档或退出等工作。以下是这种模式下的一些常用命令。² :q!:放弃任何改动而退出vi,也就是强行退出。² :w:存档不退出。² :w!:对于只读文件强行存档。² :wq:存档并退出vi。² ::x:与wq的工作一样。注意:在编辑模式下,不能输入指令,必需先按下Esc键,返回命令模式。假若用户不知身处何态,也可以按下Esc键,这时不管处于何态,都会返回命令模式。vi还可以同时编辑多个文件,它

10、的使用方法是:vi filelist。如同时编辑2个文件,复制一个文件中的文本并粘贴到另一个文件中,命令如下:vi file1 file2,回车yy,回车(在文件l的光标处复制所在行):n,回车(切换到文件2(n=next)或者按Ctrl+ww,就在两个文件间切换)p,回车(在文件2的光标所在处粘贴所复制的行):n,回车(切换回文件1)如果要在vi执行期间,转到shell执行,使用惊叹号(!)将执行系统指令。例如在vi的命令状态,列出当前目录内容,可以输入:!ls另一方面,用户可以在主目录中创建exrc环境文件,用set设置选项,每次调用vi时,都会读入.exrc中的指令与设置。以下是exrc

11、环境文件的应用实例:set wrapmarging=8set showmodeset autoindent gcc编译器Linux的发行版本中包含很多的软件开发工具,这些软件开发工具中很多都是用于C和C+应用程序开发的。Linux上可用的C编译器是GNU C编译器,它安装自由软件基金会的GPL条款自由发布,在Linux的发行关盘里面可以找到它。“gcc”是GNU C编译器的全称,此编译器中集中了C、C+和Objective C三个编译版本,可以编译他们的原程序。gcc是本编译器的通用名,在强调编译C程序时用的名字。当强调编译C+程序时,使用的编译器名称为g+。gcc编译器,不仅可以编译Linu

12、x操作系统下运行的应用程序和Linux本身,还可以作交叉编译,编译运行于其他CPU上的程序。可以作交叉编译的CPU(或DSP)涵盖了几乎所有知名,一商的产品。用于嵌入式应用的、众所周知的CPU包括:Intel的i386、Intel960、AMD29K、ARM、M32、MIPS、M68K、ColdFire、PowerPC、68HC11/12、TI的TMS32等。详细列表可到/reading网站查看。GNU gcc编译器是一套完整的交叉C编译器,包括:² C交叉编译器gcc。² 交叉汇编工具as。² 反汇编工具0bidump c,&#

13、178; 连接工具ld。² 调试工具gbd。可以用批处理文件。MakeFile将上述工具组合成方便的命令行形式。使用gcc编译C程序生成可执行文件有时似乎是一步完成的,但它其实要经历如下4个步骤:(1)预处理(Preprocessing)。这一步需要分析各种命令,如#define、#include、#ifdef等。gcc调用cpp程序来进行预处理。(2)编译(Compilation)。这一步将根据输入文件产生汇编语言,由于通常是立即调用汇编程序,所以其输出一般不保存在文件中,gcc调用ccl进行编译工作。(3)汇编(Assembly)。这一步中将汇编语言用作输入,产生具有.o扩展名的

14、目标文件。gcc调用as进行汇编工作。(4)连接(Linking)。在这一步,各目标文件.o被放在可执行文件的适当位置上,该程序引用的函数也放到可执行文件中。Gcc调用连接程序ld来完成最终的任务。gcc命令的基本用法为:gcc option filename。命令行选项指定的操作将在命令行上每个给出的文件上执行。例如:gcc o prog main.c subr1.c subr2.c subr3.c。其中,“-o prog”指定输出的可执行文件名为prog,如果没有知道-o参数,gcc将使用默认的可执行文件名a.out。如果想单独编译每一个源文件,最后再进行连接,可以调用如下命令:gcc -

15、c mian.cgcc -c subrl.cgcc -c subr2.cgcc -c sunbr3.cgcc -o prog main.o sunbrl.o sunbr2.o sunbr3.o其中,-c选项表示编译产生目标文件,但不连接,最后将所有目标文件连接在一起,构成可执行文件。由于最后一个命令的输入都是目标文件,不需要编译和连接,所以gcc就只调用连接工具ld。gcc的命令选项有许多项,但经常使用的几个选项是:² -c只预处理、编译和汇编源程序,不进行连接。编译器对每一个源程序都将产生一个后缀名为.o的目标文件。² -o Exefile:确定输出文件为Exefile,

16、如果没有指定Exefile,默认输出为可执行文件a.out。² -Dmacro或-Dmacro=defn:其作用类似于源代码程序中的#define。例如:gcc c DHAVE_GDBM_DHELPFILE=”help” cdict.c² 其中,第一个-D选项定义宏HAVE_GDBM,在程序中可以用#ifdef去检测它是否被设置;第二个-D选项将宏HELP-FILE定义为字符串“help”(由于反斜线的作用,引号实际上已经成为该宏定义的一部分),这对于控制程序打开哪个文件是很有用的。² -O:对程序编译进行优化,编译程序试图减少被编译程序的长度和执行时间,但其编译

17、速度比不进行优化慢,而且要求较多的内存。在编译嵌入式应用软件时,如果主机的性能较好,可以打开这个选项。² -O2:允许比-O更好地优化,编译速度也较之更慢一些,但结果程序的执行速度比较快。² -g:告诉gcc产生能被GNU调试器使用的调试信息以便调试程序。gcc提供了一个很多其他C编译器里没有的特性,即在gcc里能使-g和-O(产生优化代码)联用。这点非常有用,因为能在与最终产品尽可能相近的情况下调试代码。在同时使用这两个选项时必须清楚所写的某些代码已经在优化时被gcc作了改动。² -pg这个选项告诉gcc在程序里加入额外的代码,执行时产生gprof用的剖析信息以

18、显式程序的耗时情况。² dir目录加到搜寻头文件的目录列表中去,并优先于在gcc中默认的搜寻目录。在有多个-I选项的情况下,按命令行中I选项的前后顺序搜索。dir可以是相对路径,如-I./inc等。 编写Make File在Linux上写程序的人大都接触过Makefile,尤其是C语言来开发程序的人。用make来开发和编译程序的确很方便,但是要写一个Makefile就不是那么简单了。简单的来说,Makefile就是目标、关联和动作三者所组成的一连串规则。而make会根据Makefile的规则来决定如何编译和连结程序。实际上,make可以做到的不只是编译和连结程序,Makefile还可

19、以做到自动下载源程序包、解压缩、打补丁、设定,然后编译并安装至系统中。如果一个适当的MakeFile文件存在,当改变某些源文件后,只要在shell下使用make命令就可以完成所有必需的重新编译。make程序利用MakeFile文件中的数据和每个文件最近一次更改的时间来确定哪些文件需要更新。对于需要更新的文件,make程序使用MakeFile中定义的命令来更新。至于使用哪个MakeFile文件来更新,可以在make命令中用-f选项来指定。如果不指定,make程序将在当前目录下按下列顺序寻找如下文件:GUNMakeFile、MakeFile和MakeFile。最好是使用MakeFile,因为它的第

20、一个字母是大写的,通常被列在一个文件目录的所有文件列表的最前面,便于查找。1. 编写规则下面对组成MakeFile文件的一些规则加以说明。在这之前首先介绍目标(target)及相关性的概念。² 目标就是make程序要完成的一项任务,目标通常是一个文件的文件名,也有例外。² 相关性即一个目标的完成依赖于其他一些目标或文件。MakeFile文件中包含着一些目标,对于每一个目标,都提供了与这个目标具有相关性的其他目标或文件的名字,以及实现这个目标的一组命令。它的书写规则是:目标属性分隔符号依赖文件;命令列<tab>命令列与Linux下面的命令格式相同,中的内容表示可选

21、,中的内容表示可以出现多次。下面对几个条目的意义进行说明:² 属性:表示该目标文件的属性。² 分隔符:用来分割目标文件和依赖文件的符号,如冒号“:”等。² 依赖文件:实现目标所需要的文件的列表。² 命令列:重新生成目标的命令,可以有多条命令。除第一条命令外,以后的每一条命令都必须以制表键Tab隔开。下面通过一个简单的MakeFile文件的应用实例加以说明:exeProg: main.o subfunc.ogcc o exeProg main.o subfunc.omain.o: main.c main,hgcc c I.-o main.o main.cs

22、ubfunc.o:subfunc.cgcc c o subfunc.o subfunc.cclean:rm f*.o上面的MakeFile文件共定义了4个目标:exeProg、main.o、subfunc.o和clean。每个目标都是从最左边开始写,后面跟一个冒号(:),如果这个目标的实现依赖于其他的目标或文件,把它们列在冒号的后面,并以空格隔开。然后另起一行开始写实现这个目标的一组shell命令。shell命令可以有若干行。注意:每个shell命令的第一个按键必须是字符或数字,不能以空格开头,否则make就会显示如下出错信息:MakeFile:2:*missing separator.Sto

23、p。一般情况下,调用make可以输入:make targettarget是MakeFile文件中定义的目标,如果省略target,make就将更新MakeFile文件的第一个目标。例如在上一个实例中,若输入make命令不带target参数,将更新目标exeProg。make在检查一个目标是否已经过时并需要更新时,采用的是按相关性递归的方法。make在构建一个目标之前要生成该目标所依赖的所有文件,并递归地前进,从而确保这些文件都是新的。具体构建目标的过程如下:(1)如果一个目标task不是作为文件而存在,那它就已经过时了,命令maketask必定执行该任务。 (2)make检查所有与task有相

24、关性的目标。对于不是MakeFile中定义的任务,而只是文件的相关目标,则检查相关目标的生成日期是否比task文件的生成日期更近,如果有一个更近则task就过时了。对于MakeFile定义为任务的相关目标,则按同样的方法检查其是否过时,如果任意一个过时了,都需要更新。(3)递归从底层向上,对所有已经过时的目标进行更新,只有当一个目标所依赖的所有目标都已经更新后,这个目标才被更新。通过上面的例子来说明目标的更新过程。在这里假设修改r文件subfunc.c,可用以下命令更新目标exeProg,即重新编译可执行文件exeProg。% make exeProg由于exeProg依赖于目标main.o和

25、subfunc.o,所以必须检查main.o和subfunc.o是否已经过时。目标文件main.o和源文件main.c和main.h,比较目标文件main.o和源文件main.c、main.h的更新日期,如发现main.o比它所依赖的文件的日期更新,即不过时。再检查目标subfunc.o,它依赖文件subfunc.o,由于已经修改了subfunc.c,它比subfunc.o更新,即subfunc.o过时了,从而依赖subfunc.o的所有目标都过时了。应该用在makfile文件中定义好的如下shell命令更新它:gcc c o subfunc.o subfunc.c由于目标subfunc.o过

26、时并更新,导致目标exeProg已经过时,要完成“make exeProg”的任务,必须用定义exeProg的一组shell命令来更新它:gcc -o exeProg main.o subfunc.o如果是第一次编译上面这个软件,则因为exeProg、main.o和subfunc.o等目标文件都不存在,按照规定,这时所有的目标都是过时的,必须全部更新,而且必须从底而上执行定义这些目标的shell命令。在上面的例子中,还定义了一个目标clean,输入make clean命令将执行:rm f *.oclean的目标是MakeFile中常用的一种专用目标,即删除所有的目标模块。输入make clea

27、n命令时,make程序将查看一个名为clean的文件,如果该文件不存在(约定永远不在文件目录中使用该名字作为文件名称),make将执行定义该目标的所有命令。2宏和隐含规则为了简化命令的书写,在:MakeFile中可以使用几个预先定好的缩写和定义一些宏(macro)。以下是几个经常用到的缩写:² $:代表该目标的全名。² $*:代表已经删除了后缀名的目标名。² $<:代表该目录的第一个相关目标名。按照这样的缩写,上文中的例子可以改写为:#样一个使用缩写符的MakeFile例子#以#开头的一行是注释行 exeProg:main.o subfunc.o gcc o

28、 $ prog.o subfunc.o main.o: main.c main.h gcc c I o $ $< subfunc.o: subfunc.c gcc c -o $ $*.c clean: rm f *.o这类缩写对于编写默认的编译规则是很有用的。GNU的make工具除提供建立目标的基本功能之外,还有许多便于表达依建立目标的命令特色。其中之一就是变量或宏的定义能力。如果要以相同的编编译十几个C源文件,而为每个目标的编译指定冗长的编译选项的话,将是非但利用简单的变量定义,可避免这种乏味的工作。#为编译器定义一个宏名CC=gcc#定义编译宏标志CCFLAGS= -D _DEBJG

29、 g -m486#创建一个目标文件test.o:test.c test.h$(CC) c $(CCFLAGS) test.c在上面的实例中,CC和CCFLAGS都是make的变量。GNU make通常称之为变量,而其他UNIX的make工具称之为宏,实际是同一个东西。在MakeFile中引用变量的值时,只需在变量名之前添加$符号,如上面的$(CC)和$(CCFLAGS)。如果在MakeFile文件中没有给出从某一目标的相关文件构建这一目标的命令,GNUmake包含有一些内置的或隐含的规则,这些规则定义了如何从不同的依赖文件建立特定类型的目标。例如,对下面的MakeFile文件中的内容:#一个简

30、单的使用默认规则的MakeFile例子exeProg:main.o subfunc.ogcc -o exeProg main.o subr.oclean:rm f *.oexeProg的相关目标main.o和subfunc.o的构造规则如果没有定义,make程序将使用隐含规则。默认的隐含规则中可以生成目标类型为o文件的相关文件类型有多种(如.c、cc、.C、.p、.f等)。make程序将按顺序找出第一个存在的或可以构建的类型。例如,若它最先找到。main.c,它就使用隐含规则中的main.c构建main.o,如果没有,就依此类推。GNU make支持两种类型的隐含规则,它们的表示方式为:后缀规

31、则(Suffix Rules):后缀规则是定义隐含规则的较老的风格方法。后缀规则定义了将一个具有某个后缀的文件(例如c文件)转换为具有另外一种后缀的文件(例如.o文件)的方法。每个后缀规则以两个成对出现的后缀名定义。例如,将.c文件转换为.o文件的后缀规则可定义为:.c.o:$(CC) $(CCFLAGS) $(CPPFLAGS) c o $ $<模式规则(Pattern Rules):这种规则更加通用,因为可以利用模式规则定义更加复杂的依赖规则。模式规则看起来非常类似于后缀规则,但在目标名称的前面多了一个“”号,同时可用于定义目标和依赖文件之间的关系,例如下面的模式规则定义了如何将任意

32、一个X.c文件转换为X.o文件:%.c:%.o$(CC) $(CCFLAGS) $(CPPFLAGS) c o $ $<以上是MakeFile文件的大体编写规范,对于比较复杂的软件包,要自己编写MakeFile文件也是一件令人烦恼的事。一般来说,这时软件提供商会提供一个MakeFile的示例文件,在这个文件的基础之上按照自己的要求进行相应的修改就容易多了。另外,也可以使用automake和autoconf软件来生成MakeFile文件,具体使用方法请查看帮助文件。 debug工具GDB前面介绍了Linux系统下的基本开发工具,通过这些开发工具,应该可以开发出您想实现的软件。但开发出来的软

33、件无可避免地会出现各种各样的问题,在编译源代码的时候也可能出错。这时就需要一个功能强大的调试工具,在这里就将介绍在Linux中得到广泛应用的调试工具GDB。GDB是GNU的一个重要软件,最早由Richard Stallman编写。使用GDB的另一大好处是GDB支持嵌入式软件的开发模式交叉调试,当运行gdb的Linux平台(宿主机)通过串行端口(或网络连接,或是其他的方式)连接到目标板时,gdb可以对运行在目标板上的应用程序进行调试。由于这个特性,许多新开发的嵌入式操作系统都把GDB移植到其上作为调试工具。GDB能够观察另一个程序在执行时的内部活动,或程序出错时发生了什么?GDB的主要功能有以下

34、几点:² 设置运行环境和参数,运行指定程序。² 让程序在指定条件下停止和运行。² 在程序运行停止后,检查变量、内存或寄存器的值,查看程序运行情况。² 修改正在调试的程序的源代码,这样可以在线修正某个bug引起的问题,然后继续查找下一个bug。GDB的使用可以直接在shell命令行下输入gdb并按回车键,再在gdb命令行下指定要调试的程序;也可以用gdb filename在启动时指定要调试的程序名。如果正常启动,屏幕将出现类似于以下的信息,并进入GDB命令模式:GNU gdb Red Hat Linux 7.x(5.0rh_15)(MI_OUT)Copyr

35、ight 2001 Free Software Foundation,IncGDB is free software,covered by the GNU General Public License,and you are welcome to change it and/or distribute copies of it under certain conditionsType “show copying” to see the conditionsThere is absolutely no warranty for GDB.Type “show warranty” fordetail

36、sThis GDB was configured as “i386一redhatlinux”(gdb)GDB可以运行在许多模式下,这些模式是在GDB运行时在命令行作为选项指定的。下面将对这些模式进行相应的说明。² -nx或-n:不执行任何初始化文件中的命令(一般GDB的初始化文件名gdbinit)。一般情况下在这个文件中的命会将所有 的命令行参数传递给GDB后执行。² -quiet或-q:安静模式。不输出上面显示的介绍和版本信息。这些信息在“批处理”中也将被跳过。² -batch:批处理模式。当在批处理命令文件中的 所有命令都被执行后,GDB将返回状态0;如果执行

37、过程出错,将返回0值。² -cd DIRECTORY:把DIRECTORY作为GDB的工作目录,这时工作目录不再是当前目录(在一般情况下,GDB默认把当前目录作为工作目录)。² -b BIT/S:为远程调试设置串口波特率。² -tty设备名:使用其他设备作为程序的标准输入输出。这种模式对于嵌入式交叉调试很有用。在GDB启动后,就进入GDB命令方式,这时就可以使用GDB的各种命令进行调试了。下面对它的各种调试命令进行详细说明。为了使GDB能够正常工作,必须使程序在编译时包含调试信息。具体的调试信息包括程序里的每个变量的类型、在可执行文件里的地址映射以及源代码的行号等

38、。如果没有这些信息,GDB就默认到init.c中,这时就无法调试。若要使编译时包含这些信息,只需在使用gcc时加-g选项即可。下面对常用的GDB命令加以说明。² 载入程序命令:file在GDB内,载入程序很简单,使用file命令。如要加载hello程序用file hello。当然,程序的路径名要正确。² 退出GDB命令:quit在GDB的命令方式下,输入quit,就可以退出GDB。也可以输入C -d来退出GDB。² 运行程序命令:run当在GDB中已将要调试的程序载入后,可以用run命令来执行。如果程序需要参数,可以在run指令后接着输入参数,就像在Shell下执

39、行一个需要参数的命令一样。² 查看程序信息命令:infoinfo指令用来查看程序的信息,它的参数非常多,但大部分不常用。一般用info指令最多的是用它来查看断点信息:info br,这时可以得到所设置的所有断点的详细信息,包括断点号、类型、状态、内存地址、断点在源程序中的位置等。info source可以查看当前源程序。² 列出源程序命令:list这个命令从头开始将列出源程序代码,重复使用这个命令会接着前一次继续显示。若要列出某个指定函数:list FUNCTION。若以当前源文件的某行为中间显示一段源程序list LINENIJM,将显示另一个文件的一段程序:list F

40、ILENAME:FUNCTION或list FILENAME:LINENUM。² 设置断点命令:break这是最常用和最重要的命令,无论何时,只要程序已被载入,并且当前没有正在运行,修改、删除断点。设置断点的命令是break。有许多种设置断点的方法,如在函数入口设置断点:break FUNCTION;在当前源文件的某一行上设置断点:break LINENUM;在另一个源文件的某一行上设置断点:break FILENAME:LINENUM;在某个地址上设置断点,当调试的程序没有源程序时,可以用break *ADDRESS。除此之外,设置一个断点,让它只有在某些特定的条件成立时程序才会停

41、下来,可以称其为条件断点,它的命令格式breakif COND。COND是一个布尔条件表达式,语法与C语言中的一样。条件断点与一般的断点不同之处是每当程序执行到断点处,都要计算条件表达式,如果为真,程序才会停下来,否则程序会一直执行下去。² 设置监视点命令:watch当调试一个很大的程序,并且在跟踪一个关键的变量时,发现这个变量不知在哪儿被改动过,如何才能找到改动它的地方?这时可以使用watch命令。简单地说,监视点可以监视某个表达式或变量,当它被读或被写时让程序停下来。watch命令的用法如下:watch EXPRESSIONwatch指令是监视写操作的,当用户想监视某个表达式或变

42、量的读操作的话,需要使用rwatch指令,具体用法是一样的。² 显示表达式值的命令:print最常用的检查数据的方法是:print exp,print指令将打印exp表达式的值。默认情况下,表达式的值的打印格式依赖于它的数据类型。但可以用一个参数/F来选择输出的打印格式。表达式exp中的变量必须是全局变量或当前堆栈区可见的变量。否则GDB会显示像下面的一条信息:No symbol ”variable” in current context² 单步执行指令:step或next单步执行指令有step和next。step可以跟踪进入一个函数,而next指令则不会进入函数。

43、8; 继续执行命令:continue当程序被停下来后,查看了所需的信息后,如希望程序执行下去,可输入continue,这时程序将会继续执行下去。² 产生可执行文件命令:make通过make不用退出GDB就可以重新产生可执行文件。² shell命令不离开GDB就可以执行UNIX shell命令。在嵌入式Linux软件开发中,使用GDB交叉调试有两种方式:² 目标机上的嵌入式Linux系统包含GDB工具。这时可以利用TFTP把在宿主机上开发的应用软件用mount命令挂载到目标机的一个开发目录下,再在主机上启动minicom超级终端,登录到目标机上。启动目标机的GDB程

44、序,运行应用程序,之后就可以对应用程序进行调试了,调试的信息可以在minicom中看到。我们的PXA270RP实验箱上应用程序开发就属于这种方式。² 目标板中不支持GDB,这时就要在主机上运行GDB,利用GDB的远程调试功能。在目标板上也要有一个名为stub的伺服程序,这个程序的作用是接受GDB的调试命令,解释执行,并按命令要求把调试结果返回给GDB。例如,通过串口线的方式,在本地主机上输入target remote /dev/ttyS0命令,本地主机就可通过窗口1和远程主机里面的stub程序相连接。当然,对于不同的体系结构的系统,需要编写不同的stub程序,在GDB的发布套件里面提

45、供了默认stub文件,如针对Sparc机器的sparc-stub.c文件、针对m68000的m68k-stub.c的Intel 386的i386-stub.c文件。以上是GDB工具相关知识的介绍,在嵌入式Linux应用软件开发中,熟练地使用GDB是必要的,在以后的实例中也将继续介绍GDB在项目中的实际应用。3.2 嵌入式Linux驱动程序开发 嵌入式系统设备驱动Linux设备驱动程序是内核的一部分,它完成以下功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误。也就是说设备驱动担当着连接硬件和内核的

46、桥梁的角色,如图示:应用程序文件系统操作系统设备驱动程序硬件设备图 设备驱动与硬件、操作系统的关系设备驱动直接与底层硬件通信,按照硬件设备的工作方式来读写设备寄存器,完成设备的轮询、中断处理、DMA通信,进行物理内存向虚拟内存的映射,最终完成通信设备数据的收发,显示设备上文字和界面的显示,存储设备完成数据和文件的存储记录。在Linux系统下,系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。Linux设备驱动程序为应用程序屏蔽了硬件细节,在应用程序看来,Linux硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。每个设备驱动程

47、序都具有以下几个特性:² 具有一整套的和硬件设备通讯的例程,并且提供给操作系统一套标准的软件接口;² 具有一个可以被操作系统动态地调用和移除的自包含组件;² 可以控制和管理用户程序和物理设备之间的数据流。 随着当前的IC制造业的发展使得芯片集成度越来越高,在ARM、PowerPC、MIPS等处理器内部都集成了UART、I²C控制器、USB控制器、SDRAM控制器等,有的还集成了片内RAM和Flash。在这里我们这里所说的设备驱动,主要是针对存储器和外设(包括处理器内部集成的存储器和外设),而不是针对CPU核的。Linux下将存储器和外设分为3大类:

48、78; 字符设备:必须以串行顺序依次进行访问的设备,是顺序的数据流设备,这些字符连续地形成一个数据流,如触摸屏、鼠标、终端等。² 块设备:可以用任意顺序进行访问,以块为单位进行操作,这种设备使用缓冲区来存放暂时的数据,等待条件成熟以后,从缓存一次性写入设备或从设备中一次性读出放入到缓冲区,如硬盘、软驱等。² 网络设备:通过BSD socket接口访问的设备,在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。字符设备不经过系统的快速缓冲,而块设备经过系统的快速缓冲。但是块设备和

49、字符设备并没有明显的界限,如Flash设备符合块设备的特点,但是我们仍然可以把它作为一个字符设备来访问。字符设备和块设备的取得设计呈现出很大的差异,但是对于用户而言,他们都使用文件系统的操作接口open()、write()、close()、read()等函数进行访问。在Linux系统中,网络设备面向数据包的接收和发送而设计,它并不对应于文件系统的节点。内核与网络设备的通信和内核与字符设备、块设备的通信方式完全不同。 Linux设备驱动原理设备驱动程序在Linux内核中占有极其重要的位置,它是内核用于完成对物理设备的控制操作的功能模块。除了CPU、内存以及其他很少的几个部分以外,所有的设备控制操

50、作都必须由与被控设备相关代码驱动程序来完成。否则设备就无法在Linux下正常工作,这就是驱动程序开发成为Linux内核开发的主要工作的原因。在Linux内核中,设备驱动程序是一个独立的黑盒子。它使某个特定的硬件可以响应一个定义良好的内部编程接口,同时完成隐藏设备的工作。用户操作通过一组标准化的调用完成,而这些调用是和特定的驱动程序无关的。将这些调用映射到作用于实际硬件的特定操作上,是设备驱动程序的任务。这个编程接口能使得驱动程序独立于内核的其他部分而建立,在需要的时候,可在运行时“插入”内核。这种模块化的特点,使得Linux驱动程序的编写非常简单。在Linux系统里,对用户程序而言,设备驱动程

51、序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件(也有设备不作这样的映射),用户可以用访问普通文件的方式来访问控制硬件设备。Linux对硬件设备支持两个标准接口:块设备文件和字符设备文件,通过块(字符)设备文件存取的设备称为块(字符)设备或具有块(字符)设备接口。块设备接口仅支持面向块的I/O操作,所有I/O操作都通过在内核地址空间中的I/O缓冲区进行,它可以运行几乎在任意长度和任意位置上的I/O请求,即提供随机存取的功能。字符设备接口支持面向字符的I/O操作,它不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构,字符设备接口只支持顺序存取的

52、功能,一般不能进行任意长度的I/O请求,而是限制I/O请求的长度必须是设备要求的基本块长的倍数。显然,程序所驱动的串行卡只能提供顺序存取的功能,属于字符设备,因此后面的讨论在两种设备有所区别时都只涉及字符型设备接口,设备由一个主设备号和一个次设备号标识。主设备号唯一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引,次设备号仅由设备驱动程序解释,一般用于识别在若干可能硬件设备中,I/O请求所涉及到的那个设备。设备程序驱动程序可以分为三个主要组成:(1)自动配置和初始化子程序,负责检测所要驱动的硬件设备是否存在和是否能正常工作。如果该设备正常,则对这个设备及其相关的设备

53、驱动程序需要的软件状态,进行初始化。这部分驱动程序仅在初始化的时候被调用一次。(2)服务于I/O请求的子程序,又称为驱动程序的上半部分。调用这部分是由于系统调节调用的结果。这部分程序在执行的时候,系统仍认为是和进行调用的进程属于同一个进程,只是由用户态变成了核心态,具有进行此系统调用的用户程序的运行环境,因此可以在其中调用sleep()等与进程运行环境有关的函数。(3)中断服务子程序,又称为驱动程序的下半部分。在UNIX系统中,并不是直接从中断向量表中调用设备驱动程序的中断服务子程序,而是由UNIX系统来接收硬件中断,再由系统调用中断服务子程序,中断可以产生在任何一个进程运行的时候,因此在中断

54、服务程序调用的时候,不能依赖于任何进程的状态,也就不能调用任何与进程运行环境有关的函数。因为设备驱动程序一般支持同一类型的若干设备,所以一般在系统调用中断服务子程序的时候,都带有一个或多个参数。 Linux设备驱动架构作为Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统。Linux所有的设备均作为文件来对待,这些文件一般被称为特殊文件,这样做的一个好处是使用户或应用程序可按操纵普通文件的方式进行访问控制硬件设备。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel中的函数,有些常用的操作要自己来编写

55、,而且调试也不方便。在Linux内核中,设备驱动程序是作为文件系统的一个模块存在的,它向下负责和硬件设备的交互,向上通过一个通用的接口挂接到文件系统上,从而和系统的内核等联系起来。它是软件概念和硬件设备间的一个抽象层,驱动层在整个操作系统架构中的作用如图示:用户应用程序编程文件系统接口(C库函数等)操作系统Linux文件系统磁盘/Flash文件系统块设备驱动字符设备驱动进程管理硬件设备网络接口进程调度内存管理图 驱动程序的角色Linux中的设备驱动程序有很多的分类方法,从能否动态加载的角度看,可分为可动态加载和卸载的内核模块和静态链接的内核设备驱动程序两种类型,不管是哪种类型,从结构上看,整个

56、驱动程序可分为三个部分:初始化设备;独立于设备的接口;硬件设备I/O。其中硬件I/O部分是和具体硬件相关的部分,有三种通用机制可以实现CPU和外部设备的数据交换:轮询、DMA、和中断。从编程角度看,这三种类型有一定的差别,这部分的编程和其它操作系统驱动程序的相应部分有一定的相似性,在此不作深入的探讨,在实际编写时可参考有关硬件资料;独立于设备的接口是设备驱动程序和文件系统连接的桥梁,在Linux中,有很规范的接口;驱动程序初始化部分负责将设备驱动程序装载到内核或从内核中卸载等,此处不详述。3.3 嵌入式Linux程序开发初探 第一个linux C语言程序为了方便读者学习,我们先写一个简单的He

57、lloWorld程序,这个程序的功能很简单,就是在linux下利用其本身自带的编译器来编写一下简单的C语言程序,并生成可执行文件,如图所示,输入指令如下:cd /homemkdir experiments /*在home文件夹下建立experiments文件夹*/cd experimentsvi HelloWorld /*利用linux系统的典型编辑器vi来编辑我们的程序*/图 编辑第一个程序在编辑器中输入程序如图所示:图 第一个helloworld程序下面就是编译、连接和运用我们的程序:gcc o HelloWorld HelloWorld.c /*使用linux自带的编译器编译X86程序*/./HelloWorld /*运行可执行文件,输出结果*/图 运行结果实验例程解析: 调用GNU C语言编译器将我们的C语言源代码转换为可执行文件HelloWorld,运行这个程序,打印出欢迎信息。这只是一个简单的例子,如果不能正常编译执行,那么请检查你的系统是否安装了编译器。可以注意到,我们执行可执行文件的时候在前面加了一个“./”,这样操作是为了防止shell找不到此程序,在执行程序的前面加上此符号,就特别指示shell去执行当前目录下给定名称的程序。如果不加此符号,则执行的是主目录下的程序,在这里我特别指出来,防止以后错误的出现。 第一个嵌入式系统

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论