单片机软件编程规范.docx
- 文档编号:5120446
- 上传时间:2022-12-13
- 格式:DOCX
- 页数:19
- 大小:44.85KB
单片机软件编程规范.docx
《单片机软件编程规范.docx》由会员分享,可在线阅读,更多相关《单片机软件编程规范.docx(19页珍藏版)》请在冰豆网上搜索。
单片机软件编程规范
1编辑器3
2程序文件的结构3
2.1说明3
2.2编译宏定义4
2.3包含文件4
2.4用户数据类型定义4
2.5管脚定义5
2.6常量5
2.7变量5
2.8正文6
2.8.1正文顺序[推荐]6
2.8.2正文内容6
2.9长的常量数组6
3命名7
3.1常量、编译宏命名7
3.2变量命名7
3.3函数命名8
4程序的版式9
4.1缩进:
统一使用编辑器的TAB键进行缩进,同时设定其缩进量为系统默认9
4.2空行:
相对独立的程序块之间、变量说明之后必须加空行10
4.3代码行11
4.3.1一行代码只做一件事情11
4.3.2if、for、while、do等语句自占一行11
4.3.3程序块的分界符独占一行12
4.3.4多运算符的代码行,不使用默认优先级13
4.3.5不要使用难懂的技巧性很高的语句13
4.4空格14
4.4.1必要时留空格,使代码更清晰[推荐]14
4.4.2二元操作符前后留空格14
4.4.3一元操作符前后不留空格14
4.5长行拆分15
4.5.1较长的语句(>80字符)要分成多行书写15
4.5.2循环、判断等语句要在低优先级操作符处划分新行16
4.5.3函数或过程中的参数较长,则要进行适当的划分16
5全局变量定义时初始化16
6注释17
6.1必须加注释的位置[推荐]17
6.2注释应适量且准确[推荐]17
6.3函数接口的注释格式17
6.4变量的注释格式[推荐]18
6.5注释与所描述内容进行同样的缩排19
6.6将注释与其上面的代码用空行隔开20
6.7程序块结束行加注释[推荐]20
7EEPROM数据保护21
8程序失效复位处理[推荐]21
9检查21
9.1数组下标检查21
9.2指针检查22
9.3易混淆操作符检查22
9.4右值变量检查22
9.5差1错误检查22
9.6变量溢出检查23
9.7类型转换检查23
1编辑器
程序统一使用VC的编辑器。
2程序文件的结构
如果没有涉及使用平台化的用户文件,通常只能有一个用户主程序文件。
用户程序文件的内容按说明、编译宏定义、包含文件、用户数据类型定义、管脚定义、常量、变量、正文、长的常量数组的顺序编写。
2.1说明
说明:
说明位于用户程序文件的开头,主要内容有:
(1)版权信息。
(2)文件名称。
(3)程序说明:
说明程序用途、功能及使用方法等。
(4)版本记录。
(5)开发环境。
示例:
//版权信息
//Copyright(c)2001,XXXXXX有限公司产品开发部
//Allrightsreserved.
//文件名称:
filename.c
//程序说明:
XXXXX主程序,,
//版本记录:
//V101:
//1、增加警铃输出延时;
//2、修正****Bug。
//作者:
***//时间:
//V100:
正式发布。
//作者:
***//时间:
//编译工具:
KeilC6.0
2.2编译宏定义说明:
同一产品的不同硬件程序和系列产品的程序,应采用编译宏定义,来减少维护的工作量;
2.3包含文件
说明:
包含引用的标准库头文件以及用户头文件。
用#include
准库的头文件(编译器将从标准库目录开始搜索)。
用#“elude“filename.h”格式来引用非标准
库的头文件(编译器将从用户的工作目录开始搜索)。
示例:
#include
#include“user_header.h”
2.4用户数据类型定义
说明:
定义结构、联合、枚举以及其它非标准的数据类型;
示例:
typedefunionMacData//联合
struct//结构
{
unsignedcharMac;//类型
unsignedcharLen;//长度
unsignedcharAddr;//地址
unsignedcharData[13];//数据
}Msg;
};
#defineuintunsignedint;//自定义数据类型
2.5管脚定义
说明:
定义本程序使用的管脚。
2.6常量
说明:
有特定意义的常数必须进行宏定义;
同一特定意义的常数如在多个地方应用,必须进行宏定义;调试维护需要调整的常数必须进行宏定义;无特定意义的循环上、下限,不需进行宏定义。
2.7变量
说明:
定义程序所使用的变量。
有关联的、相同地址空间、初始化、不需初始化的变量要放在一起;
2.8正文
2.8.1正文顺序[推荐]
说明:
应按主程序和中断程序的共用子程序、各中断相关子程序和中断程序、主程序相关子程序和主程序;
关系紧密的子程序应放在一起,并按照从低到高的层次放。
尽量取消函数的声明,可通过注释说明;
除主程序和中断程序外,在不影响可读性的情况下不应设置只一个地方调用的函
数。
2.8.2正文内容
说明:
包含初始化程序、主循环体程序和中断程序。
2.8.2.1初始化程序[推荐]
说明:
应按管脚初始化、RAM初始化、内部设置初始化、外设初始化、打开定时器、打开
中断的顺序进行初始化。
2.8.2.2主循环程序和中断程序[推荐]
说明:
定时应采用计时器处理,不能存在长时间的停滞等待;
不允许多个事件使用一个软件计时器。
计时器宜采用倒计时;
中断事件的响应如果在主循环能够完成响应,应放在主循环。
2.9长的常量数组
说明:
在此定义长的常量数组,如字库、图案等。
3命名
命名的风格必须保持一致。
3.1常量、编译宏命名
说明:
常量、编译宏全部大写,单词间使用下划线分隔。
示例:
#defineMAIN_DELAY_NUM1
3.2变量命名
说明:
通常,在变量中加入前缀以增进人们对程序的理解。
其前缀的通用格式为:
数据类型缩写+模块名+。
同时,为了区分全局和局部变量,也兼顾命名的方便,特采用如下变量命名规则:
全局变量大小写结合,数据类型缩写后,单词首字母大写;局部变量全部小写,数据类型缩写后,使用下划线分隔各单词;局部变量在不影响可读性的前提下,可以不写数据类型;unsignedchar类型的缩写不写;
汇编中,与MPU数据总线(如8位、16位)一致数据类型的缩写不写。
数据类型缩写:
booleanb
charc
longl
floatf
doubled
inti
unsignedintui
指针p
结构s
输入管脚bi
输出管脚bo
示例:
//管脚定义
sbitbiFire=P1A1;
sbitboFireRelay=P"2;
//全局变量定义
bitbFault;
unsignedcharFireAckNum;
unsignedcharDeviceStatus[242];
unsignedchar*pDevice;
charcSampleValue;
longlTime;
long*plEntry;
floatfRadius;
doubledArea;
intiFireRelayDelay;
unsignedintuiFaultRelayDelay;
unsignedintuiSounderDelay[4];
voidGetSampleValue(void)
{unsignedchartemp;
bitb_fault;longl_fire_delay;
}
3.3函数命名
说明:
函数命名应当直观且可以拼读,可望文知意,不必进行“解码”。
标识符采用英文单词或其组合,便于记忆和阅读,并且每个单词的首字母大写,长单词可以缩写,但缩写要使用大家基本认可的,并且必要是进行注释说明。
下单词的缩写能够被大家基本认可:
temp可缩写为tmp;
flag可缩写为flg;statistic可缩写为stat;increment可缩写为inc;message可缩写为msg;
4程序的版式
4.1缩进:
统一使用编辑器的TAB键进行缩进,同时设定其缩进量为系统默认
说明:
程序要采用统一缩进风格编写。
在下列情况下,必须采用缩进:
函数或过程、类的定义、结构的定义、枚举的定义、判断和循环语句中的程序都要采用如上的缩进方式。
但如果同一程序块的缩进级数太多(一般不超过5级),可考虑使用函数减少缩进级数。
示例:
//风格良好的格式
voidFunction(floatx,floaty,floatz)
{
if(…)
{
while(…)
{
}//endofwhile
}//endofif
}
//风格很差的格式
voidFunction(floatx,floaty,floatz)
{
if(…)
{
while(…)
{
}//endofwhile
}//endofif
}
4.2空行:
相对独立的程序块之间、变量说明之后必须加空行
说明:
空行起着分隔程序段落的作用。
空行得体(不过多也不过少)将使程序的布局更加
清晰。
空行不会浪费内存,虽然打印含有空行的程序是会多消耗一些纸张,但是值得。
所以不要舍不得用空行。
示例:
如下例子不符合规范。
if(!
IsValidNI(ni))
{
...//programcode
}
repssnInd=ssnData[index].repssnIndex;
repssnNI=ssnData[index].NI;
应如下书写
if(!
IsValidNI(ni))
{
...//programcode
}
repssnInd=ssnData[index].repssnIndex;repssnNI=ssnData[index].NI;
4.3代码行
4.3.1一行代码只做一件事情
说明:
如只定义一个变量,或只写一条语句。
这样的代码容易阅读,并且方便于写注释。
示例:
(a)为风格良好的代码行
intwidth;//宽度
intheight;//高度
intdepth;//深度
x=a+b;
y=c+d;
z=e+f;
(b)为风格不良的代码行。
intwidth,height,depth;//宽度高度深度
X=a+b;y=c+d;z=e+f;
4.3.2if、for、while、do等语句自占一行
说明:
执行语句不得紧跟其后。
不论执行语句有多少都要加{}。
这样可以防止书写失误
示例:
(a)为风格良好的代码行
if(width { DoSomeThing(); } for(initialization;condition;update) { DoSomeThing(); (b)为风格不良的代码行。 if(width Other(); for(initialization;condition;update) DoSomeThing(); Other(); 4.3.3程序块的分界符独占一行 行并且位于同 说明: 程序块的分界符(如C/C++语言的大括号‘{'和‘}')应各独占一列,同时与引用它们的语句左对齐。 示例: 如下例子不符合规范。 for(...){ ...//programcode } if(...) { ...//programcode } voidExampleFun(void) { ...//programcode } 应如下书写。 for(...) { ...//programcode } if(...) { ...//programcode }voidExampleFun(void) { ...//programcode } 4.3.4多运算符的代码行,不使用默认优先级 说明: 注意运算符的优先级,并用括号明确表达式的操作顺序,防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。 示例: 下列语句中的表达式 word=(high<<8)|low (1)if((a|b)&&(a&c)) (2) if((a|b)<(c&d))(3) 如果书写为 high<<8|lowa|b&&a&ca|b high<<8|low=(high<<8)|low, a|b&&a&c=(a|b)&&(a&c), (1) (2)不会出错,但语句不易理解; a|b 4.3.5不要使用难懂的技巧性很高的语句 说明: 高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。 示例: 如下表达式,考虑不周就可能出问题,也较难理解。 *statPoi+++=1; *++statPoi+=1; 应分别改为如下。 *statPoi+=1; statPoi++;//此二语句功能相当于“*statPoi+++=1; ++statPoi; *statPoi+=1;//此二语句功能相当于“*++statPoi+=1; 4.4空格 4.4.1必要时留空格,使代码更清晰[推荐] 说明: 采用这种松散方式编写代码的目的是使代码更加清晰。 如果语句已足够清晰则不需要加空格,如多重括号间不必加空格,像const、virtual、inline、case等关键字之后,为了突出关键字,至少要留一个空格。 像if、for、while等关键字之后应留一个空格再跟左括号’(’,以突出关键字。 4.4.2二元操作符前后留空格 说明: 如“=”、“+=”“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“八”等二元操作符的前后应当加空格。 4.4.3一元操作符前后不留空格 说明: 一元操作符如“! ”、“~”、“++”、“--”、“&”(地址运算符)等前后不加空 格。 “[]”、“ .”、“->”这类操作符前后不加空格。 示例: (1)逗号、分号只在后面加空格。 inta,b,c;//良好的风格 inta,b,c;//不好的风格 (2)比较操作符,赋值操作符"="、"+=",算术操作符"+"、"%",逻辑操作符"&&"、"&", 位域操作符"<<"、”A"等双目操作符的前后加空格。 if(currentTime>=MAX_TIME_VALUE) a=b+c; a*=2; a=bA2; (3)"! "、"~"、"++"、 "--"、"&"(地址运算符)等单目操作符前后不加空格。 *p='a'; //内容操作"*"与内容之间 flag=! isEmpty; //非操作"! "与内容之间 p=&mem; //地址操作"&"与内容之间 i++; //"++","--"与内容之间 (4)"->"、"."前后不加空格。 p->id=pid;//"->"指针前后不加空格 (5)if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。 if(a>=b&&c>d) 4.5长行拆分 4.5.1较长的语句(>80字符)要分成多行书写 说明: 较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。 示例: permCountMsg.head.len= NO7_TO_STAT_PERM_COUNT_LEN +STAT_SIZE_PER_FRAM*sizeof(_UL); actTaskTable[frameId*STAT_TASK_CHECK_NUMBER+index].occupied=statPoi[index].occupied; actTaskTable[taskNo].durationTrueOrFalse =sysGetSccpStatisticState(statItem); reportOrNotFlag=((taskNo &&(IsStatItemValid(statItem)) &&(actTaskTable[taskNo].ResultData! =0)); 4.5.2循环、判断等语句要在低优先级操作符处划分新行 说明: 循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。 示例: if((taskNo &&(IsStatItemValid(statItem))) { ...//programcode } for(i=0,j=0;(i &&(j { ...//programcode } 4.5.3函数或过程中的参数较长,则要进行适当的划分 说明: 若函数或过程中的参数较长,则要进行适当的划分。 示例: StrCompare((BYTE*)&statObject, (BYTE*)&(actTaskTable[taskNo].statObject),sizeof(_STAT_OBJECT)); FlashActDuration(statItem,frameId*STAT_TASK_CHECK_NUMBER+index,statObject); 5全局变量定义时初始化 变量定义的同时初始化,未初始化的变量需注释其原因。 6注释 6.1必须加注释的位置[推荐] /*, 说明: 注释符有块注释“/*…*/”行注释和“〃…”。 应使用“进行注释,使用 /*”进行代码屏蔽。 注释通常用于: 用户程序文件开头的说明; 编译宏定义、结构和联合定义、管脚定义、常量、重要变量;重要的代码行或段落提示; 函数接口说明。 6.2注释应适量且准确[推荐] 说明: 虽然注释有助于理解代码,但不必要过多注释,也不可与代码体现的意思不一致。 注释是对代码的“提示”,而不是文档,应该“点到为止”。 注释不仅要提示代码,还要体现其显示意义。 过多的注释,会让人眼花缭乱。 如果代码本来就是清楚的,则不必加注释;否则多此一举,令人厌烦。 不一致的注释,更让人费解。 应从标识符命名、程序流程上下功夫,让代码本身就能说明自己,进而减少注释。 示例: 多余的注释 i++;//i加1, 6.3函数接口的注释格式 说明: 对函数接口进行正确而必要的注释,有助于该函数的使用和维护,甚至有助于在代码级上测试该函数。 示例: 函数接口的注释 //函数介绍: //输入参数: //输出参数: //返回值: //备注: //过程参数: (汇编中,过程参数也是需要注明的。 ) voidDrawTriangle(floatx,floaty,floatz) { if(…) { while(…) { }//endofwhile }//endofif } 6.4变量的注释格式[推荐] 说明: 全局变量要有较详细的注释,其注释的内容包括: 功能; 取值范围; 存取注意事项; 存取函数或过程; 其它说明; 示例: 变量的注释。 //activestatistictasknumber #defineMAX_ACT_TASK_NUMBER1000 #defineMAX_ACT_TASK_NUMBER1000//activestatistictasknumber 示例: 可按如下形式说明枚举/数据/联合结构。 //sccpinterfacewithsccpuserprimitivemessagename enumSCCP_USER_PRIMITIVE }; 示例: 全局变量要有较详细的注释。 //TheErrorCodewhenSCCPtranslate //GlobalTitlefailure,asfollows//变量作用、含义 //0-SUCCESS //1-GTTableerror //2-GTerrorOthers-nouse//变量取值范围 //onlyfunctionSCCPTranslate()in //thismodualcanmodifyit,andother //modulecanvisititthroughcall //thefunctionGetGTTransErrorCode()//使用方法 unsignedcharg_uchGTTranErrorCode; 6.5注释与所描述内容进行同样的缩排 说明: 可使程序排版整齐,并方便注释的阅读与理解。 示例: //如下例子,排版不整齐,阅读稍感不方便 voidExampleFun(void) { //codeonecomments CodeBlockOne //codetwocomments CodeBlockTwo } //应改为如下布局。 voidExampleFun(void) { //codeonecomments CodeBlockOne //codetwocomments CodeBlockTwo } 6.6将注释与其上面的代码用空行隔开 说明: 使人能很清晰的看出,注释与被注释的代码。 示例: 如下例子,显得代码过于紧凑。 //codeonecomments programcodeone //codetwocomm
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 软件 编程 规范