单片机应用程序设计方法

单片机应用程序设计方法

邬杨波

2008-6-14

目 录

第一章 单片机应用程序设计步骤

1.1 需求分析

1.2 开发方案的制定与系统设计

1.3 代码编写及调试

1.4 程序的测试

1.5 程序的维护

第二章 单片机程序结构的组织与设计

2.1 概述

2.2 程序的基本结构

2.3 顺序调度程序结构

2.4 优先调度程序结构

2.5 中断与前/后台程序结构

2.6 时间片与分时调度机制

2.7 键码分析调度机制(一键一义型结构)

2.8 基于状态机的程序调度机制

第三章 模块化的设计方法

3.1 概 念

3.2 模块设计原则

3.3 C语言模块化程序结构

3.4 设计中常用模块分类

第四章 常用功能模块设计

4.1 按键

4.2 显示

4.3 时钟

第一章 应用程序设计步骤

单片机应用软件的开发设计必须遵循系统工程和软件工程。传统的软件生命周期模型是一种顺序模型,自顶向下把一个软件开发过程分为:系统定义、需求分析、设计、编码、测试和维护等阶段。在开发过程中这些阶段顺序进行就象是一个飞流直下的瀑布,因此叫做瀑布模型。主要分为以下几个阶段:

(1)项目可行性分析

这一阶段要对拟开发的项目进行可行性论证,包括两方面的内容:其一技术可行性分析,对现有软件和成熟的技术进行研究,看是否实现项目要求;其二分析经费可行性,看目前的经济条件能否适应项目的要求。项目可行性分析的最后成果是给出一份任务分析书。

(2)需求分析阶段

这一阶段主要解决“做什么”的问题,根据提出的问题写出需求分析文档,确定要解决的目标、实现的功能、系统的性能及数据在系统中的流向等,为以后的开发设计提供依据。

(3)系统设计阶段

这一阶段主要解决“怎么做”的问题,分为系统架构设计和详细设计两个阶段。架构设计根据需求分析的结果和系统设计目标等将系统分解成若干子系统,确定每个子系统的功能、系统的总体结构、各个子系统间的关联。

详细设计确定每个子系统的名称、子系统的功能描述及解决算法,各个子系统的输入输出信息,各个子系统之间的输入和输出接口。

(4)编码调试阶段

根据上一阶段的设计方案,用某种编程语言编写调试程序。

(5)测试阶段

一般在需求阶段就开始写测试计划,包括测试用例、测试标准、测试方法等。测试可以分为单元测试、集成测试、系测试、接收测试等测试活动。

单元测试一般由程序员执行,按模块或类进行测试,包括黑盒测试和白盒测试。

集成测试是将几个或所有子系统集成后进行的测试,测试子系统的接口、关联,共同工作所完成的功能及达到的性能。

系统测试是从用户的角度进行的测试,包括对最终运行环境等的测试,主要是黑盒测试。

接收测试是根据合同及需求描述的要求,测试系统是否达到接收标准。每项测试活动都要求有完整的测试记录,开发人员要根据测试结果修改程序。程序修改完之后,要进行回归测试。

(6)运行与维护阶段

运行程序是软件设计的最终目的,到此设计过程已基本完成,但是程序在运行过程中还会出现各种问题,这是设计者有责任进行程序的维护。

瀑布模型法是较传统的有一种程序开发方法,存在一些缺点:项目的各个阶段缺少反馈,只有在项目的生命周期的最后才能看到结果。通过过多的强制完成

日期和里程碑来跟踪各个项目阶段等。因此,实际中又提出了许多软件开发模型,如增量模型、螺旋模型、RUP迭代模型等。但是不论哪一种模型都无法完全适应嵌入式软件的开发。

根据以上分析,接下来我们将从需求分析开始,较为详细的讨论各种阶段的任务、应采用的方法,最后结果的表示等问题。

1.1 需求分析

1.1.1 什么是需求分析

在软件开发领域,人们越来越多地提到需求。和其他领域一样,这里的需求源自用户的“需要”,而不同则在于开发软件系统最困难的部分就是准确说明开发什么,这就是软件项目的需求。

为什么我们如此多的关注需求?原因恰恰在于我们无法有效地获取需求,我们无法准确地表述需求,而需求的变化对于整个项目的成本、周期影响极大,所谓“一石激起千层浪”。所以,想让项目获得成功,首先要做好需求分析。

那么什么是需求分析呢?需求就是关于系统应该“做什么”而不是“怎么做”的问题描述。IEEE软件工程标准词汇表(1997年)中定义需求为:

(1)用户解决问题或达到目标所需的条件或权能(Capability)。

(2)系统或系统部件要满足合同、标准、规范或其它正式规定文档所需具有的条件或权能。

(3)一种反映上面(1)或(2)所描述的条件或权能的文档说明。

需求通常分为需求定义和需求分析两个阶段。需求定义产生客户理解的系统规格说明书,需求分析产生开发人员可以清楚解释的分析模型。

需求的明确与否,将直接影响着后继设计、开发与实现。软件项目中百分之四十至百分之六十的问题都是在需求分析阶段埋下的“祸根”(Leffing well 1997)。

开发软件系统最为困难的部分就是准确说明开发什么。最为困难的概念性工作便是编写出详细技术需求,这包括所有面向用户、面向机器和其它软件系统的接口。同时这也是一旦做错,将最终会给系统带来极大损害的部分,并且以后再对它进行修改也极为困难。

为什么这么说呢,因为在大多数的软件系统中,最终用户可能都不清楚他的需求是什么,这是千真万确的。如果你的用户告诉你需求就是这些了,不要相信他,继续刨根问底,直到你们都筋疲力尽了。

1.1.2 系统需求定义

需求定义阶段主要是收集需求,与用户一起定义验证所收集的需求,并提交需求规格说明书。需求定义阶段明确系统所要实现的功能以及所要达到的性能,是整个系统开发目标的准确描述。

需求定义的概念。

1、功能性需求

功能性需求是系统功能的陈述,明确系统应该提供什么功能。

2、非功能性需求

非功能性需求是指与系统功能行为没有直接关系但是用户可见的系统部分,是系统的特定特性,以保证功能的正常实现、优化产品的功能或限定产品应达到的目标值。非功能性需求对确定系统的结构和系统选用的技术进行了约束,包括定量约束。最常见的非功能性需求有:

z 可靠性

z 可用性

z 安全性

z 耐用性

z 产品的最终价格

z 系统处理速度

z 系统的尺寸和质量

z 系统的功耗

3、伪需求

伪需求是客户强加的需求,它约束系统的实现。典型的为需求是实现系统的编程语言和运行平台。

4、需求描述的要求

需求定义的最终目的是要获得没有二义性、的全面的、详尽的目标需求。因此,需求规格说明书需要满足一定的要求。这些要求包括:

高质量需求叙述的特性

正确性:每个需求必须精确描述要交付的功能。正确性依据于需求的来源,如真实的客户或高级别的系统需求说明书。一个软件需求与其对应的系统需求说明书相抵触是不正确的(当然,系统需求说明书本身可能不正确)。

可行性:在已知的能力、有限的系统及其环境中每个需求必须是可实现的。为了避免需求的不可行性,在需求分析阶段应该有一个开发人员参与,在抽象阶段应该有市场人员参与。这个开发人员应能检查在技术上什么能做什么不能做,哪些需要需要额外的付出或者和其他的权衡。

每个需求应载明什么是客户确实需要的,什么要顺应于外部的需求, 必要性:

接口或标准。每个需求源于你认可、具有权说明需求的原始资料,这是考虑必需的另外情形(译注,此句翻译不顺,请参照原文:Another way to think of “necessary” is that each requirement originated from a source you recognize as having the authority to specify requirements)。跟踪每个需求回溯到出处,如用例,系统需求,规章,或来自其他用户的意见。如果你不能标识出处,可能需求只是个镀金的例子,没有真正的必须。

优先权:为了表明在一个详细的产品版本中应包含哪些要点,需要为每个需求,特征,或用例分配实现的优先权。客户或其代理都应有强烈的责任建立优先权。如果所有的需求都被视为同等重要,那么由于在开发中,预算削减,计划超时或组员的离开导致新的需求时, 项目经理将不能起到作用。优先权的作用是提供给客户的价值,实现的相关费用,实现相关联的有关技术风险。 我是用3种级别的优先权:高优先权表明需求必须体现在下一个产品版本中,中优先权表明需求是必须的,但是如果需要可以推迟到晚一些的产品版本中,低优先权表明有它很好,但我们必须认识到如果没有充足的时间或资源,它可以被

