第六章——嵌入式软件程序设计

前言:
   计算机第六章节主要知识点。

1 知识点介绍

  • 嵌入式系统开发与设计;
  • 嵌入式程序设计;
  • 下午题训练;

2 嵌入式系统开发与设计

  • 嵌入式应用开发概述;
  • 嵌入式软件开发环境;
  • 嵌入式软件开发流程;

  一个嵌入式应用项目的开发过程是一个硬件设计和软件设计的综合过程,一般而言要经历以下几个步骤:

  • 硬件的设计与实现;
  • 设备驱动软件的设计与实现;
  • 嵌入式操作系统的选择、移植,以及API接口函数的设计;
  • 支撑软件的设计与调试;
  • 应用程序的设计与调试;
  • 系统联调,样机交付;

BuildAndLoad.png

  嵌入式软件开发有如下的几个特点。

  • 需要交叉编译工具;
  • 通过仿真手段进行调试;
  • 开发板是通过中间目标机;
  • 可利用的资源有限;
  • 需要与硬件打交道;

  嵌入式软件开发的挑战。

  • 软硬件协同设计;
  • 嵌入式操作系统;
  • 代码优化;
  • 有限的I/O功能;

3 嵌入式软件开发环境

  嵌入式系统开发最大特点:软硬件综合开发。

  • 嵌入式产品是软硬件的结合体;
  • 软件针对硬件开发、固化,不能进行任意修改;

  嵌入式软件开发模式通常包括三种。

  • 本机开发;
  • 交叉开发;
  • 模拟开发;

  交叉开发。

CrossDevelopment.png

  宿主机和目标机。

Link.png

3.1 例题

  以下关于嵌入式系统开发的叙述,正确的是(C)。

A. 宿主机与目标机之间只需要建立逻辑连接。
B. 宿主机与目标机之间只能采用串口通信方式。
C. 在宿主机上必须采用交叉编译器来生成目标机的可执行代码。
D. 调试器与被调试程序必须安装在同一台机器上。

4 嵌入式软件开发流程

  三个阶段。

  • 分析
  • 设计
  • 实现

  流程。

  • 嵌入式平台选型
  • 软件设计
  • 特性设计
  • 编码
  • 测试
  • 下载和运行

5 下载与运行

Download.png

6 嵌入式程序设计

  • 程序设计语言
  • 面向过程的语言(c语言基本概念)
  • 面向对象的语言(c++语言基本概念)

ProgrammingLanguage.png

  各种程序语言特点。

  • Fortran语言(科学计算,执行效率高);
  • Pascal语言(为教学而开发的,表达能力强,Delphi);
  • c语言(指针操作能力强,高效);
  • Lisp语言(函数式程序语言,符号处理,人工智能);
  • c++语言(面向对象,高效);
  • Java语言(面向对象,中间代码,跨平台);
  • c#语言(面向对象,中间代码,.Net);
  • Prolog语言(逻辑推理,简洁性,表达能力,数据库和专家系统);
  • Python语言(一种脚本语言);

6.1 程序语言的数据成分

  数据是程序操作的对象,具有以下属性。程序设计语言的基本成分包括:数据、运算、控制和传输。

  • 数据名称:由用户通过标识符命名;
  • 数据类型:说明数据占用内存的大小和存放形式;
  • 存储类型:说明数据在内存中的位置和生存期;
  • 作用域:说明可以使用数据的代码范围;
  • 生存期:说明数据占用内存的时间范围;
数据类型
基本类型:整形、字符型、实型、布尔型
特殊类型:空类型(void)
用户定义类型:枚举类型
构造类型:数组、结构、联合
指针类型:type*
抽象类型:类类型

  数据类型转换规则:char,short -> int -> unsigned -> long, float -> double。

6.2 程序语言的运算成分

  指明允许使用的运算符号及运算规则,运算符号要规定优先级和结合性,大多数高级程序语言的基本运算包括了。

  • 算术运算
  • 关系运算
  • 逻辑运算
  • 位运算

6.3 程序语言的控制成分

  三种基本逻辑结构。

  • 顺序结构:是一种线性有序的结构,由一系列依次执行的语句或模拟块构成;
  • 循环结构:是由一个或几个模块构成,程序运行时重复执行,直到满足某一条件为止;
  • 选择结构:是根据条件成立与否选择执行路径的结构;

  函数参数的传值和传址。

  • 传值调用:实际上重新复制了一个副本给形参,不改变调用函数实参变量的内容。
  • 传址调用:将实参地址给形参,将改变调用函数实参变量的内容。

