单片机程序设计编程规范.docx
- 文档编号:6757428
- 上传时间:2023-01-10
- 格式:DOCX
- 页数:25
- 大小:36.24KB
单片机程序设计编程规范.docx
《单片机程序设计编程规范.docx》由会员分享,可在线阅读,更多相关《单片机程序设计编程规范.docx(25页珍藏版)》请在冰豆网上搜索。
单片机程序设计编程规范
单片机程序设计编程标准
本标准适用于松翰科技8-bitMCU部门汇编程序编写准那么,同样适用于代理商及重要客户工程师编程标准参考。
本标准的目的为统一编程风格,保证程序编写质量,提高程序的可移植性和维护性。
大局部的标准严格,品质要求高的软件公司对员工编写代码的风格都有硬性规定,例如缩排的使用,TAB的长度,函数变量的命名方式。
这些规定的明显好处是可以统一标准不同程序员所编制的代码,提升程序代码的可读性与可维护性,同时统一格式的编程风格也为codereview提供方便。
设计总那么
二、排版风格
三、程序可读性及可维护性
四、注释
五、变量命名规那么
六、常量命名规那么
七、标号命名规那么
八、文件命名规那么及文件分割
九、标准程序模块
—、设计总那么
1.程序质量的评佶
程序的优劣可以从两个方面进行评估,定量指标和定性指标。
定量指标包括:
1〕程序代码执行效率;
2〕程序占用资源多少。
定性指标包括:
1〕可调试性,即是否方便排除程序语法错误;
2〕可测试性,即是否方便验证程序功能的正确性;
3〕可维护性,即是否方便程序的修改和升级;
4〕可移植性;
5〕可读性。
2、程序架构
为了便于维护和移植,推荐使用层次化的软件设计方法。
可把整个软件分为三层:
应用层、界面层和底层驱动层°各层之间的关系如以下图所TJX。
层次化设计说明:
1〕底层驱动层主要包含直接和硬件相关的驱动程序,如数码管显示、按键、峰鸣器、继电器和电机控制等。
底层的各个模块间要保持各自的独立性,不产生直接的数据交互,底层也不直接访冋应用层,如果有需要,都要通过界面层进行数据交互。
2〕界面层主要提供数据交互,为应用层和庇层驱动之间以及庇层驱动层各模块之间提供数据的交互。
3〕应用层主要完成具体功能的实现,它要通过界面层控制底层驱动层各模块来完成所需功能,而不能越过界面层直接访问/S层驱动层。
所有的用户接□要在应用层来实现。
4〕—个好的架构必须将底层硬件包装起来,为应用程序提供一组丰富的函数操作〔bufferorparameter〕,例如在中断的处理中,应用程序不需要资料中断的堆栈如何保护不需要知道地址操作,只需要读取中断产生的旗标动作。
5)在即时性软件系统里面,对到达高效率的实时性与反响力,所以程序使用大量的事件触发方式来设计任务。
事件有可能来自外部的触发(key,rxdata,sensordetect,…)也可能是系统内部自行产生的(Timer,alarm,flag),与事件触发方式相对应的是定时查询方式(polling),—般来说polling效率较差因为有多余的动作而且系统反响时间与查询polling时间间隔有关,但是在小型的MCU系统里面用Polling方式反而简单许多。
3.设计根本原那么
1)尽量减少各个子程序功能模块间的耦合度(耦合度是指一个程序的执行对启一个程序的影响力),保证各自的独立性。
一般情况下,建议子程序模块功能的划分要尽可能细化,功能尽量单一,减少子程序模块间的数据交互。
2)在满足功能需求的情况下,可适当牺牲代码的执行速度,以保证程序的透明度。
3)主要子程序模块间的交互,要通过特定的界面跟应用层进行沟通,可使用FIFO(Firstin.Firstout)或是Buffer两种方式。
每种子程序模块都可以有自己的FIFOo例如:
就按雒来说,一般有Keybuffer.KeyFIFO或直接逬入APFIFO三种设计方式。
Keybuffer:
—般用于保存数字按褪信息。
例如:
在机的设计中,需要记录按雒内容用于LCD显示、最后数字确认、数字存储等,这时候需要把按雒值的信息(0123456789*#)记录在Keybuffer中。
KeyFIFO:
—些功能按键可以将相应信息列入到KeyFIFO中,等待应用层的取用,这样可根据不同的工作模式进行不同的处理及动作。
这些类似的观念可以应用在许多周边中:
输入类:
Key、RFDatainput,UARTdatainput.Switchinput等。
输出类:
LCDdisplay、LEDdisplay,UARTdataoutput等。
APPFIFO(应用界廁层):
主要是将发生的事件储存在APPFIFO里面等待适当的时间依序处理,不然有可能造成系统在某一程序物件里面循环,从而降低系统的实时性(Real-Time)o
4)每个子程序模块只能有唯一一个程序入□地址在程序的首部,只能有唯——个程序出□地址在程序的尾部。
例如:
以下的写法是不标准的〔两个RET出口,存在调试时不易设立断点,程序可读
性降低等问题〕:
lable:
bObtsOfz
clry
应该改为〔只有一个出□位置,标号为lable90,便于程序检查〕:
lable:
bObtsOfz
jmplable90
•••
clry
lable90:
5〕上电复位时要对所有的RAM空间进行初始化〔建议用户存放器清零,系统存放器进行必要设定〕,不要使用未经初始化的变量。
RAM未经过完整的初始化,容易导致程序执行的不确定性,这一不良现象往往在批量生产中有所表达。
〔这点是工程师经常犯错的地方,须特别注意〕
6〕系统中如果需要等待一些未知的应答信号,如通信或等待输入信号时,必须进行超时或异常处理,以防止程序进入“死等〞状态。
例如在红外接收中,由于信号的突然消失或干扰从而无法得到一帧完整或正确的信息,这时需要复位接收程序的入□条件并退出接收程序,而不是一直等待信号的来临。
不然无法进行下次接收甚至会影响到其它程序的执行。
7〕通过对系统数据结构的划分与组织的改良,以及对程序算法的优化来提高空间效率。
这种方式是解决软件空间效率的根本方法。
8〕保证循环体内的工作量最小化。
应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的执行效率。
9〕在多重循环中,应将最忙的循环放在最内层。
10〕中断处理程序应尽量愆。
有效的作法为:
在中断中进行标记,在主程序中进行处理。
但一些实时性要求较蒿的程序例外。
此外,进入中断时应该保存涉及到的变量和存放器。
11〕看门狗的正确使用。
看门狗主要用于微控制器死机时的时间溢出复位,需要程序适时去除。
正确的处理方式为:
整个系统程序中尽量保证只有一处清看门狗位置,而且应处在主循环的主干位置。
切记不可在定时中断中清狗,因为微控制器有时只是在主循环中死掉。
〔所有AC电源的应用程序都必须强迫参加看门狗选项尤其是条件式的看门狗有利于系统发生异常后的重启动〕
二排版风格
1、程序采用缩进风格编写,缩逬为1个Tab键,1个Tab键定义为8个空格位。
2、程序中的标号要从第一列开始书写。
以开头的预编译命令也要从第一列开始书写,其他预编译命令采用缩进风格编写。
例如:
1〕以开头的预编译命令要从第一列开始书写,其他预编译命令采用缩进风格书写。
•LIST;从第一列开始书写
.CONST
NUMBEREQU55h
.DATA
wkOODS1
.CODE
ORGOh
2〕标号要从第一列开始书写。
main:
;从第一列开始
•••
jmpmain;缩进8个空格位
3〕变量或常量的定义采用缩进风格。
例如:
.DATA
keybufDS1
.CONST
NUMBEREQU8
4〕定义变量或常量时,变量色或常量名与命令符之间使用2个Tab键〔相当于16个空格位〕分幵,命令符与后面的操作数用1个Tab键〔相当于8个空格位〕分幵。
例如:
keybufDS1
NUMBEREQU55h
5〕操作码与操作数之间用1个Tab键〔相当于8个空格位〕分开。
例如:
ORG80h
mova,NUMBER
table:
DWI234h
6.〕程序中两个操作数之间用一个“,〞作为分隔符,“#〞号与立即数之间不需要分隔符。
例如:
Mova,#55h
7〕标号要单独占一行。
8〕相对独立的程序块之间必须加空行。
例如:
ORG10h
INCLUDEint.asm
INCLUDEkey.asm
9〕程序语句后面假设有注释,所有的注释要遵守上下对齐的原那么。
例如:
bOniov
l,#7fh
;usedpOx(hl)pointer
mov
a.#00
;setpointer=007fli
应该书写为:
bOmov
L#7fh
;usedpOx(hl)pointer
mov
a,#00
;setpointer=007fli
三、程序可读性与可维护性
1•程序中的语句、标号、变量使用小写英文字母,常量与预编译命令使用大写英文字母,以便和一般的语句进行区分。
例如:
NUMBEREQU55h
.DATA
accbufDS1
.CODE
mov
a,#NUMBER
2•表示不同进制的立即数,要在立即数后面加上不同的进制符号。
例如:
mov
久#0010001lb
mov
a,#23h
不建议使用:
mov
a,#Ox23
3•—般情况下•变量和常量要分开定义.不要混在一起。
变量在“.DATA〞段中定义,采用命令符“DS〞,常量在〞.CONST〞段中定义,采用命令符“EQU〞。
例如:
.CONST
.DATA
AccbufDS1
4.程序中不使用未定义或意义不明确的常量G
例如:
下面的赋值方法要防止使用:
•••
mova,#3;不要直接使用意义不明确的数字
在常量中做定义
movr,a
•••
建议采用如下赋值方法:
.CONST
NUMBEREQU3;循环次数
•••
.CODE
mov
a,#NUMBER
mov
r,a
5•整个程序的结尾要以“ENDP〞语句结束。
6•当一段代码在程序中有多个地方使用时,建议采用子程序调用或宏命令的方式来替代。
如此,对该代码段的修改就可在一处完成,增强代码的可维护性。
7.程序中关系较为密切的子程序代码尽可能相邻。
&防止程序中的垃圾代码,预留代码应以注释的方式出现。
程序中的垃圾代码不仅占用额外的空间,而且还可能影响到程序的功能与性能,很可能给程序的测试、维护等造成不必要的麻烦。
4.注释
1•程序应该包括两个局部注释,说明局部和语句注释。
一般情况下,源程序有效注释量必须在30%以上。
2•说明局部:
1〕源文件说明局部位于每个源文件的最前面,主要描述:
文件名、作者、生成日期、联络方式、功能描述、版本号、软硬件平台、版权说明、修改记录等的简要说明,以英文书写。
例如:
;文件名
作者
旧期
;邮箱地址
;功能描述
;版本号
;软硬件平台
Filename:
Author:
Date:
Email:
Description:
Version:
Hardware&IDE
Copyright(C),SONIXTECHNOLOGYCo.,Ltd.
History:
;修改记录
2〕子程序说明局部位于每个子程序的最前面,主要描述:
子程序名称、功能.设计原理、所用变量、入□条件、出□信息、调用模块、堆栈层数、影响资源、算法简述、使用说明和修改记录等。
例如:
Subroutine:
;子程序名称
Description:
;子程序功能的描述
Principium:
Calls:
;程序设计原理
;被本子程序调用的子程序清单
Variables:
;本子程序中所用到的临时变量
Input:
;子程序调用所需要根本参数的说明
Output:
Stack:
;子程序调用后运算结果的说明
;占用的堆栈层数
5^C/
3
性。
不再有用的注释要删除。
4•要防止在注释中使用缩写,特别是非常用缩写。
5•程序在必要的地方必须有注释.注释要准确、易懂、简洁。
注释要有意义.
如果有需要,还要详细描述相关含义。
例如:
以下是无意义的注释
mova,#5
把5赋给acc
movwk00,a
;把acc赋给wkOO
应该如下注释:
mova,#5
;设置循环次数为5次
movwk00,a6•注释应与其描述的代码相近,对代码的注释应放在其上方或右方〔对单条语句
的注释〕的相邻位置.不可放在下方,如放于上方那么需与其上面的代码用空行隔开。
例如:
clrwkOO;CheckReadindex=FiFoLimit
cmprsa,r;IsReadindex=Limit
Jmp@f
7•注释格式尽量统一,对多行注释建议使用“庐……*/〞,对单行的注释建议使用“;〞。
8•注释应考虑程序易读及外观排版因素,语言尽量统一。
对不能进行准确英文表达的建议使用中文。
9•对有含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其含义。
五、变量命名规那么
1•变量的名称要采用有意义的英文单词小写缩写。
可以采用以下几种方式进行缩写命名:
1〕去掉所有不在词头的元音字母。
如screen可以简写为scrno
2〕使用每个单词的头几个字母。
如channelactivation可以简写为chanactivo
3〕使用变量名中具有典型意义的单词。
如numberofcycle可以简写为cyclenumbero
4〕去掉无用的单词后缀ing、ed等。
如pagingrequest可以简写为pagreqo
5〕尽量使用标准或惯用的缩写形式,缩写应该保持一致性。
如serialperipheralinterface可以简写为spio
6〕部门已经完成函式的变量名称,如果没有特别原因,开展人员延续使用以增加可读性
2.在定义局部要参加注释来说明变量的含义。
3•变量的定义要在“.DATA〞段中。
4.变量标识符的长度不超过16个字符。
5•序会用到起码三种变量
1〕全局变量名称前面不加任何修饰。
2〕局部变量利用wkOO,wkOl・・・.wkOn来表示,每个独立程序里面用到的Localvar.可有效节省RAM。
3〕中断局部变量中断里面用的Interruptlocalvar.利用IwkOO,IwkOl以作为区隔〔注意中断使用的变量必定要小心的跟主程序区隔开,不然影响系统稳定性相当大〕。
例如:
.DATA
•••
accbufds1;全局变量
Lnumberds
;局部变量
6•位定义。
程序多处会经常对存放器的某一位进行操作,可以在变量定义时对需要用到的位进行定义,建议名称以〞f_〞开头。
7•临时工作存放器的定义。
程序中经常需要用到一些临时存储数据的存放器,我们称之为临时工作存放器,这些临时工作存放器的命名方法为“wk〞加上一个二位数字组成,这个数字可以从“00〞开始随着需要定义的临时工作存放器的数量的增加而增加。
需要特别说明的是,临时工作存放器的使用可以大量节省RAM空间,但是要注意相应的生命周期,必须在子程序退出之前,将空间释放以便其它子程序使用。
&在中断处理程序中用到的存放器,为了和一般的临时工作存放器作以区分,可以在存放器前面加英文字母“i〞来命名。
在使用时需要加以注意,不要和主程序中的变量复用。
例如:
.DATA
•••
wkOO
ds
1
wkOl
ds
1
wk02
ds
1
iwkOO
ds
1
;中断中要用到的临时工作存放器
iwkOl
ds
1
;中断中要用到的临时工作存放器
.CODE
Mov
Movmovmov
•••
a,r
wkOO.aa,wk01r,a
六、常量命名规那么
1•常量的名称要采用有意义的英文单词大写缩写。
2•常量要定义在“.CONST〞段中。
3•在定义局部要参加注释来说明常量含义。
4•量标识符的长度不超过16个字符。
5•系统存放器中常用到的某些位可以再额外进行定义,但要有意义:
P.keylEQUP1.0;P_打头表示为Port定义
Pm_keylEQUPlm.O:
Pm_打头表示为Port方向定义
•••
7.标号命名规那么
1•标号的名称要采用有意义的英文单词小写缩写。
2•子程序标号定义。
在同一个子程序中,所有的标号应该有规律可寻。
建议第一个标号为子程序名,下面所用到的标号用子程序名添加数字表示,从而便于今后程序的添加和修改。
数字尽量使用两位数,在子程序的退出位置,数字一般为"90〞。
例如:
在一段按褪扫描程序中,如下的标号是不可取的。
Label:
LabelOK
LabelFail
LabelQuit
Labelfun:
LabelEnd:
Ret
〔设计师要花许多精神命名label,同肘不容易看出子程序的结构关西,所以建议在子程序里面别在花精神命名,都用号码表示〕〔详细的动作都用注解来说明〕应该改为:
•*木*木木*木木*木木*木木*木木*木
;Sub-routine,Name:
label
•
Label:
IftheconditionfailthengotoLabel90;programbeginhere
Label10:
;注解都写在这里
Label20:
:
最后结尾结束的label都用90当做结尾:
有助于程序的阅读
Label90:
Ret3•为了使程序的结构更加清晰,子程序的命名要尽量能显示出相互间的调用关系。
由main主循环中直接调用的程序,要以“mn_"作为标号的开头,下面仅列出一些常用的子程序名称,其它类似情况可同样处理。
mn_appmnjntgndmn_keymn_lcd
;系统应用程序
;中断与主程序之间的界面子程序
;按键扫描子程序
;LCD显示子程序
mn_led
;LED显示子程序
mn_tone
;声音处理子程序
mn_epp
mn_bio
;EEPROM读写操作
;根本输入/输出控制
mn_adc
:
ADC输入及处理
mn_debug
:
debug处理程序
4•程序的几个常用入□地址命名如下:
帥入
reset
中断入□:
isr
主程序入口:
main
例如:
org
jmp
0
reset
org8
jmpsr;ISR(InternjptServiceRoutine)
org10
;有效程序幵始地址
reset:
•••
;进入主程序前的一些准备工作(预处理)
premain:
•••
;主程序循环圈
main:
•••
Jmpmain
)\、文件名的命名规那么及文件分割
1•在一个工程中要包括两种文件:
源文件和头文件。
源文件是程序体,扩展名为
“.asm〞,头文件包括了变量、常量、宏命令的定义,扩展名为〞.inc〞。
2•头文件的命名
头文件用三个不同的文件来分别定义常量、变量、宏命令,其命名方法如下:
常量定义文件:
变量定义文件:
宏命令定义文件:
其中,xxx表示I页目的名称。
例如:
作一个机的完整程序,头文件可如下定义:
常量定义文件:
变量定义文件:
宏命令定义文件:
3•源文件分为主文件、子文件。
主文件包括了工程的主程序,它描述了芯片信息、CODEOPTION信息及工程包含的其它子文件模块。
子文件是由各个子程序模块组成,功能相近的子程序要放在一个文件中,文件名可以用
1.
nm.
_key
2.
mn.
jnulkey
3.
mn.
Jone
4.
mn.
Jed
5.
mn.
_i2c
6.
mn.
_sio
7.
mn.
_lwire
8.
inn.
_uart
9.
wr_
fifo
10.
rd_
fifo
11.
ram2ram
12.
ron
i2ram
13.
mat
th
附录中。
实例说明
“工程名+模块功能的缩写+扩展名〞表示。
下面列举一些常用的文件名:
主程序文件:
常用的子文件定义:
中断效劳程序模块:
进程处理模块:
系统处理程序:
按键处理模块:
LCD显示模块:
其中,XXX表示工程的名称。
九、标准程序模块
常用功能模块尽量采用附件提供的标准程序,如果无法使用标准的程序模块,那
么所编写的程序一定要符合标准要求。
所提供的标准程序如下,详细的源代码在
;单键扫描子程序
;多雒处理子程序
;声音处理子程序
;LCD显示子程序
;I2C操作子程序
;SIO操作子程序
;单总线操作子程序
:
UART子程序
;写FIFO
;读FIFO
:
RAM到RAM的数据传递
:
ROM到RAM的数据传递
;根本运算程序
1•初始化
1)当程序上电复位时,一个完整的用户存放器初始化或清零动作是非常重要的,否那么容易造成程序执行的不确定性。
例如:
pre_clrRAM:
bOmov
y,#0
bOmov
z,#48
Clr
@yz
deems
z
jmp
@b
clr
@yz
ret
;清RAMbankO
2)系统存放器必须进行初始化,比方说I/O□方向和输出电平等。
需要特别说明的是输出□的初女台化必须按照以下顺序来处理:
(1)设定相应I/O□输出上下电平
(2)将相应I/O□为输出□如此可确保MCU的I/O□从输入模式转为输出模式时不会有脉冲的存在。
而在I/O□控制频繁变化(如通信)时更要引起注意。
例如:
(3)mova,#11111111b
;如果和pl」原来为输入高电平,当直接切换为输出方式时会有高电平脉冲的输出,而这不是所希望的。
bOmov
p2m,a
mov
比#11111100b
bOmov
p2,a
mov
a.#00001100b
bOmov
p2,a
;这样处理和pl」就防止了离电平脉冲的输出
mova,#l1111111b;
bOmovp2m,a
开机时后IOtoggle的作法:
利用暂时没有用到的IO做toggle可有效观察以下几点
1〕系统是否正常开机
2〕是否发生resetorwatchdogreset现象
3〕程序是否重头运行
观察IOtogglepulsewidth可以了解InternalRC频率的准确性或是协助调整外部RC数值
以上方法可以有效协助量产生产问题
开机时后TestMode的作法:
TestMode必须在开机时后按下某些组合按键同时通过de-bounce才可进入testmode
2•按键处理
1〕—般来说key的处理是所有程序的根底教科书里面所教导的key处理观念大多以delay循环与屡次检查来处理弹跳事件,但是此种方法由于导入delay循环大大降低系统实时性,而大多使用者都没有
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 程序设计 编程 规范