放弃掉。

明确性:需求叙述的读者应只能从其得到唯一的解释说明,同样,一个需求的多个读者也应达成共识。自然语言极易导致含糊。要避免使用一些对于SRS作者很清楚但对于读者不清楚的主观词汇,如:用户友好性,容易,简单,快速,有效,几个,艺术级,改善的,最大,最小等等。每写一个需要都应简洁,简单,直观的采用用户熟知的语言,不要采用计算机术语。检查需求模糊的有效方式包括需求说明书的正规检查,根据需求写测试,建立用户的假想来说明产品某个特定部分预期的特性。

可证实:看你是否能够做出测试计划或其他验证方式,如检查和实证,来决定在产品中每个需求是否正确的实现。如果需求是不可验证的,决定需求是不是正确的实现就成了判断的事。需求之间不一致,不可行,不明确也能导致不可证实。任何需求如果说产品将要支持什么也是不可证实的。

高质量需求说明的特征

完整性:不应该遗漏要求和必需的信息。完整性也是一个需求应具备的。发现缺少的信息很难,因为根本不存在。在SRS中将需求以分层目录方式组织,将帮助评审人员理解功能性描述的结构,使他们很容易指出遗失的东西。 一致性:一致性需求就是不要于其他的软件需求或高级别的系统(商业)需求发生冲突。需求中的不一致必须在开发开始前得到解决。只有经过调研才能确定哪些是正确的。修改需求时一定要谨慎,如果只审定修改的部分,没有审定于修改相关的部分,就可能导致不一致性。

可修改性:当每个需求的要求修改了或维护其历史更改时,你必须能够审定SRS。也就是说每个需求必须相对于其他需求有其单独的标示和分开的说明,便于清晰的查阅。通过良好的组织可以使需求易于修改,如:将相关的需求分组,建立目录表,索引,以及前后参考(照)。

可追踪:你应能将一个软件与其原始材料相对应,如高级系统需求,用例,用户的提议等。也能够将软件需求与设计元素,源代码,用于构造实现和验证需求的测试相对应。可追踪的需求应该具有独立标示,细密和结构化的编写,不应过大,不应是叙述性的文字和公告式的列表。

5、需求质量的评审

这些有关需求质量的特性的描述在理论上都是非常好的,但一个好的需求到底是个什么样子的呢?为了体现得更切合实际,我们做个小练习。下面有几个从实际的工程选出的需求,依据上面的质量标准,评估每个需求,看看有什么问题,然后用更好的方式重写。我将对每个例子都提出自己的分析和改进的建议。也欢迎你提出不同的见解。我所占优的只是我知道每个需求的出处。因为你我都不是真正的客户,我们只能猜测每个需求的意图。

例1、“产品应在不少于每60秒的正常周期内提供状态信息”

这个需求是不完整的:状态信息是什么,如何显示给用户。这个需求有几处含糊。我们在谈论产品的哪部分?状态信息间隔真的假定为不少于60秒? 甚者每10年显示一条新的状态信息也可以?也许它的意图是消息间隔不应超过60秒,那么1毫秒是不是太短?“每”这个词导致了不确定性。问题的后果,就是需

求的不可证实。

弥补缺陷,重写需求的一种方法:

1、状态信息

1.1后台任务管理器因该以误差上下不超过10秒的60秒间隔,在用户界面的指定位置显示状态信息

1.2如果后台进程处理正常,那么应该显示任务已完成的百分数/比

1.3任务完成时,应显示相关的信息

1.4后台任务出错应该显示错误信息

为了分别测试和追踪,我将其分成了多个需求。如果将几个需求串接在一节中,在构造和测试时就很容易漏掉一个。

例2、“产品应瞬间在显示和隐藏不可打印字符间切换”

计算机在瞬间不能做任何事,所以这个需求不切实可行。它的不完整性表现在没有声明触发状态切换的条件。软件要在某些条件下更改自己?或者用户为了模仿更改要做一些动作?而且,在文档中改变显示的范围是多大:选中的文本,整个的文档,或其他的?这也是个模糊的问题。不可打印字符合隐藏字符一样吗?或者是一些属性标志或一些控制字符?问题的后果,就是需求的不可证实。 象这样编写需求也许更好一些:“用户能够在一个由特定触发条件激活处于编辑的文档中在显示和隐藏所有HTML标记间切换”。现在就很清楚,不可打印字符是HTML标记。由于没有定义触发条件,需求对设计没有约束力。只有设计人员选定了触发条件后,你才能编写测试验证触发的正确操作。

例3、“HTML分析器可以产生HTML标记错误报告,帮助HTML入门者快速解决错误”。单词“快速”使其模糊,没有加进错误报告的定义也使其不完整。我不知道,你怎么验证这个需求。找一个自称为HTML的入门者,看看能不能根据错误报告快速解决错误?

试试这个:“HTML分析器可以产生一个错误报告,错误报告包含有在被分析文件中出错的HTML文本和行号以及错误的描述。如果没有错误,就不会产生错误报告”。现在我们知道了,什么会被加到出错报告中,但是出错报告是个什么样子,则留由设计人员决定。我们还指定了一个例外:如果没有发现错误,不产生错误报告。

例4、“如果可能,主管号码应通过联机校验,而不是通过主全体主管号码列表校验”。真感到绝望,什么是“如果可能”:如果技术上可行?如果主全体主管号码列表可以联机获得?要避免象“应该”的这类不确切的词。客户是需要这个功能性还是不需要。我曾看过一些需求说明书,采用诸如:应,将,应该/将要等一些词描述优先级的细微差别。但我更喜欢用“应”清楚的说明需求的意图,指明优先级。

这是修改后的:系统应校验输入的主管号码而不通过联机的主全体主官号码列表。如果在列表中没有发现主管号码,将会显示一条错误信息,也不接受指令。

在理解各个已完成的糟糕需求上,开发人员将会遇到的难题是:开发人员与

客户将会在审核需求,未达成共识前发生激烈的争论。详细检查大的需求文档不是一件轻松的事情。我清楚有人做过,而且他们花在检查上的每一分钟都是值得的。相对于开发阶段和用户的抱怨电话,在这个阶段修补缺陷是便宜的,

1.1.3 与客户协商的需求定义方法:联合应用设计

联合应用设计(Joint Application Design, JAD)是IBM公司在20世纪70年代末开发的一套面向结果的头脑风暴式方法。它由固定的、结构化的过程组成,需求定义工作是在一个所有相关人员参与的封闭工作环境中完成的。用户、客户、开发人员和一个训练有素的会议领导者集中在一起谈论他们的观点、倾听别人的观点、共同协商,最后形成一个共同接受的解决方案,工作的最终成果就是JAD文件,该文件是一个完整的需求规格说明文档,包括数据元素、工作流程和用户界面。

JAD主要包括5各活动。

(1)项目定义。由JAD小组共同讨论确定项目的目标、范围、约束及初步的需求。

(2)调查。由系统分析员根据项目定义进行详细的需求访谈,这个过程用户与客户也要做大量的资料收集及配合。调查内容涉及现有系统的状态、存在问题与现有业务相关的各种政策、规范、操作手册、业务数据等。

(3)预备。由相关的分析人员整理调查结果,形成需求文档并列出需确认及要讨论的问题。由项目经理或相关人员安排会议。

(4)会议。召开JAD会议,JAD小组共同讨论需求及相关问题,对有争议的问题,JAD小组领导要给出结论。

(5)最终文件。根据讨论结果,整理出最终的需求规格说明书。

1.1.4 嵌入式系统需求定义常见的问题

序号 常 见 问 题

1 系统用于什么任务?

2 什么时间交付?

3 系统具有哪些功能,完成哪些任务?

4 系统从用户或其他源接收什么输入?

5 系统向用户或其他源接收输出什么信息?

6 用户如何与系统打交道,即进行什么样的人机交互,如在小键盘输入

和显示屏输出?显示屏显示什么内容以及如何规定显示方法?

7 系统的质量和体积如何?

8 系统连接何种外部设备?

9 系统是否需要运行某些现存组件?

10 系统处理哪些种类的数据?

11 系统是否要与别的系统通信?

12 系统是单机还是网络?

13 系统的响应时间是多少?

14 需要什么样的安全措施?

15 系统在什么样的环境下运行?操作温度、湿度和环境参数说明。 16 外部存储介质是什么?内存需要多大?