6.4 例题

  函数t()、f()的定义如下所示。若调用函数t()时传递给x的值为3,并且调用函数f()时,第一个参数采用传值(call by value)方式,第二个参数采用传引用(call by reference)方式,则函数t()的返回值为(B)。

A. 35
B. 24
C. 22
D. 11

7 表达式

  • 前缀表达式(+ab)
  • 中缀表达式(a + b)
  • 后缀表达式(ab-),逆波兰式。

7.1 例题

  表达式 (a - b) * (c + 5) 的后缀式是(D)。

A. abc5+-
B. ab-c+5

C. abc-5+
D. ab-c5+

  解题方法。

  • 方法一:先构造二叉树,再后序遍历。
  • 方法二:加括号,再移动运算符到有括号后。

8 高级程序设计语言

  解释程序和编译程序。

  • 编译程序:也称为编译器,目标语言程序;
  • 解释程序:也称解释器,源程序,或者中间代码;
  • 根本区别:是否产生独立的目标程序?

  基本概念。

  • 语句
  • 语法
  • 语义
  • 语用

8.1 编译器的工作阶段

  • 词法错误:非法字符,关键字或标识符拼写错误。
  • 语法错误:语法结构出错,if…end if不匹配,缺分号。
  • 语法错误:死循环,零除数,其他逻辑错误。

Stage.png

8.2 解释程序基本原理

  解释程序是另一种语言处理程序,在词法、语法和语义分析方面与编译程序的工作原理基本相同。
  但在运行用户程序时,它直接执行源程序或源程序的内部形式。因此解释程序与编译程序最大的区别在于不产生源程序的目标程序。

  • 解释程序通常分为两部分。
    • 分析部分,包括通常的词法分析语法分析和语义分析程序,经过分析后把源程序翻译成中间代码。
    • 解释部分,用来对第一部分所产生的中间代码进行解释执行。

  解释语句实现高级语言的三种方式。

  • 源程序被直接解释执行的处理方式,如图标记A,这种解释程序对源程序逐个字符进行检查,然后执行语句规定的动作。如GOTO L。
  • 解释程序也可以先将源程序翻译成某种中间代码形式,然后对中间代码进行解释,实现用户程序的运行。解释方式B和C的不同之处在于中间代码的级别。

Realize.png

8.3 例题

  以下关于编译和解释的叙述中,正确的是(A)。

  1. 编译是将高级语言源代码转换成目标代码的过程。
  2. 解释是将高级语言源代码转换成目标代码的过程。
  3. 在编译方式下,用户程序运行的速度更快。
  4. 在解释方式下,用户程序运行的速度更快。

A. 1 3
B. 1 4
C. 2 3
D. 2 4

  编译程序对高级语言源程序进行编译的过程中,要不断手机、记录和使用源程序中一些相关符号的类型和特征等信息,并将其存入(A)中。

A. 符号表
B. 哈希表
C. 动态查找表
D. 栈和队列

9 面向过程的语言

9.1 c预处理

Pretreatment.png

9.2 预定义宏

Predefine.png

9.3 基本数据类型

PrimaryDataType.png

  • 常量(字面量和const常量);
  • void类型(特殊类型);
  • 数组(构造类型);
  • 枚举类型(自定义类型);
  • 结构体、位域和共用体(构造类型);

9.4 存储管理

  当一个函数调用时,它的内部机理是什么,执行了哪些步骤?如图所示是一个程序运行时的内存分布。

MemoryManagement.png

9.5 函数调用过程

1
2
3
4
5
6
7
int z;
void main(){
int x, y;
x = 1;
y = 2;
z = x + y;
}
  1. 程序开始运行时,main函数被装入到内存,代码存放在内存的代码区域。
  2. 全局变量区域分配了一个存储单元给变量z,并初始化为0。
  3. 接下来,系统调用主函数main去运行。
  4. 当这个函数调用发生时,系统就会在栈中给他分配一块内存空间(栈帧),存放main函数内部定义的局部变量x,y。
  5. PC跳转到主函数的第一条语句,开始执行。
  6. 函数执行完后,首先释放栈帧,x和y所占用的控件被释放,不能再访问。
  7. 整个程序结束,全部变量z释放,不能再访问。

