一、单片机C语言常见语法问题

1.无返回值函数和有返回值函数

(1)无返回值函数是指函数执行结果中无返回值,在函数定义或声明前用“void”修饰。如:void main();void delay()。

(2)有返回值函数是指函数执行结果中有返回值,在函数定义或声明前有返回类型的说明,在函数执行的末尾有return (返回值),且有返回值的类型和函数定义或声明前的类型一致。如:

unsigned char Key_Scan()
{
  unsigned char temp;
  ……
  return (temp);//temp的括号可以省略
}

例:程序功能为显示按键的按下次数,具体程序格式及其编译界面如图1所示。

Function 无返回值 无返回值程序_c语言延时函数delay延时一秒

图1 有返回值函数的使用

(3)使用有返回值函数的优点及如何避免使用有返回值函数

①优点:后面将介绍模块化编程中在子程序头文件.H中尽量避免使用定义全局变量,以免出现重复定义。而有返回值函数(默认为extern)作为采集数据的接口,可以避免在子程序头文件.H中定义全局变量,实现子程序与主程序间函数传递的问题。凸显模块化编程“高内聚,低耦合”的特点。

②如果简单的程序也可以省去定义有返回值的函数,用全局变量代替。以上“unsigned char Key_Scan()”函数为例,可以将temp定义为全局变量,在主程序中实时调用Key_Scan()函数,以动态刷新temp的值。具体程序格式及其编译界面如图2所示。

Function 无返回值 无返回值程序_Function 无返回值_02

图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所示。

Function 无返回值 无返回值程序_c语言延时函数_03

图3 未声明且不安顺序定义产生的错误

4.不同数据类型之间的赋值规则

Function 无返回值 无返回值程序_c语言延时函数delay_04

如将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为重复声明两个函数但未定义和调用编译完全正确。

Function 无返回值 无返回值程序_c语言延时函数delay_05

图4 声明但未定义的报警

Function 无返回值 无返回值程序_c语言延时函数delay延时一秒_06

图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中函数的调用。