17 系统的可拆装性、可靠性和牢固度的期望值是什么?

18 如何给系统供电?

19 系统的负载如何?

20 是否使用传感器?传感器的灵敏度、精度、分辨率的要求?

21 系统如何向用户通报故障?

22 是否需要任何手动或机械代用装置?

23 系统是否需要远程诊断或更重问题的功能?

24 系统最大可承受的成本?

25 其他问题?

1.1.5 结构化需求分析:数据流分析

结构化开发方法(Structured Developing Method)是现有的软件开发方法中最成熟,应用最广泛的方法,主要特点是快速、自然和方便。结构化开发方法由结构化分析方法(SA法)、结构化设计方法(SD 法)及结构化程序设计方法(SP 法)构成的。

结构化分析(Structured Analysis,简称SA 法)方法是面向数据流的需求分析方法,是70 年代末由Yourdon,Constaintine 及DeMarco 等人提出和发展,并得到广泛的应用。它适合于分析大型的数据处理系统,特别是企事业管理系统。

SA 法也是一种建模的活动,主要是根据软件内部的数据传递、变换关系,自顶向下逐层分解,描绘出满足功能要求的软件模型。

结构化分析方法的基本思想是“分解”和“抽象”。

分解:是指对于一个复杂的系统,为了将复杂性降低到可以掌握的程度,可以把大问题分解成若干小问题,然后分别解决。图4 是自顶向下逐层分解的示意图。顶层抽象地描述了整个系统,底层具体地画出了系统的每一个细节,而中间层是从抽象到具体的逐层过渡。

抽象:分解可以分层进行,即先考虑问题最本质的属性,暂把细节略去,以后再逐层添加细节,直至涉及到最详细的内容,这种用最本质的属性表示一个自系统的方法就是“抽象”。

SA 法的步骤

⑴建立当前系统的“具体模型”;

系统的“具体模型”就是现实环境的忠实写照,即将当前系统用DFD 图描述出来。这样的表达与当前系统完全对应,因此用户容易理解。

⑵抽象出当前系统的逻辑模型;

分析系统的“具体模型”,抽象出其本质的因素,排除次要因素,获得用DFD 图描述的当前系统的“逻辑模型”。

⑶建立目标系统的逻辑模型;

分析目标系统与当前系统逻辑上的差别,从而进一步明确目标系统“做什么”,建立目标系统的“逻辑模型”(修改后的DFD 图)。

⑷为了对目标系统作完整的描述,还需要考虑人机界面和其它一些问题。 SA 法的描述工具

⑴ 分层的数据流图

⑵ 数据词典

⑶ 描述加工逻辑的结构化语言、判定表或判定树。

数据流图

数据流图(Data Flow Diagram,简称DFD)是描述系统中数据流程的图形工具,它标识了一个系统的逻辑输入和逻辑输出,以及把逻辑输入转换逻辑输出所需的加工处理。

1.数据流图的图符数据流图有以下

4 种基本图形符号:

箭头表示数据流,圆或椭圆表示加工。双杠或者单杠表示数据存储,矩形框表示数据的源点或终点,即外部实体。

⑴ 数据流 是数据在系统内传播的路径,由一组成固定的数据项组成。除了与数据存储(文件)之间的数据流不用命名外,其余数据流都应该用名词或名词短语命名。数据流可以从加工流向加工,也可以从加工流向文件或从文件流向加工,也可以从源点流向加工或从加工流向终点。

⑵ 加工 也称为数据处理,它对数据流进行某些操作或变换。每个加工也要有名字,通常是动词短语,简明地描述完成什么加工。在分层的数据流图中,加工还应有编号。

⑶ 数据存储 指暂时保存的数据,它可以是数据库文件或任何形式的数据组织。流向数据存储的数据流可理解为写入文件,或查询文件,从数据存储流出的数据可理解为从文件读数据或得到查询结果。

⑷ 数据源点和终点 是软件系统外部环境中的实体(包括人员、组织或其他软件系统),统称为外部实体。一般只出现在数据流图的顶层图中。

1.1.6 需求规格说明书模板(暂略)

1.2 开发方案的制定与系统设计

1.3 代码编写及调试

1.4 程序的测试

1.5 程序的维护

第二章 单片机程序结构的组织与设计

本章概述:本章将介绍单片机应用软件系统的组织架构与设计。首先介绍系统监控程序的基本概念及在单片机应用软件体系架构中作用。然后介绍一些常用的单片机系统程序的架构及设计方法,包括简单的顺序调度结构、优先调度结构、时间片分时调度结构、基于状态的调度结构等。

2.1 概述

初学者在学习单片机过程中,就程序设计而言碰到的第一个坎儿就是:如何根据具体的要求来构建程序的框架?在单片机原理等基础型书籍中极少介绍这方面的知识。

所谓程序结构的组织就是如何应用已有的功能模块来控制单片机系统按照预定的操作方式有效的工作,完成所设计的功能。

2.2 程序的基本结构

一个最基本的单片机系统流程结构如图2.1所示。这是一种简单的程序架构。在此结构中包含以下两部分。

1、初始化程序

单片机上电复位后,从复位入口开始运行程序。此时,应该先对系统进行自检和初始化动作。系统的初始化动作包括对I/O、RAM、堆栈、定时器、中断、显示、ADC等其他功能模块的初始化。初始化的动作一般只需要执行一遍。

2、主程序循环体

初始化程序结束后,系统的工作环境已经建立起来了,2.1 基本程序结构

此时可以进入主程序。

主程序一般是个循环体。在这里执行的是程序要实现的具体功能,如输入检测、输出控制、显示等。

具体功能的实现可以由功能语句直接写在主程序中,也可以写成子程序的形式,由主程序进行调用。实际系统实现中都用子程序来实

现具体的功能。

3、模块化的程序结构(简单的顺序调度结构)

所谓模块化的程序结构,主程序仅仅执行调度功能,负责轮流调用功能模块程序。主程序每循环一圈,所有的

功能模块被调用一次,如图2.2所示。

显然,采用这种结构,各个模块之间的相互独立性较

强。我们可以象搭积木一样,很方便地增加或减少主程序

调用的模块。

2.2 模块化程序结构

2.3 顺序调度程序结构

系统运行后按一个预定的顺序依次执行一系列的功能模块(作业),循环不已。这种结构的程序常见于各类无人值守的单片机系统,其操作按钮很少。

功能模块的触发方式:主程序在什么条件下调用各个功能模块。大体可以分为三种:

第一种 接力方式。上一个功能模块执行完成后,无条件的触发下一个功能模块。

第二种 定时方式。预先安排好每道作业的运行时刻表,由系统时钟来顺序触发对应的作业。

第三种 外部信息触发方式。当外部信息满足预定条件时触发相应的作业。

后两种方式可以称之为事件驱动机制,给每个功能模块安排“使能标志”,

通过使能标志来触发该功能模块代表的

事件。在每次进入功能模块时,先判断

该模块是否满足执行条件(功能块使能标志=1?),如果满足则执行,同时将

使能标志清零;否则直接返回即可。功

能模块的结构如图2.3所示。

采用顺序调度机制的特点:

优点:可以保证所有的功能模块都

得到执行的机会,并且这种机会时均等的。 2.3 功能模块程序结构

缺点:有些重要的模块可能无法及

时得到响应。

图2.4 顺序调度机制

2.4 优先调度程序结构

优先调度机制的特征:主程序按照一定的优先级次序,去查询各个标志。如果高优先级功能模块的使能标志有效,则执行该功能模块(并清楚标志),完成之后不再执行后继模块的查询操作,而是跳转到主程序,重新开始新一轮操作。

缺点:排在末位的模块有可能被堵塞。

图2.5优先调度机制

2.5 中断与前/后台程序结构

前述的在主程序中进行事件轮询的调度机制,在应付一般的任务已经足够,但是遇到紧急突发事件,无法保证及时响应。

可以将实时性要求高的事件放到中断中(前台)响应,把实时性要求较低的任务(按键扫描、显示刷新等)交给主程序(后台)去调度。这样就形成了前/后台的程序结构模型。

2.6前/后台程序结构

2.6 时间片与分时调度机制

在系统任务较多时,为了保证每个任务都能得到系统事件,可以尝试分时调度机制。将整个系统时间分成若干个时间片,并用ID进行标识。每个时间片内执行一个功能模块。

我们可以将整个程序中的所有任务都纳入到分时调度机制中。在这种情况下,分时调度的执行者是主程序。程序的结构如图2.7所示。