9.6 变量的存储与作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*全局变量,固定地址,其它源文件可见*/
int global_static;
/*静态全局变量,固定地址,但只在本文件中可见*/
static int file_static;

/*函数参数,位于栈帧当中,动态创建,动态释放*/
int foo(int auto_program)
{
/*静态局部变量,固定地址,只在本函数中可见*/
static int func_static;

/*普通局部变量,位于栈帧当中,只在本函数中可见*/
int auto_i, auto_a[10];

/*动态申请的内存空间,位于堆当中*/
double *auto_d = malloc(sizeof(double) * 5);

return auto_i;
}

9.7 面向对象的语言

  Peter Coad和Edward Yourdon提出用下面的等式来识别面向对象方法,采用这四个概念开发的软件系统是面向对象的。

ObjectOriented.png

  面向对象的三个特点:多态、重载、覆盖。

9.10 例题

  问题:阅读下列说明和c语言代码,回答问题1至问题3,将解答填入答题纸的对应栏内。

【说明】

  在某工厂的物流车间,设计一款智能监测系统,实现对车间进行24小时不间断图像采集的功能。王工设计了一个实时监测采集系统,主要由图像采集卡和数据存储卡组成。由于实时图像的数据量巨大,设计采用DMA方式进行数据传输,当DMA传输完成后,DMA控制器会发起一个硬件中断,操作系统接收到硬件中断,调用中断服务程序。
  该系统的软件基于嵌入式操作系统开发,支持中断管理、多任务调度等功能,与DMA相关的一段驱动程序示例代码如下。

ex1.png

ex2.png

  DMA传输函数。返回值1表示正常完成,2表示传输超时,4表示奇偶校验错。

ex3.png

ex4.png

【问题1】(5分)

  在操作系统的头文件中,有如下类型定义:

1
2
typedef void (*VOIDFUNCPTR)(); /*ptr to function returning void*/
typedef (*FUNCPTR)(); /*ptr to function returning int*/
  1. 该类型定义了一组什么类型的变量,简述其功能。
  2. 在【程序1】的dma_init函数中,应该将intConnect函数的第二个参数转换成相应的类型,可以消除编译警告,请补充其中空(1)的内容。

【问题2】(4分)

  DMA控制器的寄存器操作序列,必须为原子操作,该程序中使用了两个信号量,一个用于进行寄存器操作系统的临界区保护,一个用于在传输函数和DMA完成中断处理程序之间同步。请根据信号量创建时的不同初始值,在【程序2】的dma_trans函数和【程序3】dma_intHandle函数中,补充空(2)、(3)、(4)、(5)处的内容。

【问题3】(6分)

  在该系统中有A、B两个应用任务同时从不同角度采集图像,都需要调用该DMA传输函数,任务A和任务B的优先级相同。该系统采用优先级抢占的调度策略。在任务A调用DMA传输函数进行传输时,有时会出现函数返回值为0的情况。根据DMA控制器的芯片手册定义,1表示正常完成,2表示传输超时,4表示奇偶校验错,所以返回值不应该为0.
  王工经过认证排查后,分析该故障发生的原因是当任务A调用dma_trans函数时,会发生任务suspend的情况,此时如果任务B也调用dma_trans函数,则会发生上述故障。

  1. 请给出dma_trans函数中会导致任务发生阻塞的代码行号。
  2. 按照王工的分析,对全局变量的不正确操作会导致该函数的返回值错误,请给出发生错误的代码行号。
  3. 王工对该程序进行了改进,将上述会导致返回值错误的代码放在某一行程序之后执行,即可解决该问题。请给出代码行号。注意:这里的行号是指【程序2】中注释所标的第1行到第5行,请在第1行到第5行之中选择。

【参考答案】

【问题1】

  1. 该类型定义了一组函数指针类型的变量。使用typedef给函数指针类型一个别名。

(1) VOIDFUNCPTR

【问题2】

(2) sem_DMA1
(3) sem_DMA2
(4) sem_DMA1
(5) sem_DMA2

【问题3】

  1. 第3行
  2. 第1行
  3. 第2行

10 总结

  本章着重考查嵌入式软件程序设计知识,考查形式主要是概念区分以及部分计算题型,不仅出现在上午的选择题当中,还出现在下午的应用技术提当中。