三、功能设计
    按上述需求,传感器的功能设计如下:
传感器上电处于待命状态,等待系统命令做以下操作:
1) 可以支持连续测量,并存放最近8次数据,测量周期可以由系统设置。在此状态下,系统根据需要读取数据。
2) 可以支持连续测量,并且将每次的数据返回给系统,由系统进行需要的后处理。
3) 可以接受系统命令,返回待命状态。
4) 可以支持单轮测量,即系统发出命令通知传感器,采集几次数据,传感器可做基本的数据处理,如取平均、剔除最大最小值,完成后返回这组数据后,恢复到待命状态。

    此外,为了便于调试,增加读、写单片机内存的功能。

四、详细设计
4.1 题外话
    看懂别人软件是件相当困难的事,即使那些较正规的、有完善文档的项目,也不是十分轻松,因为记录下来的只是结果,思维的过程无法再现,而读者有时更多关注的是如何“想到的”,特别是初学者!
但描述软件的构思过程也并非易事!
    前期我写过的“圆梦小车StepbyStep”系列文章中,尝试通过一步步“搭建”的方式来引导读者理解思考过程,并在程序中特别注释了每一步所增加的内容,程序中排版顺序都放弃了逻辑关系而“屈从”于“搭建”的顺序,可似乎收效甚微!?猜测是没有交代最基本的思路所致,因为即使是每一步都很具体,读者仍会问:怎么来的?为何?
    本文不是技术论文,其目的是帮助有意学习者实现自己的愿望,所以本篇尝试简述一下思考方式,看是否对学习者有帮助,但声明一点:此乃个人观点,并非“宝典”,不保证正确,仅供参考!

4.2 程序构建思考过程
    我开始涉足单片机编程时,由于只有汇编语言可用,且编译环境较弱,变量名、标号限制较多,所以那时很讲究使用流程图来表达程序的构思,因为从汇编代码上看懂程序实在困难,毕竟那是为机器思维服务的逻辑顺序,与人理解所需的表述相差甚远。
    当我转换到C语言编程时,开始还保持着画流程图的习惯,但逐渐觉得有些多余,因为C语言的自注释性(即语句和变量名的组合表达方式已接近人的理解需要)以及编译环境的提升,配合各类几乎无限制的定义手段,使程序本身就可以方便的为人所理解。如今编辑器也在优化,读者可以尝试一下 UltraEdit,其“折叠”、“展开”功能十分有助于理解程序的思路。所以渐渐的放弃了流程图。但还维持着按实现过程来构建程序的习惯。
    自从我尝试编写PC环境下的VC程序后,逐渐构思习惯有了很大变化,读者如果没有尝试过,可以参照“圆梦小车StepbyStep之二”做一次,然后再用类似的方式构建几个自己想象的题目,一定会有所感受!

    在VC中构建一个程序,其过程大致如下:
1) 设计功能 —— 这是机器所不能代替的,靠你的创造力实现之,需要用文本记录之;
2) 构思界面 —— 这就是VC为你提供的方便了,根据功能和工具可以实现你所要的界面
3) 变量定义 —— 构建界面时VC会自动生成变量,根据功能对这些变量进行类型定义;
4) 编写处理程序 —— 基于界面所产生的操作(按钮等)编写对上述变量进行处理的程序,这是你的智慧展示的空间。

    在PC上编程(默认是Windows下),由于很多事情都由Windows操作系统帮助做了,所以在VC环境下编程确实比较轻松,只需关注和功能相关的事,无创意的琐碎事务都由系统和VC处理了。
    单片机中虽没有这么“美”的事,但是这种构建过程倒是改变了我,我现在基本也是按此思路去构建一个程序,只不过一些VC帮助自动生成的过程由自己完成了。

    首先,是确定所做的东西要完成哪些功能,这是基础。在需求分析和概要设计阶段基本搞定,在详细设计的开始处将其具体化,用技术术语表达之。
    之后根据这些功能定义相应的变量。如需要记录 8 次测量数据,就需要有一个 8元的数组,同时要有存放指针和取数指针(注意:此处所述“指针”,非C语言的指针,是指数组的下标,只是个人表达习惯而已,下同),以便于对数组操作。
根据硬件的性能和需求确定数组的类型,是用整型还是字节型等;因为我定义的测量范围为5米,即使用cm为单位字节型也不够,所以用整型。因为不可能有负数,所以用无符号整型。数值表达范围大了,将单位提高到mm,虽然不一定需要,但不增加工作量,感觉却好多了 : P 何乐而不为?
    在定义变量的同时,定义一些与变量处理相关的常量,一方面为了程序的可读性,同时也是为了日后便于修改。如现在设计是保留最近8次数据,但日后也许需要更多或较少,将数组的单元数声明为符号常量 —— DATA_SAVE_NUM,定义为8,需要时只需修改此处定义即可,不用在程序中“遍地”去找,遗漏一个就形成一个bug!
    在构思服务于功能的变量时顺便考虑如何处理之,还是拿测量数据存放为例。既然需要存放最近N次的数据,可以这样处理:存满8个之后依次向前移,覆盖序号最小的单元,腾出序号最大的存放新数据。这样处理效率太低,常用的方式是环形缓冲区的概念,即将数据存放区看成是个首尾相接的环,存放数据时指针不断“加”,到尾时自动环到首,不用任何数据搬家操作,而取数也是同样,只是从存数指针向回“减”,到首时自动环到尾。
    基于这个思路,自然2个指针变量的需求就产生了。这两个指针据需要能够“加”到尾环头,或“减”到头环尾。如凭直觉,就用比较的方式判断,每次运算都作一次检测,虽能完成,但似乎有些繁琐。考虑一下有无更好的方式?如果还记得二进制的基本运算,就可以理解我为何在程序中设计环形数据存放区的时候均要求单元数是2的幂,即4、8、16……

    按上述方式,可以依次定义出功能用的变量。之后就要结合运行定义一些处理用的变量,这就是VC和操作系统可以帮你完成的那部分。