2.7 主程序中采用时间片分时调度机制

2.7 键码分析调度机制(一键一义型结构)

如果系统的功能之间既没有固定的顺序,也没有固定的优先关系,以上介绍的程序结构就不适用了。常见的情形是系统的工作状态取决于外界的输入,如按键输入。系统根据键盘输入信息决定工作状态。大多数单片机系统都属于这种类型。

由按键和功能的对应关系,此类调度机制可以分为两大类: 一键一义型和一键多义型。对于一键一义型结构,操作者每按下一个按键,系统就获得一个键盘编码信息,然后由键码散转到对应功能模块的入口,启动对应的作业。键盘信息的获取可以由三种方式:

第一种:查询法。主程序用扫描键盘来获取键盘信息,然后执行响应功能。 第二种:中断法。按下任何一个键都可以引起一个外部中断,键码分析过程位于外部中断服务程序中。

第三种:定时查询法。利用定时中断,每隔一定时间查询一次键盘。 三种结构的流程图分别如图2.8、2.9、2.10所示。

2.8主程序查询法调度机制 2.9键盘中断法

2.10定时中断法调度机制

2.8 基于状态机的程序调度机制

2.8.1基于状态机的程序调度机制基本概念与结构

当系统工作状态较为复杂时,作业的调度不仅与外因有关(按键输入、外部触发信号、遥控命令等),也与内因有关(系统当前所处的状态、时间信号等)为了分析设计的方便引入状态机的概念,以简化系统的分析和设计。

基本思路:用状态寄存器来表示程序的工作状态;在调度程序中,根据系统当前工作状态和触发条件,综合解释,执行相应的动作,决定迁移的次态。

在这种系统中,先将系统的工作状态进行划分,并给每个状态编号。当某个按键被触发时,我们在判断按键编号的同时,还要判断系统当前所处的状态(现态)。通过对“键值”和“现态”的综合解释,然后确定执行哪个功能,或者切换到新的工作状态(次态)。这就是“一键多义”的程序调度机制。

图 2.9 一键多义按键执行程序结构图

基于状态机的程序调度机制包含4个要素: 现态-当前所处的工作状态;

条件-触发动作或状态迁移的条件; 动作-条件满足后执行的动作; 次态-条件满足后要迁移的新状态。

2.8.2 基于状态机的单片机程序的设计方法与步骤 1、系统状态的分析

分析系统所有可能的状态,这一步越仔细越好。开始时可以按照系统的功能分成几个状态,然后再逐步细分。 2、状态转移的分析

将各个状态之间的转移关系和转移条件进行仔细分析,即分析

当前状态有可能转移到哪些状态? 转移的条件是什么?

在众多的转移关系和条件中,有很多关系和条件是由用户提出来的,如操作顺序和方式,定时时间和报警门限。因此,必须将这些用户规定的关系和条件弄清。

4、画出状态转移图

可以参考数字电子技术中状态转移图的做法。 5、作出状态转换表

可以参考数字电子技术中状态转移表的做法。

第三章 模块化的程序设计方法

3.1 概 念

模块化程序设计方法,即面向“模块”的程序设计方法(M-O)是属于第二代程

序设计方法。其基本思想是,在结构上将软件系统划分为若干功能“模块”(Module)或实体,分别采用模块化程序设计语言如:PASCAL编程实现;再由各模块联结、组合成相应结构的软件系统。

称为面向模块(Module-Oriented Programming)的程序设计方法或模块化程序设计方法(Module Programming)。也称为面向“实体”的程序设计方法(Entity-Oriented Programming)。 这种(M-O)方法适用于设计模块化、结构化程序,可提高软件系统的模块化、结构化水平,设计和组装较大规模的软件系统,有助于提高软件的通用性、重用性、扩展性。

3.2 模块设计原则 1、模块相对独立性

(1)模块实现相对独立的特定子功能。模块的功能单一,函数处理的任务明确,函数的定义相互独立,一个函数不从属于另一个函数,但可以相互调用。 (2)模块之间的关系简单。模块之间没有过多的相互作用,只通过数据传递发生联系,并且函数传递的数据个数越少越好。例如,C语言禁止使用goto语句作用到另一个函数,以保证函数的独立性。

(3)模块内数据的局部化。模块内使用的数据具有独立性,一个模块不允许使用其它模块的数据,且一个模块的数据也不能影响其他模块中的数据。例如,C语言的局部变量就可以满足模块内数据局部化的要求。 2、模块大小适中 3、模块分解层次清楚

模块化程序设计要求对问题进行逐层分解、逐步细化,形成模块的层次结构。分解问题时要注意对问题进行抽象,将问题中的相似方面集中和概括起来,暂时忽略它们之间的差异,采取自上而下、逐步求精的方法实现。

3.3 C语言模块化程序结构

C就是模块化程序设计语言,基于C语言的程序结构如下图所示。

C语言中模块的构成。即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;

某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明。

模块内的函数和全局变量需在.c文件开头冠以static关键字声明。

一个简单的例子:一个常用的延时模块的结构。该模块由两个文件构成,一个是源程序文件 delay.c 用来定义函数;另一个是头文件 delay.h 用来函数原型声明。

3.4 设计中常用模块分类

1、初始化模块

当系统上电或复位后对CPU本身以及系统外围电路进行一系列的设置,包括:

z CPU内部寄存器初始化

z CPU的I/O端口的初始化

z 软件全局变量的初始化

z 系统外设的初始化等

常用的文件名为:initial.c,initial.h。其中可以包括若干个函数,如initialcpu( )用于对CPU内部寄存器进行初始化;initialcpuIO( )用于对CPU的端口引脚状态进行设置。

2、全局变量模块

用于定义系统需要的全局变量。

常用的文件名为:grobal.c,grobal.h。

3、延时模块

用于定义系统需要的延时函数。可以包含几个不同延时长度的函数,如延时1ms,延时10ms等。

常用的文件名为:delay.c,delay.h。

4、按键输入与处理模块

这是一个较为常用的功能模块,用来定义按键扫描函数和按键处理函数。

5、显示模块

通常用来定义系统的显示函数。根据使用显示器件的不同常见的有:发光二极管、数码管、字符型液晶显示器、图形液晶显示器等。

6、其他功能模块

以上所介绍的是大部分应用系统都会用到的常用功能模块。更重要的模块是实际系统的功能模块。

单片机应用程序设计方法

邬杨波

2008-6-14

目 录

第一章 单片机应用程序设计步骤

1.1 需求分析

1.2 开发方案的制定与系统设计

1.3 代码编写及调试

1.4 程序的测试

1.5 程序的维护

第二章 单片机程序结构的组织与设计

2.1 概述

2.2 程序的基本结构

2.3 顺序调度程序结构

2.4 优先调度程序结构

2.5 中断与前/后台程序结构

2.6 时间片与分时调度机制

2.7 键码分析调度机制(一键一义型结构)

2.8 基于状态机的程序调度机制

第三章 模块化的设计方法

3.1 概 念

3.2 模块设计原则

3.3 C语言模块化程序结构

3.4 设计中常用模块分类

第四章 常用功能模块设计

4.1 按键

4.2 显示

4.3 时钟

第一章 应用程序设计步骤

单片机应用软件的开发设计必须遵循系统工程和软件工程。传统的软件生命周期模型是一种顺序模型,自顶向下把一个软件开发过程分为:系统定义、需求分析、设计、编码、测试和维护等阶段。在开发过程中这些阶段顺序进行就象是一个飞流直下的瀑布,因此叫做瀑布模型。主要分为以下几个阶段:

(1)项目可行性分析

这一阶段要对拟开发的项目进行可行性论证,包括两方面的内容:其一技术可行性分析,对现有软件和成熟的技术进行研究,看是否实现项目要求;其二分析经费可行性,看目前的经济条件能否适应项目的要求。项目可行性分析的最后成果是给出一份任务分析书。

(2)需求分析阶段

这一阶段主要解决“做什么”的问题,根据提出的问题写出需求分析文档,确定要解决的目标、实现的功能、系统的性能及数据在系统中的流向等,为以后的开发设计提供依据。

(3)系统设计阶段

这一阶段主要解决“怎么做”的问题,分为系统架构设计和详细设计两个阶段。架构设计根据需求分析的结果和系统设计目标等将系统分解成若干子系统,确定每个子系统的功能、系统的总体结构、各个子系统间的关联。

