项目七 让我的单片机智能化——函数
一、项目简介
小到手表、收音机、电脑,大到火车、飞机、航母,都包含了许多元器件——相对独立的模块,它们可以分别被维修、更新或替换,而不影响其他部分。
类似地,在程序中也可以制造和使用自己的“元器件”——功能相对独立的模块——函数。一个个函数可以被看作是“蒙着面干活”的黑箱,它们分别用于实现不同的功能,并随时听候我们调用。
有了函数,不仅可大大简化编程的复杂度,还可以使程序逻辑更为清晰。
函数能够实现C语言的模块化程序设计,通过函数,可以让单片机智能化运行。
二、项目目标
本项目为C语言的模块化程序设计,将相对独立的功能用函数来实现。要求了解C语言中函数的概念,掌握函数的定义方法、函数的参数、函数的调用方法、函数的原型与声明。
三、工作任务
根据本项目的要求,以任务驱动的方式,用函数实现模块化程序设计。
① 用有参函数控制LED闪烁速度。
② 按键识别功能模块的函数实现。
③ 按键控制LED流水灯速度。
四、知识准备
1.函数概述
在设计一个较大的程序时,往往分为若干个程序模块,每一个模块包括一个或多个函数。一个C语言程序可以由一个主函数和若干个其他函数构成。由主函数调用其他函数,其他函数再调用别的函数。程序中函数调用的示意图如图7-1所示。
图7-1 程序中函数调用示意图
C语言的函数有以下特点:
① C语言程序由函数组成,包括一个主函数main()和若干其他函数。
C程序的执行是由main()函数开始的,如果在main()函数中调用其他函数,在调用后,返回至main()函数,在main()函数中结束整个程序的运行。
② 函数之间是调用的关系,调用某函数的函数称为主调函数,被调用的函数称为被调函数,如图7-2所示。
图7-2 函数调用示意图
主函数可以调用其他函数,其他函数可以相互调用,但主函数不能被其他函数调用。
③ 一个C51程序由一个或多个文件构成。
④ 每个函数都是平行的,任何函数都不从属于其他函数。
⑤ 从用户角度,函数可以分为:
☆标准函数,即库函数,是由系统提供的,用户不必自己定义,可以直接使用的函数。
☆用户自定义的函数,是用于解决用户特定需要的函数。
⑥ 根据函数形式,函数可以分为:
☆无参函数。
☆有参函数。
⑦ 根据函数有无返回值,函数可以分为:
☆有返回值函数。
☆无返回值函数。
2.函数定义
在C语言中,在程序中用到的函数必须“先定义,后使用”。
定义函数时,应该包括以下四项内容:
① 指定函数的名字,以便以后按名字调用。
② 指定函数的类型,即函数返回值的类型。
③ 指定函数的参数的类型和名字,在调用函数时,向它们传递数据。无参函数调用时,不需要这项。
④ 指定函数的功能。这是函数体要实现的。
3.定义函数的一般形式
函数的定义由两部分组成:
① 头部(第一行)。头部给出了函数名,还规定了函数的返回值类型,以及各个参数的类型和参数名。
② 函数体。即头部下面用{ }包起来的语句,用于实现函数的功能。函数体包括声明部分和语句部分。
函数根据有无参数,可分为无参数函数和有参数函数。
4.无参数函数定义的一般形式
5.有参数函数定义的一般形式
6.空函数
空函数什么工作也不做,没有任何实际作用。其用途是先分配好函数名,等以后扩充函数功能时补上函数体、参数、类型。
小贴士
之前学习过的项目任务中的C语言语句都可以写在函数体中,实现各个项目任务功能的模块化。
C语言中各个函数是相互独立的。函数的定义不能嵌套,在一个函数体内部不允许再定义另外一个函数。
例如,下面的函数定义是错误的:
正确的写法是:
关于函数定义的说明:
① 函数类型。
定义函数时,函数类型应写在函数名之前,其规定了函数返回值的数据类型。函数类型可以是int、long、short、float、char等。如果不写函数类型,默认是int型。
如果要规定函数没有返回值,函数类型应使用关键字void,而不能省略。
例如,下面定义的ledOff()函数的功能是熄灭所有LED灯,该函数不需要返回值,可以定义为:
② 函数名。
函数名必须符合C语言的标识符命名规则。最好给函数取一个“见名知意”的名字。一个好的函数名能够反映该函数的功能。
例如:
ledOff,熄灭所有LED灯;
ledOn,点亮所有LED灯。
③函数名后的()必不可少,即使函数没有参数。如果少了(),那么就不是函数定义了。
7.函数的参数
一个程序由若干个函数组成,各函数调用时,经常要传递一些数据,即调用函数把数据传递给被调用函数,经过被调用函数处理后,得到一个确定的结果,在返回调用函数时,将结果带回调用函数,如图7-3所示。
图7-3 函数参数传递
各函数之间的数据往来通过参数传递和返回语句实现。
8.形式参数和实际参数
函数参数:用于函数之间数据的传递。
形式参数:定义函数时给出的参数。
实际参数:调用函数时给出的参数。
说明:
① 定义函数时,必须说明形参的类型。形参只能是变量,不能是常量或表达式。
② 子函数被调用之前,形参和子函数中的变量不占内存;调用结束并返回后,形参所占的内存被收回。
③ 实参可以是常量、变量或表达式,因为传递过来的是具体数值。
④ 实参和形参类型必须一致(或可以安全转换)。
⑤ C语言中,实参和形参传递是“按值传递”,即单向传递,只与参数相对位置有关,而与变量名无关。
9.函数值
函数值也就是函数的返回值,是一个具体的值。
说明:
① 函数使用return语句返回值。
② 一个函数内可以有多个return语句,执行到任何return语句时,函数都将立即返回到调用函数。
③ return后面的()可以省略,可以返回一个表达式,先求解表达式的值,再返回。
(1)函数值的类型
说明:
① 函数值的类型即函数的类型。
例如,函数max是int型,函数的返回值也是int型。
② 省略了类型说明的函数,默认是int型。
③ return中表达式的值一般和函数类型相同,如果不一致,则需要进行类型转换。
(2)无返回值
说明:
① 如果函数中没有return语句,可以使用void类型。
② 如果一个函数被声明为void类型,没有返回值,那么就不允许再引用它的返回值,只能单纯地调用它。
10.函数调用
(1)函数语句
形式为:
例如:
说明:
这种方式不要求函数带返回值,函数只执行一定操作。
(2)函数表达式
函数的返回值参与运算。
例如:
说明:
void类型函数不能使用这种调用方式。
(3)函数调用的执行过程
① 计算实参表达式的值。
② 按照位置,将实参的值一一传递给形参。
③ 执行被调用函数。
④ 当遇到return(表达式)语句时,计算表达式的值并返回调用函数。
11.函数原型
在程序中调用函数需满足以下条件:
① 被调用函数必须存在,并且遵循“先定义,后使用”的原则。
② 如果被调用函数在主调函数之后定义,则在调用之前需要给出原型说明。
原型说明: