1、单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,#,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,2021/12/16,#,第,1,章,认识嵌入式系统,嵌入式,Linux,开发基础,1.,什么是嵌入式系统,提纲,2.,嵌入式系统的发展史,3.,嵌入式系统的应用,4.,常见的嵌入式系统,5.,嵌入式,Linux,的优点,1.,什么是嵌入式系统,IEEE(电气和电子工程师协会)对嵌入式系统的定义是这样的:“嵌入式系统是控制、监视或辅助机器和设备运行的装置。”国内大多数资料都这样描述嵌入式系统:嵌入式系统是“以应用为中心,以计
2、算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统。”,1.,什么是嵌入式系统,嵌入式系统的例子:汽车电喷系统,2.,嵌入式系统的发展史,60,年代,阿波罗导航计算机,民兵,I,导弹,D-17,自动导航控制计算机,70,年代,基于单片机发展。,Intel4004,,,8080,,,.,。,80,年代,简单操作系统的支持,90,年代,高效率、多任务,文件系统、,GUI,21,世纪,网络连接,智能化,3.,嵌入式系统的应用,生活方面,3.,嵌入式系统的应用,生产方面,3.,嵌入式系统的应用,管理方面,4.,常见的嵌入式系统,Windows CE,v
3、xWorks,eCos,uC/OS-2,嵌入式,Linux,5.,嵌入式,Linux,的优点,完全的开源,广泛的硬件支持,高可定制性,占用较少的硬件资源,具备强大的网络功能,其它优点,第,3,章 搭建,C,语言开发环境,1.IDE,和分步开发,提纲,2.,安装,C,语言开发工具集,3.,优化,gedit,编码环境,1.,IDE,和分步开发,要产生一个独立运行的应用程序,需要经过编码(编写源代码)、编译、链接等步骤。如果在测试过程中出现逻辑错误,还可能需要通过调试等手段发现错误,再回头改正错误,重新编译、链接。,有些开发工具,集成了开发的所有步骤,称为,IDE,。,2.,安装,C,语言开发工具集
4、在CentOS里,安装软件大致有三种方法:,1、通过源代码编译安装。,2、RPM方式安装。,3、YUM方式安装。,其中,,YUM,最简单易用。,2.,安装,C,语言开发工具集,1,、挂载光盘,以系统光盘为安装源的,YUM,安装方式:,2,、配置安装源,3,、安装软件,2.,安装,C,语言开发工具集,1,、挂载光盘,以系统光盘为安装源的,YUM,安装方式:,2.,安装,C,语言开发工具集,以系统光盘为安装源的,YUM,安装方式:,2,、配置安装源,rootlocalhost#cd /etc/yum.repos.d/,rootlocalhost yum.repos.d#vim CentOS-DV
5、D.repo,DVD,name=CentOS 6.7 dvd,baseurl=file:/media/CentOS_6.7_Final/,enabled=1,gpgcheck=0,2.,安装,C,语言开发工具集,以系统光盘为安装源的,YUM,安装方式:,3,、安装软件,3.,优化,gedit,编码环境,1、可以自动缩进。自动缩进对编写程序代码特别有用,能够使得代码错落有致、层次清晰,方便阅读、理解和调试。,2、可以设置tab键的格式。可以根据个人爱好设置tab键宽度,还可以设置使用空格代替tab键。,3、能够显示行号、列号。行号列号对程序设计特别重要,如果编译出错,编译器会显示出错的行号、列号
6、和错误信息,根据行号和列号,可以在快速定位出错代码。,4、能突出显示当前行。,5、能够突出显示匹配的(大、中、小)括号。这个功能对于多层嵌套的代码特别有用,可以清楚地看到每一层嵌套的开始位置和结束位置。,6、对于超长单行文本能够自动换行,还能智能识别英语单词,自动换行时避免把一个单词拆成两行。,7、可以随意改变字体大小、颜色、风格。,8、支持UTF-8和ASCII等多种编码,对中文的支持很好,支持包括gb2312、gbk在内的多种中文字符编码。,9、可以识别包括C语言在内的多种程序设计语言,根据不同的语言实现语法高亮,以不同的颜色突出显示关键字和标识符。,gedit,的功能和特点,3.,优化,
7、gedit,编码环境,设置,gedit,3.,优化,gedit,编码环境,以文件扩展名,.c,识别为,C,语言源文件,3.,优化,gedit,编码环境,安装系统光盘上的,gedit,插件,yum install gedit-plugins,3.,优化,gedit,编码环境,安装独立的插件,csmartindent,以智能缩进,使用,tar,命令解压解包,csmartindent,插件。,cd tar -zxvf csmartindent.tar.gz,csmartindent,解压解包出两个文件:,csmartindent.gedit-plugin,csmartindent.py,把解压出来的
8、文件复制到,/.gnome2/gedit/plugins,目录下。(,/.gnome2/gedit/plugins,是,gedit,专门放置当前用户插件的目录,为了方便描述,以下简称插件目录。在插件目录表达式中,“,”表示当前用户的,home,目录,也就是说,不同用户的插件目录不一样。),cd /.gnome2,mkdir -p gedit/plugins,3.,优化,gedit,编码环境,安装独立的插件,csmartindent,以智能缩进,cd gedit/plugins,cp /csmartindent.gedit-plugin .cp /csmartindent.py .,csmart
9、indent,插件安装完毕,重启,gedit,。,感谢聆听,第,4,章 简单的,Linux C,程序,1.,准备工作,提纲,2.,编写代码,3.,编译运行,4.Linux,下,C,语言的输入,1.,准备工作,源程序(源文件):代码所在文件。,源代码、代码:可指代源文件,亦可指代代码片段。需结合上下文理解。,程序:指编译后可运行的机器指令代码文件。,在日常生活中,程序有时会指代源程序。,1.,准备工作,为了方便管理,建立源程序(程序)专用目录:,cd ,mkdir linux-C(,大写,),2.,编写代码,#include ,#include ,int main(),printf(“hello
10、 world!n”);,return EXIT_SUCCESS;,gedit,的语法高亮是针对具体的程序设计语言的,想在,gedit,内实现,C,语言程序的语法高亮和智能缩进,首先得让,gedit,知道所编辑的文件是,C,语言源程序。,gedit,根据文档的文件名判断文件类型。,C,语言程序的标准文件名为,*.c,。所以,需要先把文档保存成,.c,文件,“,/root/Linux-Chelloworld.c,”。,2.,编写代码,常用转义字符,字符,意义,n,换行,t,制表符(tab),单引号。在C语言里,单引号用来括起字符,如果单引号直接出现在字符串里会出现混乱,所以字符串中的单引号字符必须
11、使用转义字符来表达。比如字符串Toms age在C语言里写成:”Toms age”。,单引号。在C语言里,双引号用来括起字符串,如果双引号直接出现在字符串里会出现混乱,所以字符串中的双引号字符必须使用转义字符来表达。比如the“good”man在C语言里写成:”the”good”man”。,反斜杠。反斜杠已经被用来表达转义字符,所以,如果反斜杠本身作为字符需要写成连续的两个反斜杠。,?,问号,第,5,章 使用自定义函数,1.,函数和自定义函数的概念,提纲,2.,定义函数,3.,范例,1.,函数和自定义函数的概念,所谓函数,是指可以供其它代码调用,帮助其它代码完成某一功能的独立的代码块。代码块并
12、不编写在被调用处,而是在另外一个单独的地方。为了调用方便,代码块一般都会有一个名字,这个名字就是函数名。函数能接受调用代码传来的数据,这些数据被称为参数;也可以把处理结果返回给调用代码,这个处理结果被称为返回值。前面的Hello world!源程序中的main()和printf()就是函数,它们是C语言定义的标准函数。除此之外,程序员还可以在源程序中定义自己的函数,称为自定义函数。,2.,定义函数,C语言严格遵循常量、变量、函数等一切标识符先定义后使用的原则。,但是,这种写法明显不符合人们的阅读习惯,不方便人们去阅读和理解程序。因为人要理解一个复杂的事物,一般都是先看这个事物整体实现什么功能,
13、再了解事物由哪些部件构成,根据需要再了解某些部件的具体实现。也就是说,阅读代码一般都是先从main()函数开始,再根据需要阅读子函数的代码。这是一种先全局后局部,自顶向下的思维方式,这种思维方式对于理解、把握复杂的事物很有帮助。,2.,定义函数,C语言对函数的定义作了改进,允许把函数的定义分成两部分:声明和实现。声明部分不包含函数的具体代码,只是函数的返回值类型、函数名和参数的说明。实现部分则是完成函数功能的具体代码。,函数的声明格式:,2.,定义函数,如果程序包含多个函数,则各子函数应该在main()主函数之前一一声明。函数的声明顺序并不重要,即使函数之间存在互相调用的情况,而且,函数的声明
14、顺序和实现顺序没有关联。有了函数声明,函数可以按任意顺序实现。,2.,定义函数,如果程序包含多个函数,则各子函数应该在main()主函数之前一一声明。函数的声明顺序并不重要,即使函数之间存在互相调用的情况,而且,函数的声明顺序和实现顺序没有关联。有了函数声明,函数可以按任意顺序实现。,3.,范例,程序,5.1,程序,5.2,详见教材,3.,范例,从键盘输入某个年份,判断该年份是否为闰年。,判断闰年条件:非整百年数除以,4,,无余为闰,有余为平;整百年数除以,400,,无余为闰有余平。,从键盘输,入,一个成绩(,0-100,,整数),使用,switch,判断该成绩的等级。,等级划分:,90-10
15、0,:优秀;,80-89,:良好;,70-79,:中等;,60-69,:及格;,0-59,:不及格。,3.,范例,判断闰年,整百年,被,400,整除,闰年,不被,400,整数,平年,非整百年,被,4,整除,闰年,不被,4,整除,平年,感谢聆听,3.,编译、运行,编译,gcc helloworld.c,默认产生的程序名为,a.out,运行,./a.out,自定义程序名编译,gcc helloworld.c -o helloworld,产生的程序名为,helloworld,运行,./helloworld,3.,编译、运行,常用的编译选项,选项,选项描述,-x language,指定源代码使用的语言
16、gcc除可编译C语言源程序外,还可以编译C+和汇编源程序。在默认情况下,gcc根据源程序的扩展名识别源程序使用的语言。-x用于人工指定源程序使用的语言。,-c,只对源程序进行编译和汇编,生成.o目标文件,但不进行链接,-S,把源程序编译成汇编语言源程序,生成.s汇编程序文件,但不进行汇编和链接。,-E,只对源程序进行预处理,不编译和链接。使用了此选项,如果源程序不需要预处理,则gcc自动忽略此源程序。,-o file,指定生成的文件名。-o选项可以和其它选项合用,不管最终生成什么类型的文件,都可以用该选项指定文件名,比如gcc c o file file1.c,把file1.c源程序编译成名
17、为file的目标文件。,-v,显示gcc的版本信息和编译过程中的一些信息。,-version,显示gcc的版本信息和版权信息,-fsyntax-only,只对源程序进行语法检查,不进行编译,-w,禁止所有警告信息,-Wall,显示附加的警告信息,-g,给程序添加本地操作系统格式的调试信息,-ggdb,给程序添加各种调试信息,包括gdb扩展的调试信息,-O0、-O(-O1)、-O2、-O3,使用不同的级别对程序进行优化,其中,-O0指不对程序进行优化,是gcc的默认项,-O和-O1同义,O后面跟的数字越大,表示优化的级别越高。除此之外,还有-Os选项,对程序的体积进行优化。,-I directo
18、ry,指定头文件的搜索目录,指定的搜索目录将优先于系统缺省的头文件搜索目录。,-l library,指定链接时使用的库文件,4.Linux,下,C,语言的输入,scanf(),缓冲区问题,10,n,n,c,输入缓冲区,办法,1,:利用,%*c,丢弃整数后面的回车符。,在使用scanf()时,如果在格式化点位符前面加上星号*,则表示把相应的数据丢弃而不赋给任何变量。%*c表示丢弃一个字符,%*s表示丢弃一个字符串。,办法,2,:调用函数清空输入缓冲区。,Linux C,有一个名为,_fpurge(),的函数,它的作用是清空指定的缓冲区。原型如下:,#include ,Int _fpurge(FI
19、LE *stream);,感谢聆听,第,6,章 使用多个源文件编程,1.,多源文件编程,的概念,提纲,2.,多源文件的编写,3.,多源文件项目的编译,1.,多源文件编程的概念,对于大规模的系统,把所有代码写在单个源文件里的做法有着显而易见的缺点:,1、即使代码使用了自定义函数,大量的代码堆积在单个文件里仍然会导致阅读、理解、调试和维护上的困难。,2、大体积的文件会降低编辑器的运行效率。每次打开、查找、保存都需要花费大量的时间。,3、编译大体积的源文件会花费大量的时间,影响系统的开发效率。,4、不利于团队协作。,所以,在大规模的系统开发中,源代码一般分成多个源文件来实现。,2.,多源文件的编写,
20、2.,定义函数,每个非主源文件配置一个对应的头文件:,2.,多源文件的编写,在需要调用函数的源文件里包含头文件:,2.,多源文件项目的编译,多个源文件的项目仍然使用gcc编译链接。在编译链接时需要在命令行中枚举项目使用的所有源文件。头文件因为已经包含在源文件中,所以不需要枚举头文件。,第,6,章 使用多个源文件编程,1.,多源文件,项目的编写规则,提纲,2.,多源文件,项目的分步编译,3.,案例练习,1.,多源文件项目的编写规则,原则:主函数,main(),和自定义函数分开存放在不同的源文件。,自由:,使用多少个源文件根据需要而定。,多个自定义函数可以放在一个源文件。也可以分开存放。,多个源文
21、件可以对应一个头文件,也可以分别对应一个头文件。,一个源文件可以有多个头文件。,2.,多源文件项目的分步编译,编译:生成,.o,目标文件,gcc -c x.c x1.c x2.c x3.c,链接:生成最终程序,gcc -o x x.o x1.o x2.o x3.o,x.c,-,x.o,x1.c,-,x1.o,x2.c,-,x2.o,x3.c,-,x3.o,链接,x,比较费时间(按需编译),比较不费时间,3.,案例练习,编写成绩分析程序,,main(),函数负责接口部分,每个成绩分析功能独立成一个源文件。,程序要求如下:,在教学过程中,老师要对每次的考试成绩进行分析,分析内容包含显示成绩、排序(
22、从高到低排序、从低到高排序)、查看最高分、查看最低分等。,假设班上有,10,位同学。编写一个程序,根据老师的选择实行成绩分析。,为了简单起见,假设,10,位同学的姓名保存在一个全局数组中,成绩按姓名的顺序保存在另外一个全局数组中。对成绩进行排序时,只需要把排序结果输出到屏幕上,不需要写入数组中。姓名和成绩自拟。,第,7,章 使用和认识,make,1.make,概念,提纲,2.Makefile,的编写,3.,改进版,Makefile,4.Makefile,进阶用法,1.make,概念,make是一个智能化的系统开发项目管理工具。在编译时,make可以自动识别自上次编译以来哪些源文件被修改过,哪些
23、源文件没被修改过,从而自动忽略没被修改过的源文件,只重新编译被修改过的源文件。如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用make可以避免不必要的重新编译,大大提高开发效率。,2.Makefile,的编写,make,并不能在没有任何提示的情况下猜测人的意图。也就是说,需要人工下达指令指示,make,工作。我们把指令写在一个名为,makefile,或,Makefile,的文本文件里。对于,make,而言,,makefile,和,Makefile,是等效的,但由于大写的,M,在一大堆文件中更加显眼,所以,在实际应用中更习惯使用,Makefile,。,2.Makefile,的编写
24、Makefile是一个按规定的语法规则编写的文本文件,用来指示make工作。Makefile的规则很简单,表述起来只有两行:,其中,目标指的是命令最终生成什么文件,可以是.o目标文件,也可以是可执行文件;依赖文件是指要生成目标需要哪些文件;命令是指生成目标需要执行的命令。,3.,改进版,Makefile,一个大型系统一般分成多个源文件进行开发。要生成最终的可执行文件,需要两个步骤:编译和链接。对于大量的代码,从源文件到.o目标文件的编译最耗费时间。在后期的调试阶段,往往只修改其中某个或几个源文件,其它源文件保持原状。如果能够有选择地重新编译修改过的源文件,忽略未修改过的源文件,将会大大提高开
25、发效率。为达到此目标,Makefile文件应该做出相应的改变,把编译和链接分开进行。,3.,改进版,Makefile,在上面的例子中,make运行时,发现依赖文件是经过编译后的目标文件,并不是最原始的源文件。所以,如果发现目标文件不存在,则以目标文件名作为目标往后查找相应的内容。比如说,发现test7.1.o不存在,则往后查找到3、4行。在执行1、2行之前,先执行3、4行。同样的道理,如果发现目标文件accumulator.o不存在,则查找并执行5、6行。就这样,make一层一层地往下追溯,再回溯,最后生成最终的目标test7.1。,4.Makefile,进阶用法,一、伪目标,在系统的调试过程
26、中,我们经常需要象上面的第一步那样做一些额外的工作,比如删除一些文件,有时候这些额外的工作所用的命令比较复杂或者比较多,每次手工处理显得比较麻烦。针对这种情况,make提供了一种称为伪目标的方法。所谓的伪目标,也就是说,目标只是一个标识符,并不最终产生相应的文件,只是使用这个标识符标记一些命令。,4.Makefile,进阶用法,上面的Makefile文件多次出现了同一长字符串:,test7.1.o accumulator.o factorial.o square_sum.o,有经验的程序员都知道,直接在多个地方书写同样的内容,容易引起输入错误,而且会给后期的修改、维护带来麻烦。用简单的变量代替
27、它们是最好的做法。为了解决这一问题,make引入了变量的概念。变量在Makefile中用来代表一串字符。,4.Makefile,进阶用法,为了方便编写和简化Makefile,除了自定义变量,make还预定义了一批变量。,Makefile中常见的预定义变量,变量,含义,CC,C编译器的名字,默认值为cc,CPP,C预编译器的名字,默认值为$(CC)-E,CXX,C+编译器的名字,默认值为g+,AR,库文件维护程序的名字,默认值为ar,AS,汇编程序的名字,默认值为as,CFLAGS,C编译器的选项,无默认值,CPPFLAGS,C预编译器的选项,无默认值,CXXFLAGS,C+编译器的选项,无默认
28、值,ARFLAGS,库文件维护程序的选项,无默认值,ASFLAGS,汇编程序的选项,无默认值,4.Makefile,进阶用法,Makefile还可以使用自动变量和环境变量。,变量,含义,$*,不包含扩展名的目标文件名称,$,目标文件的完整名称,$+,以空格分开的所有的依赖文件,并以原来定义的先后顺序为序。有可能包含重复项。,$,以空格分开的所有不重复的依赖文件,$2-3-4-1的顺序滚动。同一时刻,只亮其中一盏LED。所以,控制字节的低4位中,同一时刻,只有1位是1,其余位为0,并且,1的位置从低位向高位顺序移动,移到第4位后回到第1位。,代码略,第,13,章 控制板载,LED,1.,按键介绍
29、提纲,2.,读取按键,3.,按键控制,LED,1.,按键介绍,网关的开发板上提供了9个物理按键,可以用于模拟实际应用中的用户输入。按键编号从0开始,分别命名为k0k9。k0和系统lock共用一个按键,电路板上没有打印“k0”字样。物理按键被分成了3组,第1组只有1个k0;第2组包含4个按键,从左到右分别是k1、k2、k3、k4;第3组同样包含4个按键,从左到右分别是k5、k6、k7、k8。,1.,按键介绍,要在我们的程序中使用按键,需要先停止,hotkey,服务。,#service hotkey stop,每次按键被分解成两个动作:按下和松开。某个键被按下时,驱动程序返回该键的“序号值,+1
30、的字符形式给应用程序;举例来说,按下,k0,,得到的键值是字符,1,;按下,k5,,得到的键值是字符,6,。松开任何按键时,驱动程序都会返回,0,字符。应用程序通过读取设备文件获得按键值。,2.,读取按键,代码详见课本,此处略,3.,按键控制,LED,控制系统最基本的任务是根据输入信号控制设备工作。控制系统的一般模型如图。,3.,按键控制,LED,在本例子中,我们模拟一个简单的控制系统,开发板上的物理按键作为输入设备,板载LED作为受控设备。根据物理按键的状态控制LED的亮灭。具体的业务逻辑是:,1、按照图13-11的按键物理分组,把按键的逻辑功能分为3组。,2、第1组只有k0一个按键,作
31、为控制系统的退出按键。用户按下k0,控制系统结束工作。,3、第2组按键为k1k4,按下其中一个键,亮对应编号的LED,其余LED熄灭。比如按下k2,LED2亮起,LED1、LED3、LED4熄灭;按下k4,LED4亮起,LED1、LED2、LED3熄灭。,4、第3组按键为k5k8,其功能为对应k1k4的反相功能,亦即是,k5为k1的反相,按下k5时,LED1熄灭,其余3盏LED亮起;k6为k2的反相,按下k6时,LED2熄灭,其余3盏LED亮起。依次类推。,5、松开k1k8,熄灭所有LED。,代码略。,第,14,章 串口通信,1.,串口通信基础,提纲,2.,串口通信编程,1.,串口通信基础,传
32、统的近距离1对1通信有并行方式和串行方式。所谓并行,是指同时传输一个字节的8个二进制位;而串行,则是指每次只传输1个二进制位。,1.,串口通信基础,导致并行通信的传输线和接口体积都较大,一般使用25针的D型接口。串行通信一般常用9针的D型接口。,1.,串口通信基础,实验箱串口。,2.,串口通信编程,UART是串行异步通信方式,帧是UART通信中最基本单元,它主要包含:开始位,数据位,校验位(如果开启了数据校验,要包含校验位),和停止位。,2.,串口通信编程,函数是,tcgetattr(),,用于获得串口的属性值。原型为:,int tcgetattr(int fd,struct termios*
33、termios_p);,2.,串口通信编程,struct termios,定义:,1,2,3,4,5,6,7,8,9,1011,struct termios,tcflag_t c_iflag;/*input mode flags*/,tcflag_t c_oflag;/*output mode flags*/,tcflag_t c_cflag;/*control mode flags*/,tcflag_t c_lflag;/*local mode flags*/,cc_t c_line;/*line discipline*/,cc_t c_ccNCCS;/*control characters*/,speed_t c_ispeed;/*input speed*/,speed_t c_ospeed;/*output speed*/,;,2.,串口通信编程,tcsetattr(),,用于设置串口的属性值。原型为:,int tcsetattr(int fd,int optional_actions,const struct termios*termios_p);,2.,串口通信编程,使用串口的一般步骤,