详细设计确定每个子系统的名称、子系统的功能描述及解决算法,各个子系统的输入输出信息,各个子系统之间的输入和输出接口。

(4)编码调试阶段

根据上一阶段的设计方案,用某种编程语言编写调试程序。

(5)测试阶段

一般在需求阶段就开始写测试计划,包括测试用例、测试标准、测试方法等。测试可以分为单元测试、集成测试、系测试、接收测试等测试活动。

单元测试一般由程序员执行,按模块或类进行测试,包括黑盒测试和白盒测试。

集成测试是将几个或所有子系统集成后进行的测试,测试子系统的接口、关联,共同工作所完成的功能及达到的性能。

系统测试是从用户的角度进行的测试,包括对最终运行环境等的测试,主要是黑盒测试。

接收测试是根据合同及需求描述的要求,测试系统是否达到接收标准。每项测试活动都要求有完整的测试记录,开发人员要根据测试结果修改程序。程序修改完之后,要进行回归测试。

(6)运行与维护阶段

运行程序是软件设计的最终目的,到此设计过程已基本完成,但是程序在运行过程中还会出现各种问题,这是设计者有责任进行程序的维护。

瀑布模型法是较传统的有一种程序开发方法,存在一些缺点:项目的各个阶段缺少反馈,只有在项目的生命周期的最后才能看到结果。通过过多的强制完成

日期和里程碑来跟踪各个项目阶段等。因此,实际中又提出了许多软件开发模型,如增量模型、螺旋模型、RUP迭代模型等。但是不论哪一种模型都无法完全适应嵌入式软件的开发。

根据以上分析,接下来我们将从需求分析开始,较为详细的讨论各种阶段的任务、应采用的方法,最后结果的表示等问题。

1.1 需求分析

1.1.1 什么是需求分析

在软件开发领域,人们越来越多地提到需求。和其他领域一样,这里的需求源自用户的“需要”,而不同则在于开发软件系统最困难的部分就是准确说明开发什么,这就是软件项目的需求。

为什么我们如此多的关注需求?原因恰恰在于我们无法有效地获取需求,我们无法准确地表述需求,而需求的变化对于整个项目的成本、周期影响极大,所谓“一石激起千层浪”。所以,想让项目获得成功,首先要做好需求分析。

那么什么是需求分析呢?需求就是关于系统应该“做什么”而不是“怎么做”的问题描述。IEEE软件工程标准词汇表(1997年)中定义需求为:

(1)用户解决问题或达到目标所需的条件或权能(Capability)。

(2)系统或系统部件要满足合同、标准、规范或其它正式规定文档所需具有的条件或权能。

(3)一种反映上面(1)或(2)所描述的条件或权能的文档说明。

需求通常分为需求定义和需求分析两个阶段。需求定义产生客户理解的系统规格说明书,需求分析产生开发人员可以清楚解释的分析模型。

需求的明确与否,将直接影响着后继设计、开发与实现。软件项目中百分之四十至百分之六十的问题都是在需求分析阶段埋下的“祸根”(Leffing well 1997)。

开发软件系统最为困难的部分就是准确说明开发什么。最为困难的概念性工作便是编写出详细技术需求,这包括所有面向用户、面向机器和其它软件系统的接口。同时这也是一旦做错,将最终会给系统带来极大损害的部分,并且以后再对它进行修改也极为困难。

为什么这么说呢,因为在大多数的软件系统中,最终用户可能都不清楚他的需求是什么,这是千真万确的。如果你的用户告诉你需求就是这些了,不要相信他,继续刨根问底,直到你们都筋疲力尽了。

1.1.2 系统需求定义

需求定义阶段主要是收集需求,与用户一起定义验证所收集的需求,并提交需求规格说明书。需求定义阶段明确系统所要实现的功能以及所要达到的性能,是整个系统开发目标的准确描述。

需求定义的概念。

1、功能性需求

功能性需求是系统功能的陈述,明确系统应该提供什么功能。

2、非功能性需求

非功能性需求是指与系统功能行为没有直接关系但是用户可见的系统部分,是系统的特定特性,以保证功能的正常实现、优化产品的功能或限定产品应达到的目标值。非功能性需求对确定系统的结构和系统选用的技术进行了约束,包括定量约束。最常见的非功能性需求有:

z 可靠性

z 可用性

z 安全性

z 耐用性

z 产品的最终价格

z 系统处理速度

z 系统的尺寸和质量

z 系统的功耗

3、伪需求

伪需求是客户强加的需求,它约束系统的实现。典型的为需求是实现系统的编程语言和运行平台。

4、需求描述的要求

需求定义的最终目的是要获得没有二义性、的全面的、详尽的目标需求。因此,需求规格说明书需要满足一定的要求。这些要求包括:

高质量需求叙述的特性

正确性:每个需求必须精确描述要交付的功能。正确性依据于需求的来源,如真实的客户或高级别的系统需求说明书。一个软件需求与其对应的系统需求说明书相抵触是不正确的(当然,系统需求说明书本身可能不正确)。

可行性:在已知的能力、有限的系统及其环境中每个需求必须是可实现的。为了避免需求的不可行性,在需求分析阶段应该有一个开发人员参与,在抽象阶段应该有市场人员参与。这个开发人员应能检查在技术上什么能做什么不能做,哪些需要需要额外的付出或者和其他的权衡。

每个需求应载明什么是客户确实需要的,什么要顺应于外部的需求, 必要性:

接口或标准。每个需求源于你认可、具有权说明需求的原始资料,这是考虑必需的另外情形(译注,此句翻译不顺,请参照原文:Another way to think of “necessary” is that each requirement originated from a source you recognize as having the authority to specify requirements)。跟踪每个需求回溯到出处,如用例,系统需求,规章,或来自其他用户的意见。如果你不能标识出处,可能需求只是个镀金的例子,没有真正的必须。

优先权:为了表明在一个详细的产品版本中应包含哪些要点,需要为每个需求,特征,或用例分配实现的优先权。客户或其代理都应有强烈的责任建立优先权。如果所有的需求都被视为同等重要,那么由于在开发中,预算削减,计划超时或组员的离开导致新的需求时, 项目经理将不能起到作用。优先权的作用是提供给客户的价值,实现的相关费用,实现相关联的有关技术风险。 我是用3种级别的优先权:高优先权表明需求必须体现在下一个产品版本中,中优先权表明需求是必须的,但是如果需要可以推迟到晚一些的产品版本中,低优先权表明有它很好,但我们必须认识到如果没有充足的时间或资源,它可以被

放弃掉。

明确性:需求叙述的读者应只能从其得到唯一的解释说明,同样,一个需求的多个读者也应达成共识。自然语言极易导致含糊。要避免使用一些对于SRS作者很清楚但对于读者不清楚的主观词汇,如:用户友好性,容易,简单,快速,有效,几个,艺术级,改善的,最大,最小等等。每写一个需要都应简洁,简单,直观的采用用户熟知的语言,不要采用计算机术语。检查需求模糊的有效方式包括需求说明书的正规检查,根据需求写测试,建立用户的假想来说明产品某个特定部分预期的特性。

可证实:看你是否能够做出测试计划或其他验证方式,如检查和实证,来决定在产品中每个需求是否正确的实现。如果需求是不可验证的,决定需求是不是正确的实现就成了判断的事。需求之间不一致,不可行,不明确也能导致不可证实。任何需求如果说产品将要支持什么也是不可证实的。

高质量需求说明的特征

完整性:不应该遗漏要求和必需的信息。完整性也是一个需求应具备的。发现缺少的信息很难,因为根本不存在。在SRS中将需求以分层目录方式组织,将帮助评审人员理解功能性描述的结构,使他们很容易指出遗失的东西。 一致性:一致性需求就是不要于其他的软件需求或高级别的系统(商业)需求发生冲突。需求中的不一致必须在开发开始前得到解决。只有经过调研才能确定哪些是正确的。修改需求时一定要谨慎,如果只审定修改的部分,没有审定于修改相关的部分,就可能导致不一致性。

可修改性:当每个需求的要求修改了或维护其历史更改时,你必须能够审定SRS。也就是说每个需求必须相对于其他需求有其单独的标示和分开的说明,便于清晰的查阅。通过良好的组织可以使需求易于修改,如:将相关的需求分组,建立目录表,索引,以及前后参考(照)。

可追踪:你应能将一个软件与其原始材料相对应,如高级系统需求,用例,用户的提议等。也能够将软件需求与设计元素,源代码,用于构造实现和验证需求的测试相对应。可追踪的需求应该具有独立标示,细密和结构化的编写,不应过大,不应是叙述性的文字和公告式的列表。

