第六章 嵌入式软件程序设计
嵌入式系统开发与设计
- 一个嵌入式应用项目的开发过程是一个硬件设计和软件设计的综合过程,一般而言要经历以下几个步骤:
- 硬件的设计与实现
- 设备驱动软件的设计与实现
- 嵌入式操作系统的选择、移植,以及API接口函数的设计
- 支撑软件的设计与调试
- 应用程序的设计与调试
- 系统联调,样机交付
- 嵌入式应用程序的生成与加载
- 嵌入式软件开发有如下的几个特点
- 需要交叉编译工具
- 通过仿真手段进行调试
- 开发板是中间目标机
- 可利用的资源有限
- 需要与硬件打交道
- 嵌入式软件开发的挑战
- 软硬件协同设计
- 嵌入式操作系统
- 代码优化
- 有限的I/O功能
- 嵌入式系统开发的最大特点:软硬件综合开发
- 嵌入式产品是软硬件的结合体
- 软件针对硬件开发、固化,不能进行任意修改
- 嵌入式软件开发模式通常是包括三种
- 本机开发
- 交叉开发
- 模拟开发
- 嵌入式软件开发流程
- 嵌入式平台选型
- 软件设计
- 特性设计
- 编码
- 测试
- 下载和运行
嵌入式程序设计
程序设计语言
程序设计语言
各种程序语言特点
- Fortran语言(科学计算,执行效率高)
- Pascal语言(为教学而开发的,表达能力强,Delphi)
- C语言(指针操作能力强,高效)
- Lisp语言(函数式程序语言,符号处理,人工智能)
- C++语言(面向对象,高效)
- Java语言(面向对象,中间代码,跨平台)
- C#语言(面向对象,中间代码,.Net)
- Prolog语言(逻辑推理,简洁性,表达能力,数据库和专家系统)
- Python语言(一种脚本语言)
程序语言的数据成分
- 数据是程序操作的对象,具有以下属性
- 数据名称:由用户通过标识符命名
- 数据类型:说明数据占用内存的大小和存放形式
- 存储类别:说明数据在内存中的位置和生存期
- 作用域:说明可以使用数据的代码范围
- 生存域:说明数据占用内存的时间范围
- 程序设计语言的基本成分包括:
- 数据
- 运算
- 控制
- 传输
- 数据类型
- 基本类型:整型、字符型、实型、布尔类型
- 特殊类型:空类型(void)
- 用户定义类型:枚举类型
- 构造类型:数组、结构、联合
- 指针类型:type*
- 抽象类型:类类型
- 数据类型转换规则:char,short->int->unsigned->long,float->double
程序语言的运算成分
- 指明允许使用的运算符号及运算规则,运算符号要规定优先级和结合性,大多数高级程序语言的基本运算包括了
- 算术运算
- 关系运算
- 逻辑运算
- 位运算
程序语言的控制成分
- 三种基本逻辑结构
- 顺序结构:是一种线性有序的结构,由一系列依次执行的语句或模块组成
- 循环结构:是由一个或几个模块构成,程序运行时重复执行,直到满足某一条件为止
- 选择结构:是根据条件成立与否选择执行路径的结构
传值/传址
- 传值调用:实际上重新复制了一个副本给形参,不改变调用函数实参变量的内容
- 传址调用:将实参地址给形参,将改变调用函数实参变量的内容
表达式
- 前缀表达式
+ab
- 中缀表达式
a+b
- 后缀表达式
ab+
(逆波兰式)
编译器的工作阶段
- 词法错误:非法字符,关键字或标识符拼写错误
- 语法错误:语法结构出错,if…end if不匹配,缺分号
- 语义错误:死循环,零除数,其他逻辑错误
解释程序基本原理
解释程序是另一种语言处理程序,在词法、语法和语义分析方面与编译程序的工作原理基本相同
但在运行用户程序时,它直接执行源程序或源程序的内部形式。因此,解释程序与编译程序最大的区别就是不产生源程序的目标程序
解释程序通常可分为两部分
- 分析部分,包括通常的词法分析、语法分析和语义分析程序。经分析后把源程序翻译成中间代码
- 解释部分,用来对第一部分所产生的中间代码进行解释执行
解释语句实现高级语言的三种方式
- 源程序被直接解释执行的处理方式,如图标记A,这种解释程序对源程序逐个字符进行检查,然后执行语句规定的动作。如GOTO L
- 解释程序也可以先将源程序翻译成某种中间代码的形式,然后对中间代码进行解释,实现用户程序的运行。解释方式B和C的不同之处在于中间代码的级别
C预处理
#define
:定义宏#include
:包含一个源代码文件#undef
:取消已定义的宏#ifdef
:如果宏已经定义,则返回真#ifndef
:如果宏没有定义,则返回真#if
:一般含义是如果#if
后面的常量表达式为true
,则编译它与#endif
之间的代码,否则跳过这些代码#else
:类似C语言中的else
,#else
建立另一选择(#if
失败的情况下)#elif
:类似于elseif
,它形成一个if else-if
阶梯状语句,进行多种编译选择#endif
:标识一个#if
块的结束#error
:当遇到标准错误时,输出错误消息#pragma
:使用标准化方法,向编译器发布特殊的命令到编译器中
预定义宏
__DATE__
:当前源文件的编译日期,格式为“Mmm dd yyyy”的字符串字面量__TIME__
:当前源文件的编译时间。格式为“hh:mm:ss”的字符串字面量__FILE__
:当前源文件名称,含路径信息__FUNC__
:当前函数名称__LINE__
:当前程序行的行号,表示为十进制整型常量__STDC__
:若当前编译器符合ISO标准,那么该宏的值为1,否则未定义__STDC_HOSTED__
:(C99)如果当前是宿主系统,则该宏的值为1,否则为0
数据类型
- 基本数据类型
- 变量
- 常量(字面量和const常量)
- void类型(特殊类型)
- 数组(构造类型)
- 枚举类型(自定义类型)
- 结构体、位域和共用体(构造类型)
存储管理
- 如图所示是一个程序运行时的内存分布
函数调用的过程
- 程序开始运行时,main函数被装入到内存,代码存放在内存的代码区域
- 全局变量区域分配了一个存储单元给变量z,并初始化为0
- 接下来,系统调用主函数main去运行
- 当这个函数调用发生时,系统就会在栈中给它分配一块内存空间(栈帧),存放main函数内部定义的局部变量x,y
- PC跳转到主函数的第一条语句,开始执行
- 函数执行完后,首先释放栈帧,x和y所占用的空间被释放,不能再访问
- 整个程序结束,全部变量z释放,不能再访问
变量的存储与作用域
面向对象的语言
- Peter Coad和Edward Yourdon提出用下面的等式来识别面向对象方法,采用这四个概念开发的软件系统是面向对象的