单片机程序设计编程规范.doc_第1页
单片机程序设计编程规范.doc_第2页
单片机程序设计编程规范.doc_第3页
单片机程序设计编程规范.doc_第4页
单片机程序设计编程规范.doc_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

单片机程序设计编程规范本规范适用于松翰科技 8-bit MCU部门汇编程序编写准则,同样适用于代理商及重要客户工程师编程规范参考。本规范的目的为统一编程风格,保证程序编写质量,提高程序的可移植性和维护性。大部分的规范严格, 品质要求高的软件公司对员工编写代码的风格都有硬性规定, 例如缩排的使用,TAB 的长度,函数变量的命名方式。这些规定的明显好处是可以统一规范不同程序员所编制的代码,提升程序代码的可读性与可维护性,同时统一格式的编程风格也为code review提供方便。目录一、设计总则二、排版风格三、程序可读性及可维护性四、注释五、变量命名规则六、常量命名规则七、标号命名规则八、文件命名规则及文件分割九、标准程序模块十、附录一、设计总则1程序质量的评估程序的优劣可以从两个方面进行评估,定量指标和定性指标。定量指标包括:1) 程序代码执行效率;2) 程序占用资源多少。定性指标包括:1) 可调试性,即是否方便排除程序语法错误;2) 可测试性,即是否方便验证程序功能的正确性;3) 可维护性,即是否方便程序的修改和升级;4) 可移植性;5) 可读性。2、程序架构为了便于维护和移植,推荐使用层次化的软件设计方法。可把整个软件分为三层:应用层、界面层和底层驱动层。各层之间的关系如下图所示。层次化设计说明:1) 底层驱动层主要包含直接和硬件相关的驱动程序,如数码管显示、按键、峰鸣器、继电器和电机控制等。底层的各个模块间要保持各自的独立性,不产生直接的数据交互,底层也不直接访问应用层,如果有需要,都要通过界面层进行数据交互。2) 界面层主要提供数据交互, 为应用层和底层驱动之间以及底层驱动层各模块之间提供数据的交互。3) 应用层主要完成具体功能的实现,它要通过界面层控制底层驱动层各模块来完成所需功能,而不能越过界面层直接访问底层驱动层。所有的用户接口要在应用层来实现。4) 一个好的架构必须将底层硬件包装起来,为应用程序提供一组丰富的函数操作(buffer or parameter),例如在中断的处理中,应用程序不需要资料中断的堆栈如何保护不需要知道地址操作, 只需要读取中断产生的旗标动作。5) 在即时性软件系统里面,对达到高效率的实时性与反应力, 所以程序使用大量的事件触发方式来设计任务。事件有可能来自外部的触发(key , rxdata , sensor detect, )也可能是系统内部自行产生的(Timer, alarm, flag),与事件触发方式相对应的是定时查询方式(polling),一般来说polling 效率较差因为有多余的动作而且系统反应时间与查询polling时间间隔有关, 但是在小型的MCU系统里面用Polling方式反而简单许多。3、设计基本原则1) 尽量减少各个子程序功能模块间的耦合度(耦合度是指一个程序的执行对另一个程序的影响力),保证各自的独立性。一般情况下,建议子程序模块功能的划分要尽可能细化,功能尽量单一,减少子程序模块间的数据交互。2) 在满足功能需求的情况下,可适当牺牲代码的执行速度,以保证程序的透明度。3) 主要子程序模块间的交互,要通过特定的界面跟应用层进行沟通,可使用 FIFO(First in,First out)或是 Buffer 两种方式。每种子程序模块都可以有自己的FIFO。例如:就按键来说,一般有 Key buffer、Key FIFO 或直接进入AP FIFO三种设计方式。Key buffer:一般用于保存数字按键信息。例如:在电话机的设计中,需要记录按键内容用于LCD 显示、最后数字确认、数字存储等,这时候需要把按键值的信息(0123456789*#)记录在 Key buffer 中。Key FIFO:一些功能按键可以将相应信息列入到Key FIFO中,等待应用层的取用,这样可根据不同的工作模式进行不同的处理及动作。这些类似的观念可以应用在许多周边中:输入类:Key、RF Data input、UART data input、Switch input等。输出类:LCD display、LED display、UART data output等。APP FIFO(应用界面层):主要是将发生的事件储存在APP FIFO里面等待适当的时间依序处理,不然有可能造成系统在某一程序物件里面循环,从而降低系统的实时性(Real-Time)。4) 每个子程序模块只能有唯一一个程序入口地址在程序的首部, 只能有唯一一个程序出口地址在程序的尾部。例如:以下的写法是不规范的(两个RET出口,存在调试时不易设立断点,程序可读性降低等问题):lable:b0bts0 fzretclr yret应该改为(只有一个出口位置,标号为 lable90,便于程序检查):lable:b0bts0 fzjmp lable90clr ylable90:ret5) 上电复位时要对所有的RAM空间进行初始化(建议用户寄存器清零,系统寄存器进行必要设定),不要使用未经初始化的变量。RAM未经过完整的初始化,容易导致程序执行的不确定性,这一不良现象往往在批量生产中有所体现。(这点是工程师经常犯错的地方,须特别注意)6) 系统中如果需要等待一些未知的应答信号,如通信或等待输入信号时,必须进行超时或异常处理,以防止程序进入“死等”状态。例如在红外接收中,由于信号的突然消失或干扰从而无法得到一帧完整或正确的信息,这时需要复位接收程序的入口条件并退出接收程序,而不是一直等待信号的来临。不然无法进行下次接收甚至会影响到其它程序的执行。7) 通过对系统数据结构的划分与组织的改进,以及对程序算法的优化来提高空间效率。这种方式是解决软件空间效率的根本办法。8) 保证循环体内的工作量最小化。 应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的执行效率。9) 在多重循环中,应将最忙的循环放在最内层。10) 中断处理程序应尽量短。有效的作法为:在中断中进行标记,在主程序中进行处理。但一些实时性要求较高的程序例外。此外,进入中断时应该保存涉及到的变量和寄存器。11) 看门狗的正确使用。看门狗主要用于微控制器死机时的时间溢出复位,需要程序适时清除。正确的处理方式为:整个系统程序中尽量保证只有一处清看门狗位置,而且应处在主循环的主干位置。切记不可在定时中断中清狗,因为微控制器有时只是在主循环中死掉。(所有AC电源的应用程序 都必须强迫加入看门狗选项尤其是条件式的看门狗 有利于系统发生异常后的重启动)二、排版风格1、程序采用缩进风格编写,缩进为1个Tab 键,1个Tab键定义为8个空格位。2、程序中的标号要从第一列开始书写。以“.”开头的预编译命令也要从第一列开始书写,其他预编译命令采用缩进风格编写。例如:1) 以“.”开头的预编译命令要从第一列开始书写,其他预编译命令采用缩进风格书写。.LIST ;从第一列开始书写INCLUDESTD macro1.h.CONSTNUMBER EQU 55h.DATAwk00 DS 1 .CODEORG 0h2) 标号要从第一列开始书写。main: ;从第一列开始jmp main ;缩进8个空格位3) 变量或常量的定义采用缩进风格。例如:.DATAkeybuf DS 1.CONSTNUMBER EQU 84)定义变量或常量时, 变量名或常量名与命令符之间使用2个Tab键(相当于16个空格位)分开,命令符与后面的操作数用1个Tab键(相当于8个空格位)分开。例如:keybuf DS 1NUMBER EQU 55h5) 操作码与操作数之间用1个Tab键(相当于8个空格位)分开。例如:ORG 80hmov a,NUMBERtable:DW 1234h6.) 程序中两个操作数之间用一个“ ,”作为分隔符,“ ”号与立即数之间不需要分隔符。例如:Mov a,#55h7) 标号要单独占一行。8) 相对独立的程序块之间必须加空行。例如:ORG 10hINCLUDE sys.asmINCLUDE int.asmINCLUDE key.asm9) 程序语句后面若有注释,所有的注释要遵守上下对齐的原则。例如:b0mov l,#7fh ;use dp0x(hl) pointermov a,#00 ;set pointer = 007fh应该书写为:b0mov l,#7fh ;use dp0x(hl) pointermov a,#00 ;set pointer = 007fh三、程序可读性与可维护性1.程序中的语句、标号、变量使用小写英文字母,常量与预编译命令使用大写英文字母,以便和一般的语句进行区分。例如:NUMBER EQU 55h.DATAaccbuf DS 1.CODEmov a,#NUMBER2.表示不同进制的立即数,要在立即数后面加上不同的进制符号。例如:mov a,#00100011bmov a,#23h不建议使用:mov a,#0x233.一般情况下,变量和常量要分开定义,不要混在一起。变量在“.DATA ” 段中定义,采用命令符 “DS” ,常量在”.CONST ” 段中定义,采用命令符 “EQU” 。例如:.CONSTNUMBER EQU 10.DATAAccbuf DS 14.程序中不使用未定义或意义不明确的常量。例如:下面的赋值方法要避免使用:mov a,#3 ;不要直接使用意义不明确的数字在常量中做定义mov r,a建议采用如下赋值方法:.CONSTNUMBER EQU 3 ;循环次数.CODEmov a,#NUMBERmov r,a5.整个程序的结尾要以“ENDP”语句结束。6.当一段代码在程序中有多个地方使用时,建议采用子程序调用或宏命令的方式来替代。如此,对该代码段的修改就可在一处完成,增强代码的可维护性。7.程序中关系较为密切的子程序代码尽可能相邻。8.避免程序中的垃圾代码,预留代码应以注释的方式出现。程序中的垃圾代码不仅占用额外的空间,而且还可能影响到程序的功能与性能,很可能给程序的测试、维护等造成不必要的麻烦。四、注释1.程序应该包括两个部分注释,说明部分和语句注释。一般情况下,源程序有效注释量必须在30以上。2.说明部分:1) 源文件说明部分位于每个源文件的最前面,主要描述:文件名、作者、生成日期、联络方式、功能描述、版本号、软硬件平台、版权说明、修改记录等的简要说明,以英文书写。例如:/*File name: ;文件名Author: ;作者Date: ;日期Email: ;邮箱地址Description: ;功能描述Version: ; 版本号Hardware&IDE ;软硬件平台Copyright (C), SONIX TECHNOLOGY Co., Ltd.History: ;修改记录*/2)子程序说明部分位于每个子程序的最前面,主要描述:子程序名称、功能、设计原理、所用变量、入口条件、出口信息、调用模块、堆栈层数、影响资源、算法简述、使用说明和修改记录等。例如:/*Subroutine: ;子程序名称Description: ;子程序功能的描述Principium: ;程序设计原理Calls: ;被本子程序调用的子程序清单Variables: ;本子程序中所用到的临时变量Input: ;子程序调用所需要基本参数的说明Output: ;子程序调用后运算结果的说明Stack: ;占用的堆栈层数History: ;修改记录*/3.边写代码边注释, 修改代码的同时修改相应注释,以保证注释与代码的一致性。不再有用的注释要删除。4.要避免在注释中使用缩写,特别是非常用缩写。5.程序在必要的地方必须有注释, 注释要准确、易懂、简洁。注释要有意义,如果有需要,还要详细描述相关含义。例如:以下是无意义的注释mov a,#5 ;把5 赋给 accmov wk00,a ;把 acc 赋给 wk00应该如下注释:mov a,#5 ;设置循环次数为5 次mov wk00,a6.注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)的相邻位置,不可放在下方,如放于上方则需与其上面的代码用空行隔开。例如: clr wk00; Check Read index = FiFo Limit cmprs a,r ;Is Read index = Limit Jmp f7.注释格式尽量统一,对多行注释建议使用“/* */” ,对单行的注释建议使用“;”。8.注释应考虑程序易读及外观排版因素,语言尽量统一。对不能进行准确英文表达的建议使用中文。9.对有含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其含义。五、变量命名规则1.变量的名称要采用有意义的英文单词小写缩写。可以采用以下几种方式进行缩写命名:1)去掉所有不在词头的元音字母。如 screen可以简写为scrn。2)使用每个单词的头几个字母。如 channelactivation 可以简写为 chanactiv。3)使用变量名中具有典型意义的单词。如 numberofcycle 可以简写为 cyclenumber。4)去掉无用的单词后缀 ing、ed 等。如 pagingrequest 可以简写为 pagreq。5 )尽量使用标准或惯用的缩写形式,缩写应该保持一致性。如 serial peripheralinterface 可以简写为 spi。6)部门已经完成函式的变量名称, 如果没有特别原因, 发展人员延续使用 以增加可读性2.在定义部分要加入注释来说明变量的含义。3.变量的定义要在“.DATA” 段中。4.变量标识符的长度不超过16 个字符。5.序会用到起码三种变量1)全局变量 名称前面不加任何修饰。2)局部变量利用 wk00 , wk01 .wk0n 来表示, 每个独立程序里面用到的Local var.可有效节省RAM。3)中断局部变量中断里面用的 Interrupt local var.利用 Iwk00, Iwk01 以作为区隔(注意中断使用的变量必定要小心的跟主程序区隔开,不然影响系统稳定性相当大)。例如:.DATAaccbuf ds 1 ;全局变量l_number ds 5 ;局部变量6.位定义。程序多处会经常对寄存器的某一位进行操作,可以在变量定义时对需要用到的位进行定义,建议名称以”f_”开头。7.临时工作寄存器的定义。程序中经常需要用到一些临时存储数据的寄存器,我们称之为临时工作寄存器,这些临时工作寄存器的命名方法为“wk”加上一个二位数字组成,这个数字可以从“00”开始随着需要定义的临时工作寄存器的数量的增加而增加。需要特别说明的是,临时工作寄存器的使用可以大量节省 RAM空间,但是要注意相应的生命周期,必须在子程序退出之前,将空间释放以便其它子程序使用。8.在中断处理程序中用到的寄存器,为了和一般的临时工作寄存器作以区分,可以在寄存器前面加英文字母“i”来命名。在使用时需要加以注意,不要和主程序中的变量复用。例如:.DATAwk00 ds 1wk01 ds 1wk02 ds 1iwk00 ds 1 ;中断中要用到的临时工作寄存器iwk01 ds 1 ;中断中要用到的临时工作寄存器.CODEMov a,rMov wk00,amov a,wk01mov r,a六、常量命名规则1.常量的名称要采用有意义的英文单词大写缩写。2.常量要定义在“.CONST”段中。3.在定义部分要加入注释来说明常量含义。4.量标识符的长度不超过16个字符。5.系统寄存器中常用到的某些位可以再额外进行定义,但要有意义:P_key1 EQU P1.0 ;P_ 打头表示为 Port 定义Pm_key1 EQU P1m.0 ;Pm_ 打头表示为 Port 方向定义七、标号命名规则1.标号的名称要采用有意义的英文单词小写缩写。2.子程序标号定义。在同一个子程序中,所有的标号应该有规律可寻。建议第一个标号为子程序名,下面所用到的标号用子程序名添加数字表示,从而便于今后程序的添加和修改。数字尽量使用两位数,在子程序的退出位置,数字一般为”90”。例如:在一段按键扫描程序中,如下的标号是不可取的。Label:LabelOKLabelFailLabelQuitLabelfun:LabelEnd:Ret(设计师要花许多精神命名label, 同时不容易看出子程序的结构关西,所以建议在子程序里面别在花精神命名,都用号码表示)(详细的动作都用注解来说明)应该改为:;*;Sub-routine , Name : label;*Label:If the condition fail then go to Label90;program begin hereLabel10:;注解都写在 这里Label20:;最后结尾结束的label都用90当做结尾:有助于程序的阅读Label90:Ret3.为了使程序的结构更加清晰,子程序的命名要尽量能显示出相互间的调用关系。由 main 主循环中直接调用的程序,要以“mn_”作为标号的开头,下面仅列出一些常用的子程序名称,其它类似情况可同样处理。mn_app ;系统应用程序mn_intgnd ;中断与主程序之间的界面子程序mn_key ;按键扫描子程序mn_lcd ;LCD 显示子程序mn_led ;LED 显示子程序mn_tone ;声音处理子程序mn_epp ;EEPROM 读写操作mn_bio ;基本输入/输出控制mn_adc ;ADC 输入及处理mn_debug ;debug 处理程序4.程序的几个常用入口地址命名如下:复位入口: reset中断入口: isr主程序入口: main例如:org 0jmp resetorg 8jmp sr ;ISR(Interrupt Service Routine)org 10;有效程序开始地址reset:;进入主程序前的一些准备工作(预处理)premain:;主程序循环圈main:Jmp main八、文件名的命名规则及文件分割1.在一个项目中要包括两种文件:源文件和头文件。源文件是程序体,扩展名为 “ .asm ”,头文件包括了变量、常量、宏命令的定义,扩展名为 ”.inc”。2.头文件的命名头文件用三个不同的文件来分别定义常量、变量、宏命令,其命名方法如下:常量定义文件: xxx_equ.inc变量定义文件: xxx_ram.inc宏命令定义文件: xxx_macro.inc其中,xxx 表示项目的名称。例如:作一个电话机的完整程序,头文件可如下定义:常量定义文件: phone_equ.inc变量定义文件: phone_ram.inc宏命令定义文件: phone_macro.inc3.源文件分为主文件、子文件。主文件包括了项目的主程序,它描述了芯片信息、CODEOPTION 信息及项目包含的其它子文件模块。子文件是由各个子程序模块组成,功能相近的子程序要放在一个文件中, 文件名可以用“项目名模块功能的缩写扩展名”表示。下面列举一些常用的文件名:主程序文件: xxx_main.asm常用的子文件定义:中断服务程序模块: xxx_int.asm进程处理模块: xxx_pro.asm系统处理程序: xxx_sys.asm按键处理模块: xxx_key.asmLCD显示模块: xxx_lcd.asm其中,xxx 表示项目的名称。九、标准程序模块常用功能模块尽量采用附件提供的标准程序,如果无法使用标准的程序模块, 那么所编写的程序一定要符合规范要求。所提供的标准程序如下,详细的源代码在附录中。1. mn_key ;单键扫描子程序2. mn_mulkey ;多键处理子程序3. mn_tone ;声音处理子程序4. mn_lcd ;LCD 显示子程序5. mn_i2c ;I2C 操作子程序6. mn_sio ;SIO 操作子程序7. mn_1wire ;单总线操作子程序8. mn_uart ;UART 子程序9. wr_fifo ;写 FIFO10. rd_fifo ;读 FIFO11. ram2ram ;RAM 到 RAM 的数据传递12. rom2ram ;ROM 到 RAM 的数据传递13. math ;基本运算程序实例说明1.初始化1)当程序上电复位时, 一个完整的用户寄存器初始化或清零动作是非常重要的, 否则容易造成程序执行的不确定性。例如:pre_clrRAM: b0mov y,#0 ;清 RAM bank0 b0mov z,#48: Clr yz decms z jmp b clr yz ret2) 系统寄存器必须进行初始化,比如说 I/O 口方向和输出电平等。需要特别说明的是输出口的初始化必须按照下列顺序来处理:(1) 设定相应 I/O 口输出高低电平(2) 将相应 I/O 口为输出口如此可确保 MCU 的 I/O 口从输入模式转为输出模式时不会有脉冲的存在。 而在 I/O 口控制频繁变化(如通信)时更要引起注意。例如:(3) mov a,# 11111111b;如果 p1.0 和 p1.1 原来为输入高电平, 当直接切换为输出方式时会有高电平脉冲的输出,而这不是所希望的。 b0mov p2m,a mov a,# 11111100b b0mov p2,a (4) mov a,#00001100b b0mov p2,a;这样处理 p1.0 和 p1.1 就避免了高电平脉冲的输出 mov a,#11111111b ; b0mov p2m,a开机时后IO toggle的作法:利用暂时没有用到的IO 做 toggle 可有效观察以下几点1) 系统是否正常开机2) 是否发生 reset or watchdog reset 现象3) 程序是否重头运行观察IO toggle pulse width 可以了解 Internal RC频率的准确性或是协助调整外部RC数值以上方法可以有效协助量产生产问题开机时后 Test Mode 的作法:Test Mode 必须在开机时后按下某些组合按键同时通过de-bounce 才可进入 test mode2.按键处理1)一般来说key的处理是所有程序的基础教科书里面所教导的key处理观念大多以delay 循环与多次检查来处理弹跳事件,但是此种方法由于导入delay 循环 大大降低系统实时性,而大多使用者 都没有警觉此问题 依然延续此观念设计 key scan and de-bounce 技巧,此份文件详细叙述key处理观念。2)家电产品中经常用到抗干扰的测试EFT ,会从电源端打入噪声测试系统抗噪声能力, 如果 key 处理不好会有key误动作产生,一般使用者会在key scan 地方加入电容以减低此问题的产生,但是此方法还是无法完全避免此问题 同时还增加硬件成本,这里提出的de-bounce 观念可以完全解决此问题。3)按键处理很多程序员都会将系统的程序设计与key程序结合没有分开结构,这造成很多程序就以key程序 变成程序主体来运行,这里提出将 key 动作得出的 keycode 到 fifo(first in first out)中,使得AP系统得以在有空闲的时候才处理 key code 动作 ,程序架构自然形成。4)一般来说 key 处理都只侦测key down ,但是在某些系统确有key down and keyup 的要求,这方面可以透过 key in buffer 的储存new/old buffer XOR 比对得到key event,更深一层的技巧侦测多按键处理更是需要利用 new/old buffer XOR 来处理合理的按键处理一般包括按键扫描、按键弹跳处理、按键输出转换等环节。例如:mn_key:call keyin ;读取按键输入将资料储存在 keyinbuf 里面Call keychk ;按键弹跳处理Call keycvt ;弹跳处理后,将按键扫描码转换储存到 FIFO里面!retkeyin按键扫描,其主要负责将外部按键信息读入到内部 buffer中。常用的按键一般包括:直接按键、M*N 矩阵式扫描按键、三角形按键、扩充按键、按键与其它周边共享I/O 脚位等,部分场合还要考虑睡眠和按键的唤醒功能。下面进行分别说明:1)直接按键最简单的按键方式, 通常作法利用 MCU 里面的 pull-up 电阻上拉,外面按键落地,平时没有按键的时候, MCU input 端口读到 Hi , 按键按下时候读到 Low, 如下图所示:2) M*N 矩阵式扫描按键最典型的按键扫描方式, 有分 Single key , multi-key 扫描。单按键扫描 : 一个时间只允许一个按键动作 同时也只读取一个按键。多按键扫描: 一个时间 允许一个以上的 key 按下, 但是只读取最新按下的按键。扫描注意事项 : 一般来说扫描的作法 有 Output port and input port 配合Output port 1110 1101 1011 0111依序送出0信号 让 input port 读取, 但此时可能发生两件冲突事件需要注意如果用 output 0 and output 1 的组合来送出 scan pattern ,当客户同时按下同一排两组按键的时候,会有短路现象, 传统作法是加入 二极管 diode 来保护, 现在单片机的作法则是利用 output input pull-up R 的方式来达成。 见图面说明但是当使用 Input pull-up R 时候 又有另外一件事情要注意就是当1110 1101 时候 , bit0 =output 0 input pull-up 1 ,必须是 bit 0 = output 0 output 1 input pull-up 中间必须经过output 1的动作,这动作要协助 output 0的信号直接快速拉至Hi准位,然后再切换入 inputmode,如果 直接output 0 input mode,此时会有一个较长的上升时间,导致 key scan错误3) 三角形按键 效的增加扫描按键数目,见图面说明4) 扩充按键 可以加上 diode 增加 key scan 数目 见图面说明5) 按键与其它周边共享 I/O 脚位6) ADC 与 RF 接收机杂音避免的方式keychk按键弹跳处理,其主要负责滤除按键输入口灌入的杂讯或按键弹跳杂波。1)一般建议 弹跳时间 处理约在70mS 100mS , EFT 特性如果要好 可以更加长到使用者可接受到最常时间 200mS。2)弹跳时间的处理并非用 delay loop 延迟, 这会降低系统的实时性与反应力 必须检查的动作放在主程序循环里面 配合 keychat time 的递减来完成 。3)如果 主循环绕圈时间 1mS 那按键稳定检查连续次数可高达100次左右 这对于Key 处理来说是非常稳定的。4)弹跳的检查 是连续检查 key 变化后 维持相同状态100mS , 比如说 key 按下后Hi 变成 Low 这时候程序侦测到输入有异动便开启检查时间机制 ,当程序连续检查100mS都发现 Low 没有改变的时候便发出 key event , 此时才有按键发生。5)关于 de-bounce 的程序验证可透过修改弹跳时间测试, 比如说故意将弹跳时间改1sec. 观察在一秒内的按键动作是否都不成立, 只有按键持续达一秒以上 才有动作产生, 确认后再将弹跳时间改回。keycvt按键输出转换,其主要负责将确认的按键信息进行转换和存储。1) KeyCVT 主要工作将经过de-bounce 的 keybuffer 跟之前所得到的 key 相比对,看看新的 key event为何,转换出来后 存储到 keybuffer or keyfifo 甚至直接进入 apfifo2) 将 key code 储存到 fifo 中是一个非常重要的观念,这里展示出 Key 处理是一个独立的物件程序,他的运行跟其他程序都没有相关,唯一对外的界面interface 就是 fifo。而key 的处理方式端看当时系统的 status 还有AP设计的流程才做出相对应的工作 Task。3.计时系统计时系统一般包括定时器初始化和定时设置及处理两部分。1)定时器初始化部分又包括:(1) 定时器控制寄存器的设定(2) 相关用户寄存器的设定(3) 定时时间的初始化2)定时设置及处理:由于系统里面会经常在不同的时间点执行不同的动作, 所以定时的设置及处理变的尤为重要。例如需要以下时间的定时:10ms 定时: 每 10ms 产生定时到达标志位100ms 定时: 每 100ms 产生定时到达标志位1000ms 定时: 每 1000ms 产生定时到达标志位一般来说,10ms 的工作可放在中断处理程序或主程序循环圈中执行,至于采取哪种方式主要是看时间准确性的要求。100ms 以上的工作如果没有特别的要求建议放在主程序循环中执行。 此外在系统时间设计中, 时间不准确的问题经常发生,一般来源于时基的计算与处理。可以在定时中断处理程序中输出一个方波来检查中断发生的时间。定时设置及处理有两种方法可作参考:(1)计算法:利用 MCU 本身的定时中断作出10ms 的时基,再利用计算的方法作出 100ms、1000ms 的定时。(2)累加法:此方法适用于对时间没有特别要求的场合。下面以四位位元依次累加来说明做法:假设变量 timeslot 以每 5ms 的时间来累加:timeslot= 0 0 0 btimeslot= 0 0 1 b ;bit0=1, 5ms 动作timeslot= 0 1 0 b ;bit1=1, 产生 10ms flagtimeslot= 0 1 1 b ;bit0=1, 执行 5ms 动作, 此时不再检查 bit1timeslot= 1 0 0 b ;bit2=1, 产生 20ms flagtimeslot= 1 0 1 b ;bit0=1, 执行 5ms 动作timeslot= 1 1 0 b ;bit1=1, 执行 10ms 动作timeslot= 1 1 1 b ;bit0=1, 执行 20ms 动作timeslot= 0 0 0 b ;没有动作由上面例子的规律来看,一个时间只会有一个时间任务产生,从而不会有太多的时间单位。4.中断和主程序的处理1) Push and PoP 动作要确实完整 i. 请参照不同母体的建议作法2) 透过 mnintgnd 副程序来操作 i. Interrupt 中产生的动作 可以在中断中直接处理 ( 又急又准的需求)约 mS 等级的动作 如 tone output , RF TX, 有些计时参数的递减等 ii. 不需要在中断处理 ,设立旗标 flag 等待在主程序中检查处理(mnintgnd)约100mS 以上的动作: 如0.5S 计时动作, 某些 timeout 命令需要 AP 层处理 iii. 需要了解 interrupt 暂用系统多少时间, 可以在进入中断时候做一个 output H离开中段时候作个 output L 来观察,当然这方面可以利用假指令(If Debug = 1 ) 来设置, 当系统完成后 将此 output H/L 动作关闭, 进入中断所占用的时间越短越好, 原则是只要能够在主程序处理的动作 都在中断里面设定 flag 等到主程序(mnintgnd)处理, 所以中断/主程序的比例越低越好(这里也可以透过主程序循环的 toggle 来观察主循环的绕圈时间)。5.EEPROM 的读写操作1) EEPROM 的使用有以下几个问题要注意 i.EEPROM write time 需要一些时间 , 所有有两种作法 , a) write , delay , write 不建议使用 除非写入资料很少 , 暂用系统时间少2) write, check busy, write 超过10 byte data 以上 ii.透过 buffer read/write iii.24 series EEP 要特别注意 ACK 讯号(绝大部份的设计者都失败在 ACK 信号的处理,造成系统稳定性不佳),同时上拉电阻的设置对于24series 也是很重要的 iv.品牌较差的EEPROM普遍存在 datalost 的问题当有高电压脉冲的时候(尤其开机瞬间)很容易将内部资料清除,所以这方面要注意,当然开机那瞬间 MCU对于EEP的output设定也是很重要的很容易在开机瞬间误写错误信息给EEP。6.Tone 的处理1)可能 MCU 产生的 tone 有下列几种 i.配合按键动作的 Key tone 约100mS single tone。 ii.电话响铃音 来电转接音 保留音。 iii.标准音乐 Do-Re-Mi 等。 iv.警示音 error tone。7.Display 的处理1)LCD Display 程序的唯一性尤其LCM模块使用更是重要 i.平时 LCD 都是透过 LCD Buffer(RAM)来作为interface,当AP层面有更动LCD 资料并不直接对 LCM 硬件操作,而是针对RAM Buffer 更动资料 同时设立LCDREQ flag。 ii.MNLCD 里面发现 LCDREQ=1 时候才进入 MNLCD 程序运行显示更新, 此法可有效改善效率与显示的稳定性。 iii.相同如果非 LCM 的操作 有些人认为可以直接更改 LCD RAM 数值直接更新显示, 这也存在相当大的风险, 最好的方式 还式透过另外一组 Buffer 来做缓冲。 iv.松翰的 ICE 发展系统有提供软件LCD模拟器给客户使用 当客户的 LCD还没有实体,可以透过模拟器直接在 PC 画面上显示,配合程序开发非常方便。8. Telecomm 的处理1)Sync (with clock) and Async.2)Sync. 类似 SPI 信号 data in, data out, and clock3)Async. 本身没有 Clock 时钟信号 一般来说有以下几个组成 i.Bit sync 位元同步 ii.Frame sync 特定的 frame code 来锁定 frame data 开始 iii.Data length 资料长度 来收集资料 iv.Checksum 最后靠 check sum 来验证资料的正确性4) 一般来说同步或异步通信程序 都是 TX 容易 / RX 译码 困难 i.拍码 TX 只需要考虑大笔资料拍码的 buffer and pointer 影响程序实时性不大。 ii.接收 RX 部分就有点困难 需要有较多的技巧考量 尤其异步通信更是麻烦。5)RF通信里面 还要考虑拍码调变的方式 某些硬件电路只能利用曼彻斯特编码法来拍码以去除 DC分量9.Main Loop 的处理1)进入主程序循环前要有个”前处理”(Pre_Main) 来将基本参数设置好 才进入主循环2)看门狗/条件式看门狗 能够放在主循环内, 可以确保主循环有效的运行, 当主循环运行失败,“看门狗”自然发生 Reset 动作3)主循环的绕圈时间(实时性 系统反应力) i.牵涉到系统的实时性(real-time) 所以绕圈时间越短越好 建议在5mS 以内,利用 IO toggle 来观察主循环绕圈时间, 如果程序里面有多余的 IO 就可以留下此IO供日后生产测试观察使用,如果没有多余 在程序稳定后可以将此观察的IO移除。 ii.主循环绕圈时间也会受到中断的影响,由于中断的执行等级高于主循环所以当中断运行时间越长自然主循环的运行时间也越长,所以中断里面占用时间必须稳定的控制,不然影响系统 实时性反应性很大。 iii.主循环里面每一个物件都要设计良好才能确保一个整体的绕圈时间,每一个子程序物件进入前,都必须透过旗标判断是否需要执行,如程序进入后立即检查是否 lcdreq=1 ,如果在此绕圈动作中没有任何lcd 资料更新 ,那也就不用浪费时间进入lcd sub-routine。另外如 EEP 储存动作由于会有 write data busy 问题所以也必定要将资料分批写入,不然程序会停留在 writ

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论