5、需求质量的评审

这些有关需求质量的特性的描述在理论上都是非常好的,但一个好的需求到底是个什么样子的呢?为了体现得更切合实际,我们做个小练习。下面有几个从实际的工程选出的需求,依据上面的质量标准,评估每个需求,看看有什么问题,然后用更好的方式重写。我将对每个例子都提出自己的分析和改进的建议。也欢迎你提出不同的见解。我所占优的只是我知道每个需求的出处。因为你我都不是真正的客户,我们只能猜测每个需求的意图。

例1、“产品应在不少于每60秒的正常周期内提供状态信息”

这个需求是不完整的:状态信息是什么,如何显示给用户。这个需求有几处含糊。我们在谈论产品的哪部分?状态信息间隔真的假定为不少于60秒? 甚者每10年显示一条新的状态信息也可以?也许它的意图是消息间隔不应超过60秒,那么1毫秒是不是太短?“每”这个词导致了不确定性。问题的后果,就是需

求的不可证实。

弥补缺陷,重写需求的一种方法:

1、状态信息

1.1后台任务管理器因该以误差上下不超过10秒的60秒间隔,在用户界面的指定位置显示状态信息

1.2如果后台进程处理正常,那么应该显示任务已完成的百分数/比

1.3任务完成时,应显示相关的信息

1.4后台任务出错应该显示错误信息

为了分别测试和追踪,我将其分成了多个需求。如果将几个需求串接在一节中,在构造和测试时就很容易漏掉一个。

例2、“产品应瞬间在显示和隐藏不可打印字符间切换”

计算机在瞬间不能做任何事,所以这个需求不切实可行。它的不完整性表现在没有声明触发状态切换的条件。软件要在某些条件下更改自己?或者用户为了模仿更改要做一些动作?而且,在文档中改变显示的范围是多大:选中的文本,整个的文档,或其他的?这也是个模糊的问题。不可打印字符合隐藏字符一样吗?或者是一些属性标志或一些控制字符?问题的后果,就是需求的不可证实。 象这样编写需求也许更好一些:“用户能够在一个由特定触发条件激活处于编辑的文档中在显示和隐藏所有HTML标记间切换”。现在就很清楚,不可打印字符是HTML标记。由于没有定义触发条件,需求对设计没有约束力。只有设计人员选定了触发条件后,你才能编写测试验证触发的正确操作。

例3、“HTML分析器可以产生HTML标记错误报告,帮助HTML入门者快速解决错误”。单词“快速”使其模糊,没有加进错误报告的定义也使其不完整。我不知道,你怎么验证这个需求。找一个自称为HTML的入门者,看看能不能根据错误报告快速解决错误?

试试这个:“HTML分析器可以产生一个错误报告,错误报告包含有在被分析文件中出错的HTML文本和行号以及错误的描述。如果没有错误,就不会产生错误报告”。现在我们知道了,什么会被加到出错报告中,但是出错报告是个什么样子,则留由设计人员决定。我们还指定了一个例外:如果没有发现错误,不产生错误报告。

例4、“如果可能,主管号码应通过联机校验,而不是通过主全体主管号码列表校验”。真感到绝望,什么是“如果可能”:如果技术上可行?如果主全体主管号码列表可以联机获得?要避免象“应该”的这类不确切的词。客户是需要这个功能性还是不需要。我曾看过一些需求说明书,采用诸如:应,将,应该/将要等一些词描述优先级的细微差别。但我更喜欢用“应”清楚的说明需求的意图,指明优先级。

这是修改后的:系统应校验输入的主管号码而不通过联机的主全体主官号码列表。如果在列表中没有发现主管号码,将会显示一条错误信息,也不接受指令。

在理解各个已完成的糟糕需求上,开发人员将会遇到的难题是:开发人员与

客户将会在审核需求,未达成共识前发生激烈的争论。详细检查大的需求文档不是一件轻松的事情。我清楚有人做过,而且他们花在检查上的每一分钟都是值得的。相对于开发阶段和用户的抱怨电话,在这个阶段修补缺陷是便宜的,

1.1.3 与客户协商的需求定义方法:联合应用设计

联合应用设计(Joint Application Design, JAD)是IBM公司在20世纪70年代末开发的一套面向结果的头脑风暴式方法。它由固定的、结构化的过程组成,需求定义工作是在一个所有相关人员参与的封闭工作环境中完成的。用户、客户、开发人员和一个训练有素的会议领导者集中在一起谈论他们的观点、倾听别人的观点、共同协商,最后形成一个共同接受的解决方案,工作的最终成果就是JAD文件,该文件是一个完整的需求规格说明文档,包括数据元素、工作流程和用户界面。

JAD主要包括5各活动。

(1)项目定义。由JAD小组共同讨论确定项目的目标、范围、约束及初步的需求。

(2)调查。由系统分析员根据项目定义进行详细的需求访谈,这个过程用户与客户也要做大量的资料收集及配合。调查内容涉及现有系统的状态、存在问题与现有业务相关的各种政策、规范、操作手册、业务数据等。

(3)预备。由相关的分析人员整理调查结果,形成需求文档并列出需确认及要讨论的问题。由项目经理或相关人员安排会议。

(4)会议。召开JAD会议,JAD小组共同讨论需求及相关问题,对有争议的问题,JAD小组领导要给出结论。

(5)最终文件。根据讨论结果,整理出最终的需求规格说明书。

1.1.4 嵌入式系统需求定义常见的问题

序号 常 见 问 题

1 系统用于什么任务?

2 什么时间交付?

3 系统具有哪些功能,完成哪些任务?

4 系统从用户或其他源接收什么输入?

5 系统向用户或其他源接收输出什么信息?

6 用户如何与系统打交道,即进行什么样的人机交互,如在小键盘输入

和显示屏输出?显示屏显示什么内容以及如何规定显示方法?

7 系统的质量和体积如何?

8 系统连接何种外部设备?

9 系统是否需要运行某些现存组件?

10 系统处理哪些种类的数据?

11 系统是否要与别的系统通信?

12 系统是单机还是网络?

13 系统的响应时间是多少?

14 需要什么样的安全措施?

15 系统在什么样的环境下运行?操作温度、湿度和环境参数说明。 16 外部存储介质是什么?内存需要多大?

17 系统的可拆装性、可靠性和牢固度的期望值是什么?

18 如何给系统供电?

19 系统的负载如何?

20 是否使用传感器?传感器的灵敏度、精度、分辨率的要求?

21 系统如何向用户通报故障?

22 是否需要任何手动或机械代用装置?

23 系统是否需要远程诊断或更重问题的功能?

24 系统最大可承受的成本?

25 其他问题?

1.1.5 结构化需求分析:数据流分析

结构化开发方法(Structured Developing Method)是现有的软件开发方法中最成熟,应用最广泛的方法,主要特点是快速、自然和方便。结构化开发方法由结构化分析方法(SA法)、结构化设计方法(SD 法)及结构化程序设计方法(SP 法)构成的。

结构化分析(Structured Analysis,简称SA 法)方法是面向数据流的需求分析方法,是70 年代末由Yourdon,Constaintine 及DeMarco 等人提出和发展,并得到广泛的应用。它适合于分析大型的数据处理系统,特别是企事业管理系统。

SA 法也是一种建模的活动,主要是根据软件内部的数据传递、变换关系,自顶向下逐层分解,描绘出满足功能要求的软件模型。

结构化分析方法的基本思想是“分解”和“抽象”。

分解:是指对于一个复杂的系统,为了将复杂性降低到可以掌握的程度,可以把大问题分解成若干小问题,然后分别解决。图4 是自顶向下逐层分解的示意图。顶层抽象地描述了整个系统,底层具体地画出了系统的每一个细节,而中间层是从抽象到具体的逐层过渡。

抽象:分解可以分层进行,即先考虑问题最本质的属性,暂把细节略去,以后再逐层添加细节,直至涉及到最详细的内容,这种用最本质的属性表示一个自系统的方法就是“抽象”。

SA 法的步骤

⑴建立当前系统的“具体模型”;

系统的“具体模型”就是现实环境的忠实写照,即将当前系统用DFD 图描述出来。这样的表达与当前系统完全对应,因此用户容易理解。

⑵抽象出当前系统的逻辑模型;

分析系统的“具体模型”,抽象出其本质的因素,排除次要因素,获得用DFD 图描述的当前系统的“逻辑模型”。

