注:本文提到的编程标准只是我个人的一些想法和实践。 有些体验可能并不适合所有场合。 当然,偏见的观点是不可避免的。 请大家批评指正。
1.1. 实验目的
前面我们学习了如何将一个复杂的单片机程序按照模块功能划分为多个程序模块,然后利用头文件包含将不同的程序模块有机地链接起来。 以模块化格式编写的程序将非常易于阅读和查询。
在这个例子中,我们进一步对单片机程序的编程规范做一些简单的说明,这样我们写的程序就不会显得那么乱,每个读我们程序的人都能看懂。
1.2. 设计理念
在这个例子中,我们将从变量命名规范、程序注释、程序体结构划分等方面来简单了解如何让程序看起来干净整洁。 变量的含义一看就知道。 程序的各个部分都是独立的,但又可以有机地组合起来。
1.3. 基础知识
我们来看看变量的命名约定、变量的初始化、函数体的结构以及注解方法。 至于其他的编程规范和方法,我们会在后续的例子中逐步了解。
1.4. 变量名称的命名约定
变量名应使用有特定含义的英文单词组合或缩写,避免使用i、j、k等无任何含义的变量名。
不过,i、j、k 等变量也并非完全无法使用。 在某些情况下,建议使用 i、j 和 k 等变量。 什么情况下可以使用这种无意义的变量呢? 可以用在循环语句中,如for循环、while循环、do…while循环,循环次数可以用i、j、k等变量表示。 在一些非常简单、目的很明确的情况下,比如循环次数,使用这些变量不仅不会造成歧义,而且还能让程序更加简洁。
在大多数情况下,建议使用具有特定含义的变量名称。 我个人习惯使用动词+名字的方式,每个年级的第一个字母大写。 例如,定义一个向DS1302写入数据的变量可以定义为WriteData。 当程序中包含多个外设模块且这些模块的操作类似时,最好添加外设模块的名称以及具体操作的变量。 名称之间使用下划线“_”将两者组合起来,以区分对哪个模块进行操作。 例如,程序中有两个外围模块LCD1602和DS1302,两者都有数据写入操作。 它们分别命名为:LCD1602_WriteData 和 DS1302_WriteData。 也可以定义为WriteData_LCD1602、WriteData_DS1302。 模块名称可以在前面,也可以在后面,根据自己的习惯。
对于英文名比较长的单词,可以使用缩写,但缩写名要容易理解,或者使用常规缩写。 例如,对于串口数据发送和接收所使用的变量,一般约定用Rev代表接收数据变量,Trn代表发送数据变量。 对于数组变量,一般用Buff来命名。
另一种命名约定是在命名时包含变量的数据类型。 例如,要定义一个无符号整数数据,可以像这样定义 unsigned int uiCounter 。 在这种情况下,只要看到变量名前面有“ui”,就知道该变量是无符号整型数据。
1.4.1. 变量的初始化
变量定义时可以直接初始化,如unsigned int uiCounter=0; 您也可以只定义变量但不初始化变量的值。
如果变量在定义时没有初始化其值,则在程序中使用时应为该变量设置明确的值。 不能直接使用,否则容易出错。 例如首先定义了变量unsigned int uiCounter; 它的值没有被初始化。 此时,如果直接执行如下操作 P0=uiCounter,则 P0 口的 8 位状态是随机的,并且每次调用该语句时,P0 口的 8 位状态都不同。
1.4.2. 函数体结构
一般函数体的内容包括:局部变量定义和初始化、具体函数语句、函数返回值语句。
其中,局部变量定义和初始化以及函数返回值语句不需要包含。 另外,函数返回值语句可以在函数体的任意位置,不一定限于函数末尾。
函数内最好用空行分隔局部变量初始化、执行语句、返回值三部分。 例如下面的代码。
bit BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
RW=1;
E=1; //E=1,才允许读写
_nop_(); //空操作
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
result=BF; //将忙碌标志电平赋给result
E=0; //将E恢复低电平
return result;
}
这样做的好处是可以让函数结构清晰。
还建议根据不同的功能和内容,在函数体中的语句中添加空行。 这样的节目不会让人感到疲倦。
1.4.3. 对节目的评论
程序注释分为两部分:函数函数注释和程序语句注释。
函数语句的注释一般包括函数函数、入口参数、出口参数等,对于比较复杂的函数,有的还建议添加函数创建时间、更改时间、更改内容等。
如下代码所示。
/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:dictate
***************************************************/
void WriteInstruction (unsigned char dictate)
{
}
程序语句的注释一般放在语句后面,并与语句保持适当的空格,以免程序语句和注释被视为一体。
对于比较长的语句,或者这个语句的注释比较长,注释一般放在语句的上面。 如下。
/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
***************************************************/
void WriteAddress(unsigned char x)
{
//显示位置的确定方法规定为"80H+地址码x"
WriteInstruction(x|0x80);
}
1.5. 电路设计
该示例没有电路。
1.6. 编程
本例没有具体的程序代码。
1.7. 模拟示例
本例中没有进行模拟。
1.8. 概括
单片机项目设计不仅仅是为了实现功能,更是为了让程序设计得更合理、更清晰、易于移植,因为大多数情况下,公司里的单片机项目不会被设计者单独看,让单独一个人一直在管理和修改项目。 所以要养成良好的编程习惯。