一、单片机C语言常见语法问题
1.无返回值函数和有返回值函数
(1)无返回值函数是指函数执行结果中无返回值,在函数定义或声明前用“void”修饰。如:void main();void delay()。
(2)有返回值函数是指函数执行结果中有返回值,在函数定义或声明前有返回类型的说明,在函数执行的末尾有return (返回值),且有返回值的类型和函数定义或声明前的类型一致。如:
unsigned char Key_Scan()
{
unsigned char temp;
……
return (temp);//temp的括号可以省略
}
例:程序功能为显示按键的按下次数,具体程序格式及其编译界面如图1所示。
图1 有返回值函数的使用
(3)使用有返回值函数的优点及如何避免使用有返回值函数
①优点:后面将介绍模块化编程中在子程序头文件.H中尽量避免使用定义全局变量,以免出现重复定义。而有返回值函数(默认为extern)作为采集数据的接口,可以避免在子程序头文件.H中定义全局变量,实现子程序与主程序间函数传递的问题。凸显模块化编程“高内聚,低耦合”的特点。
②如果简单的程序也可以省去定义有返回值的函数,用全局变量代替。以上“unsigned char Key_Scan()”函数为例,可以将temp定义为全局变量,在主程序中实时调用Key_Scan()函数,以动态刷新temp的值。具体程序格式及其编译界面如图2所示。
图2 更改为无返回值函数
2.函数声明、定义与调用的区别
函数的声明没有函数体,函数的定义有函数体,函数的调用有实参。
①如函数的声明:void delay(unsigned int z);应用于主函数之前,其中z可省略,即只需说明形参的数据类型。
②函数的定义:void delay(unsigned int z)//z为形参
{
while(z--);
}
③函数的调用;
delay(50000);//50000为实参
3.声明与定义的先后顺序问题
①如果在主函数之前先声明,则主函数之后的定义无先后顺序。
②如果不声明而直接定义,则定义的函数必须在主函数之前,且按调用顺序依次定义,如果不按次序定义,则编译过程中会出错,出错的原因为“缺少函数原型”,实际中被定义了,只是将其放在调用函数的后面。如数码管显示函数Seg7_Disp(uint temp)和延时函数delay(uint z),Seg7_Disp(uint temp)在执行中要调用delay(uint z)消除余晖,如果两个函数均未声明,则主函数之前一定要先定义delay(uint z),否则会出错。具体出错如图3所示。
图3 未声明且不安顺序定义产生的错误
4.不同数据类型之间的赋值规则
如将float转换为int型,将舍弃小数点部分。因此转换过程中根据精度要求扩大相应的倍数一般为10的幂次方,在显示中小数点左移相应的位数即可。如8位ADC的电压采集系统,采集电压范围为0-5V,其精度约为0.02V,某个电压值下单片机的采集结果为1.598V(千分位为计算后的误差位),而调用显示函数为Seg7_Disp(unsigned int result),当调用的实参为1.598时即Seg7_Disp(1.598),会将float型转化为unsigned int型,丢失了小数部分。此时可将其扩大100倍变为159.8,显示时显示159,然后将显示函数的小数点左移两位,即可得到相应精度的测量电压。
5.函数声明、未定义、未调用常见问题
函数如果声明,但未定义,且要调用声明的函数则在编译过程中只是会报警(能生成.hex下载文件,此报警不可忽略)如图4所示;如果函数既声明又定义但未调用,则编译过程中会报警为“定义的函数未调用”;而如果只是声明但未调用,则编译会完全正确(不会出现报警);如果声明两个相同的函数,且没有定义和调用,则编译也会完全正确(不会出现报警)。图5为重复声明两个函数但未定义和调用编译完全正确。
图4 声明但未定义的报警
图5重复声明但未定义也未调用编译完全正确
二、模块化程序设计方法
1.头文件和源文件的命名规则
建议一个.C文件对应一个.H文件,且.C和.H文件命名相同。头文件.H主要实现位定义(便于移植过程中硬件的修改)、函数的声明;源文件.C主要实现函数的定义;头文件中一般不能定义全局变量。
2.函数的命名习惯
命名的名称因个人习惯,一般为:目标词+动词+目的地,如:LCD_write_str();Timer0_Init();INT0_ISR()。
3.头文件防重复引用处理
#ifndef xxx
#define xxx
#endif
①“被重复引用”是指一个头文件在一个.C文件中引用了多次。
②“被重复引用”的后果是增加了编译的工作量,仅仅是编译效率降低。但如果定义了全局变量,则会引起重复定义的错误。如:去掉#include头文件中的防重复引用的宏定义,系统编译会出错。
③防重复引用处理,只有好处没有坏处,应该养成良好的编程习惯。
4.头文件中函数的声明
头文件中函数的声明关键字extern可以省略,一般默认的是extern。
5.不同源文件.C直接函数的调用
首先将源文件.C加载至工程,主函数main.c中包含该工程的头文件,就可以实现对其源文件.C中函数的调用。