⑶建立目标系统的逻辑模型;

分析目标系统与当前系统逻辑上的差别,从而进一步明确目标系统“做什么”,建立目标系统的“逻辑模型”(修改后的DFD 图)。

⑷为了对目标系统作完整的描述,还需要考虑人机界面和其它一些问题。 SA 法的描述工具

⑴ 分层的数据流图

⑵ 数据词典

⑶ 描述加工逻辑的结构化语言、判定表或判定树。

数据流图

数据流图(Data Flow Diagram,简称DFD)是描述系统中数据流程的图形工具,它标识了一个系统的逻辑输入和逻辑输出,以及把逻辑输入转换逻辑输出所需的加工处理。

1.数据流图的图符数据流图有以下

4 种基本图形符号:

箭头表示数据流,圆或椭圆表示加工。双杠或者单杠表示数据存储,矩形框表示数据的源点或终点,即外部实体。

⑴ 数据流 是数据在系统内传播的路径,由一组成固定的数据项组成。除了与数据存储(文件)之间的数据流不用命名外,其余数据流都应该用名词或名词短语命名。数据流可以从加工流向加工,也可以从加工流向文件或从文件流向加工,也可以从源点流向加工或从加工流向终点。

⑵ 加工 也称为数据处理,它对数据流进行某些操作或变换。每个加工也要有名字,通常是动词短语,简明地描述完成什么加工。在分层的数据流图中,加工还应有编号。

⑶ 数据存储 指暂时保存的数据,它可以是数据库文件或任何形式的数据组织。流向数据存储的数据流可理解为写入文件,或查询文件,从数据存储流出的数据可理解为从文件读数据或得到查询结果。

⑷ 数据源点和终点 是软件系统外部环境中的实体(包括人员、组织或其他软件系统),统称为外部实体。一般只出现在数据流图的顶层图中。

1.1.6 需求规格说明书模板(暂略)

1.2 开发方案的制定与系统设计

1.3 代码编写及调试

1.4 程序的测试

1.5 程序的维护

第二章 单片机程序结构的组织与设计

本章概述:本章将介绍单片机应用软件系统的组织架构与设计。首先介绍系统监控程序的基本概念及在单片机应用软件体系架构中作用。然后介绍一些常用的单片机系统程序的架构及设计方法,包括简单的顺序调度结构、优先调度结构、时间片分时调度结构、基于状态的调度结构等。

2.1 概述

初学者在学习单片机过程中,就程序设计而言碰到的第一个坎儿就是:如何根据具体的要求来构建程序的框架?在单片机原理等基础型书籍中极少介绍这方面的知识。

所谓程序结构的组织就是如何应用已有的功能模块来控制单片机系统按照预定的操作方式有效的工作,完成所设计的功能。

2.2 程序的基本结构

一个最基本的单片机系统流程结构如图2.1所示。这是一种简单的程序架构。在此结构中包含以下两部分。

1、初始化程序

单片机上电复位后,从复位入口开始运行程序。此时,应该先对系统进行自检和初始化动作。系统的初始化动作包括对I/O、RAM、堆栈、定时器、中断、显示、ADC等其他功能模块的初始化。初始化的动作一般只需要执行一遍。

2、主程序循环体

初始化程序结束后,系统的工作环境已经建立起来了,2.1 基本程序结构

此时可以进入主程序。

主程序一般是个循环体。在这里执行的是程序要实现的具体功能,如输入检测、输出控制、显示等。

具体功能的实现可以由功能语句直接写在主程序中,也可以写成子程序的形式,由主程序进行调用。实际系统实现中都用子程序来实

现具体的功能。

3、模块化的程序结构(简单的顺序调度结构)

所谓模块化的程序结构,主程序仅仅执行调度功能,负责轮流调用功能模块程序。主程序每循环一圈,所有的

功能模块被调用一次,如图2.2所示。

显然,采用这种结构,各个模块之间的相互独立性较

强。我们可以象搭积木一样,很方便地增加或减少主程序

调用的模块。

2.2 模块化程序结构

2.3 顺序调度程序结构

系统运行后按一个预定的顺序依次执行一系列的功能模块(作业),循环不已。这种结构的程序常见于各类无人值守的单片机系统,其操作按钮很少。

功能模块的触发方式:主程序在什么条件下调用各个功能模块。大体可以分为三种:

第一种 接力方式。上一个功能模块执行完成后,无条件的触发下一个功能模块。

第二种 定时方式。预先安排好每道作业的运行时刻表,由系统时钟来顺序触发对应的作业。

第三种 外部信息触发方式。当外部信息满足预定条件时触发相应的作业。

后两种方式可以称之为事件驱动机制,给每个功能模块安排“使能标志”,

通过使能标志来触发该功能模块代表的

事件。在每次进入功能模块时,先判断

该模块是否满足执行条件(功能块使能标志=1?),如果满足则执行,同时将

使能标志清零;否则直接返回即可。功

能模块的结构如图2.3所示。

采用顺序调度机制的特点:

优点:可以保证所有的功能模块都

得到执行的机会,并且这种机会时均等的。 2.3 功能模块程序结构

缺点:有些重要的模块可能无法及

时得到响应。

图2.4 顺序调度机制

2.4 优先调度程序结构

优先调度机制的特征:主程序按照一定的优先级次序,去查询各个标志。如果高优先级功能模块的使能标志有效,则执行该功能模块(并清楚标志),完成之后不再执行后继模块的查询操作,而是跳转到主程序,重新开始新一轮操作。

缺点:排在末位的模块有可能被堵塞。

图2.5优先调度机制

2.5 中断与前/后台程序结构

前述的在主程序中进行事件轮询的调度机制,在应付一般的任务已经足够,但是遇到紧急突发事件,无法保证及时响应。

可以将实时性要求高的事件放到中断中(前台)响应,把实时性要求较低的任务(按键扫描、显示刷新等)交给主程序(后台)去调度。这样就形成了前/后台的程序结构模型。

2.6前/后台程序结构

2.6 时间片与分时调度机制

在系统任务较多时,为了保证每个任务都能得到系统事件,可以尝试分时调度机制。将整个系统时间分成若干个时间片,并用ID进行标识。每个时间片内执行一个功能模块。

我们可以将整个程序中的所有任务都纳入到分时调度机制中。在这种情况下,分时调度的执行者是主程序。程序的结构如图2.7所示。

2.7 主程序中采用时间片分时调度机制

2.7 键码分析调度机制(一键一义型结构)

如果系统的功能之间既没有固定的顺序,也没有固定的优先关系,以上介绍的程序结构就不适用了。常见的情形是系统的工作状态取决于外界的输入,如按键输入。系统根据键盘输入信息决定工作状态。大多数单片机系统都属于这种类型。

由按键和功能的对应关系,此类调度机制可以分为两大类: 一键一义型和一键多义型。对于一键一义型结构,操作者每按下一个按键,系统就获得一个键盘编码信息,然后由键码散转到对应功能模块的入口,启动对应的作业。键盘信息的获取可以由三种方式:

第一种:查询法。主程序用扫描键盘来获取键盘信息,然后执行响应功能。 第二种:中断法。按下任何一个键都可以引起一个外部中断,键码分析过程位于外部中断服务程序中。

第三种:定时查询法。利用定时中断,每隔一定时间查询一次键盘。 三种结构的流程图分别如图2.8、2.9、2.10所示。

2.8主程序查询法调度机制 2.9键盘中断法

2.10定时中断法调度机制

2.8 基于状态机的程序调度机制

2.8.1基于状态机的程序调度机制基本概念与结构

当系统工作状态较为复杂时,作业的调度不仅与外因有关(按键输入、外部触发信号、遥控命令等),也与内因有关(系统当前所处的状态、时间信号等)为了分析设计的方便引入状态机的概念,以简化系统的分析和设计。

基本思路:用状态寄存器来表示程序的工作状态;在调度程序中,根据系统当前工作状态和触发条件,综合解释,执行相应的动作,决定迁移的次态。

在这种系统中,先将系统的工作状态进行划分,并给每个状态编号。当某个按键被触发时,我们在判断按键编号的同时,还要判断系统当前所处的状态(现态)。通过对“键值”和“现态”的综合解释,然后确定执行哪个功能,或者切换到新的工作状态(次态)。这就是“一键多义”的程序调度机制。

图 2.9 一键多义按键执行程序结构图

基于状态机的程序调度机制包含4个要素: 现态-当前所处的工作状态;

条件-触发动作或状态迁移的条件; 动作-条件满足后执行的动作; 次态-条件满足后要迁移的新状态。

2.8.2 基于状态机的单片机程序的设计方法与步骤 1、系统状态的分析

分析系统所有可能的状态,这一步越仔细越好。开始时可以按照系统的功能分成几个状态,然后再逐步细分。 2、状态转移的分析

将各个状态之间的转移关系和转移条件进行仔细分析,即分析

当前状态有可能转移到哪些状态? 转移的条件是什么?

在众多的转移关系和条件中,有很多关系和条件是由用户提出来的,如操作顺序和方式,定时时间和报警门限。因此,必须将这些用户规定的关系和条件弄清。

4、画出状态转移图

可以参考数字电子技术中状态转移图的做法。 5、作出状态转换表

可以参考数字电子技术中状态转移表的做法。

第三章 模块化的程序设计方法

3.1 概 念

模块化程序设计方法,即面向“模块”的程序设计方法(M-O)是属于第二代程

序设计方法。其基本思想是,在结构上将软件系统划分为若干功能“模块”(Module)或实体,分别采用模块化程序设计语言如:PASCAL编程实现;再由各模块联结、组合成相应结构的软件系统。

称为面向模块(Module-Oriented Programming)的程序设计方法或模块化程序设计方法(Module Programming)。也称为面向“实体”的程序设计方法(Entity-Oriented Programming)。 这种(M-O)方法适用于设计模块化、结构化程序,可提高软件系统的模块化、结构化水平,设计和组装较大规模的软件系统,有助于提高软件的通用性、重用性、扩展性。

3.2 模块设计原则 1、模块相对独立性

(1)模块实现相对独立的特定子功能。模块的功能单一,函数处理的任务明确,函数的定义相互独立,一个函数不从属于另一个函数,但可以相互调用。 (2)模块之间的关系简单。模块之间没有过多的相互作用,只通过数据传递发生联系,并且函数传递的数据个数越少越好。例如,C语言禁止使用goto语句作用到另一个函数,以保证函数的独立性。

(3)模块内数据的局部化。模块内使用的数据具有独立性,一个模块不允许使用其它模块的数据,且一个模块的数据也不能影响其他模块中的数据。例如,C语言的局部变量就可以满足模块内数据局部化的要求。 2、模块大小适中 3、模块分解层次清楚

模块化程序设计要求对问题进行逐层分解、逐步细化,形成模块的层次结构。分解问题时要注意对问题进行抽象,将问题中的相似方面集中和概括起来,暂时忽略它们之间的差异,采取自上而下、逐步求精的方法实现。

3.3 C语言模块化程序结构

C就是模块化程序设计语言,基于C语言的程序结构如下图所示。

C语言中模块的构成。即是一个.c文件和一个.h文件的结合,头文件(.h)中是对于该模块接口的声明;

某模块提供给其它模块调用的外部函数及数据需在.h中文件中冠以extern关键字声明。

模块内的函数和全局变量需在.c文件开头冠以static关键字声明。

一个简单的例子:一个常用的延时模块的结构。该模块由两个文件构成,一个是源程序文件 delay.c 用来定义函数;另一个是头文件 delay.h 用来函数原型声明。

3.4 设计中常用模块分类

1、初始化模块

当系统上电或复位后对CPU本身以及系统外围电路进行一系列的设置,包括:

z CPU内部寄存器初始化

z CPU的I/O端口的初始化

z 软件全局变量的初始化

z 系统外设的初始化等

常用的文件名为:initial.c,initial.h。其中可以包括若干个函数,如initialcpu( )用于对CPU内部寄存器进行初始化;initialcpuIO( )用于对CPU的端口引脚状态进行设置。

2、全局变量模块

用于定义系统需要的全局变量。

常用的文件名为:grobal.c,grobal.h。

3、延时模块

用于定义系统需要的延时函数。可以包含几个不同延时长度的函数,如延时1ms,延时10ms等。

常用的文件名为:delay.c,delay.h。

4、按键输入与处理模块

这是一个较为常用的功能模块,用来定义按键扫描函数和按键处理函数。

5、显示模块

通常用来定义系统的显示函数。根据使用显示器件的不同常见的有:发光二极管、数码管、字符型液晶显示器、图形液晶显示器等。

6、其他功能模块

以上所介绍的是大部分应用系统都会用到的常用功能模块。更重要的模块是实际系统的功能模块。


相关内容

  • [电子科学综合设计]题目
  • <电子科学综合设计>题目 课程设计采用Proteus7.12和Keil C7.5(UV2)软件来完成,通过课程设计,培养学生的实践能力和创新精神,加强学生计算机软件及其与硬件的应用能力.熟悉各类硬件设备的开发流程,以及综合性的软件设计方法.了解信息与信号传输的基本技术,及其在通信领域的应 ...

  • 以应用为目标的单片机原理教学
  • 文章编号:1672-5913(2013)22-0049-06 中图分类号:G642 摘要:探讨以应用为目标的单片机原理课程在教学内容的组织.课堂教学效果的提高.理论教学与实践教学的结合.考核方式的改革等方面存在的问题,提出优化教学内容.强化课堂演示.加强理论与实验融合的策略,以及"作品加分 ...

  • 单片机的复位电路
  • 98 内蒙古石油化工第30卷 单片机的复位电路 郭 景 (内蒙古科技大学理学院物理系,内蒙古包头014030) 摘要 在单片机应用系统的设计中,保证单片机能够准确.可靠的复位,是单片机应用 系统的重要环节.在时钟电路工作后,只要在单片机的复位(RST)脚上出现24个时钟振荡脉冲(也就是2个机器周期) ...

  • 单片机系统复位电路设计
  • T技术 SCIENCE&TECHNOLOGY 单片机系统复位电路设计 贾正松 四川广元(四川信息职业技术学院 62801 7) 摘要:针对单片机应用系统可能出现干扰而发生"死机"或"程序跑飞"等现象,从简到繁结合实例分析单片机系统中几个典 型复位电路. ...

  • 单片机电子时钟毕业设计(论文)
  • 1 引言 单片机系统被定义为:以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能.可靠性.成本.体积.功耗严格要求的专用计算机系统.实际上单片机系统是计算机的一种应用形式,是将先进的计算机技术.半导体技术和电子技术与各个行业的具体应用相结合后的产物,具有软件代码小.高度自动化.响应速 ...

  • 哈尔滨工业大学大一年度项目中期检查报告
  • 编号: 哈尔滨工业大学 大一年度项目中期检查报告 项目名称: 基于STM32单片机的温度报警系统设计 项目负责人:雷江河 学号: 1140110126 联系电话: [1**********] 电子邮箱:院系及专业:电气工程及自动化学院 测控技术与仪器专业 指导教师:刘冰 职称:讲师 联系电话:045 ...

  • 课题研究的背景
  • 引言 1.1 课题研究的背景 由于直流电动机具有良好的线性调速特性,简单的控制性能,在工业场合应用广泛.近代,由于生产技术的发展,对电气传动在起制动.正反转以及调速精度.调速范围.静态特性.和动态响应方面都提出了更高的要求,寻找更高效.更可靠.成本更低的直流电机控制方法成为新世纪研究的热点. 近十几 ...

  • 物联网专业教学大纲
  • 物联网专业(4年制)教学大纲 无线龙物联网专业教学大纲按照物联网三层结构规划了培养目标: 传感层:无线节点硬件和核心协议栈软件设计,RFID无源有源标签设计技术掌握,低功耗无线设计,基础无线网络技术掌握,安全和加密原理和设计: 网络层:多种网络网关设计,HF,UHF -RFID读卡器设计,掌握主流无 ...

  • [单片机原理及应用]课程设计
  • <微机控制技术及应用> 课程设计 题 目∶ 院 系∶ 8051单片机系统扩展 专业班级∶ 姓 名∶ 学 号∶ 指导教师∶ 成 绩∶ 目录 引言 -----------------------------------(2) 一.设计目的和要求------------------------ ...

  • MCS-51单片机的堆栈及其应用
  • 福建农业大学学报28(1):115-120.1999 Journa]ofF邺anAg呲uIturaIUnlversLty MCS一51系列单片机的堆栈及其应用 陈惠端吴锤红 (福建农业大学机电工程系,福州350002) 摘要论述rMcs一51系列单片机堆栈特点.开辟方法和应用技巧,并指出了堆栈的不当 ...