第3章 简洁的Arduino语言 Arduino使用C/C++语言编写程序,它的语法是建立在C/C++基础上的,其实就是基础的C语法。在一般情况下,C语言要求一个源程序不论由多少个文件组成,都必须有且仅有一个主函数,即main()函数。C语言程序执行是从主函数开始的。但在Arduino中,主函数main()已经在内部定义了,开发者只需要完成setup()函数和loop()函数,就能够完成Arduino程序的编写。其中,setup()函数负责Arduino 程序的初始化部分,loop()函数负责Arduino 程序的执行部分。 下面重点介绍Arduino程序的架构、数据类型、数据运算、程序结构、函数的使用。 3.1语言概览 Arduino语言很简洁,在官网https://www.arduino.cc/reference/en/上可以查询到最新版本的语言参考,图31所示为Arduino语言参考2019版。 图31官网的语言参考 Arduino语言主要由程序结构、变量、函数三大部分组成,见表31。标注为“Arduino”的为Arduino所特有,标注为“标准C”的与标准C语言一致。 表31Arduino语言参考 结构、流程、运算变量、注释Arduino函数 setup()ArduinoHIGH | LOWArduino数字I/O loop()ArduinoINPUT | OUTPUTArduinopinMode()Arduino 程序流程控制true | false标准CdigitalWrite()Arduino if标准C整型常量标准CdigitalRead()Arduino if...else标准C浮点数常量标准C模拟I/O for标准C数据类型标准CanalogReference()Arduino switch case标准Cvoid标准CanalogRead()Arduino while标准Cboolean标准CanalogWrite()Arduino do...while标准Cchar标准C高级I/O break标准Cunsigned char标准CshiftOut()Arduino continue标准Cbyte标准CpulseIn()Arduino return标准Cint标准C计时及延时 goto标准Cunsigned int标准Cmillis()Arduino 算术运算符word标准Cdelay(ms)Arduino + (加)标准Clong 标准CdelayMicroseconds(μs) Arduino - (减) 标准Cunsigned long 标准C数学库 * (乘) 标准Cfloat 标准Cmin() Arduino / (除) 标准Cdouble 标准Cmax() Arduino % (取模) 标准Cstring 标准Cabs() Arduino 比较运算符String(c++) 标准Cconstrain() Arduino == (等于) 标准Carray 标准Cmap() Arduino != (不等于) 标准C数据类型转换标准Cpow() Arduino < (小于) 标准Cchar() 标准Csqrt() Arduino > (大于) 标准Cbyte() 标准C三角函数 <= (小于或等于) 标准Cint() 标准Csin(rad) Arduino >= (大于或等于) 标准Cword() 标准Ccos(rad) Arduino 布尔运算符long() 标准Ctan(rad) Arduino && (逻辑与) 标准Cfloat() 标准C随机数 || (逻辑或) 标准C变量作用域标准CrandomSeed() Arduino ! (逻辑非) 标准Cstatic (静态变量)标准Crandom() Arduino 指针运算符volatile (易变变量) 标准Crandom() Arduino * (指针运算符) 标准Cconst (固定变量) 标准C位操作 &(地址运算符)标准C辅助工具标准ClowByte() Arduino 位运算sizeof() 标准ChighByte() Arduino 续表 结构、流程、运算变量、注释Arduino函数 & (位与) 标准C扩展语法标准CbitRead() Arduino | (位或) 标准C; (分号) 标准CbitWrite() Arduino ^(位异或) 标准C{ (大括号)标准CbitSet() Arduino ~ (位非) 标准C// (单行注释) 标准CbitClear() Arduino << (左移) 标准C/**/ (多行注释) 标准Cbit() Arduino >> (右移) 标准C#define (宏定义) 标准C设置中断函数 复合运算符标准C#include(包含) 标准CattachInterrupt() Arduino ++ (自加) 标准C标准CdetachInterrupt() Arduino -- (自减) 标准Cinterrupts() Arduino += (复合加) 标准CnoInterrupts() Arduino -= (复合减) 标准C主要串口通信函数 *= (复合乘) 标准Cbegin() Arduino /= (复合除) 标准Cavailable() Arduino &= (复合与) 标准Cread() Arduino |= (复合或) 标准Cflush Arduino print() Arduino println() Arduino write() Arduino peak() Arduino serialEvent() Arduino 3.2Arduino语言基础 3.2.1程序的架构 Arduino程序的架构大体可以分为3部分,如程序31所示。 1/******************************************************** 2* 程序3-1: Arduino程序的架构 3*********************************************************/ 4int tmpPin = 8; //在最前面定义变量,把引脚号赋值给某变量 5void setup() 6{ 7//在这里填写setup()函数代码,它只运行一次 8} 9void loop() 10{ 11//在这里填写loop()函数代码,它会不断重复运行 12} (1) 声明变量和接口名称。 (2) setup()。Arduino程序运行时,首先要调用setup()函数,一般放在程序开头,用于初始化变量、设置引脚的输出/输入类型、配置串口、引入类库文件等。 每次Arduino上电或重启后,setup()函数只运行一次。 (3) loop()。loop()函数用于执行程序,是一个死循环,其中的代码将被循环执行,用于完成程序的功能,如读入引脚状态、设置引脚状态等。 3.2.2数据类型 Arduino与C语言类似,所有的数据都必须指定数据类型。数据类型在数据结构中的定义是值的集合及在这个值的集合上的一组操作。各种数据类型都需要在特定的地方使用。一般来说,变量的数据类型决定如何将代表这些值的位存储到计算机的内存中,在声明变量时,需要指定它的数据类型,以便存储不同类型的数据。 常用的数据类型有整型、浮点型、布尔型、字符型、字节型、数组及字符串等。 (1) 整型。整型即整数类型。Arduino可以使用的整数类型及取值范围见表32。 表32Arduino支持的整数类型及取值范围 整 数 类 型比特数取 值 范 围示例 有符号基本整型 [signed] int16-32768~+32767int a=-3; 无符号基本整型 unsigned int160~65535unsigned int b = 3267; 有符号长整型 long [int]32-2147483648~+2147483647long c=-4235; 无符号长整型 unsigned long [int]320~+4294967296unsigned long d=1000; (2) 浮点型。浮点型其实就是平常所说的实数。Arduino有float(单精度)和double(双精度)两种浮点型。浮点数可以用来表示含有小数点的数,如1.24。float浮点型数据占4字节的内存; double浮点型 数据占8字节的内存。双精度浮点型数据比单精度浮点型数据的精度更高。 (3) 布尔型。布尔型(boolean)变量的值有两个,即假 (false)和真(true)。布尔值是一种逻辑值,可以用来进行计算。最常用的布尔运算符为: 与运算(&&)、或运算(||)及非运算 (!)。表33为布尔运算真值表。 表33布尔运算真值表 ABA与BA或BA非 TrueTrueTrueTrueFalse TrueFalseFalseTrueFalse 续表 ABA与BA或BA非 FalseTrueFalseTrueTrue FalseFalseFalseFalseTrue 对于A&&B,仅当A和B均为真时,运算结果才为真; 否则,运算结果为假。对于A||B运算,仅当A和B均为假时,运算结果才为假; 否则,运算结果为真。对于!A运算,当A为真时,运算结果为假; 当A为假时,运算结果为真。 (4) 字符型。字符型(char)变量可以用来存放字符,数值范围为-128~+128,如: char A=58; (5) 字节型。字节型(byte)变量可用1字节来存储8位无符号数,数值范围为0~255,如: byte B=8; (6) 数组。数组是由一组具有相同数据类型的数据构成的集合。数组中的每一个数据都具有相同的数据类型,可用一个统一数组名和下标来唯一确定数组中的每个数据。Arduino的数组是基于C语言的。本节只简单介绍如何定义和使用数组。 数组的声明和创建与变量一致,下面是一些创建数组的实例: int arraylnts[6]; int arrayNums[] = {2,4,6,8,11}; int arrayVals[6] = {2,4,-8,3,5,7}; char arrayString[7] = "Anlaino" ; 由实例可以看出,Arduino 数组的创建可以指定初始值,如果没有指定初始值,则编译器默认为0; 同时,如果不指定数组的大小,则编译器在编译时会通过计算数据的个数来指定数组的大小。 数组被创建之后,可以指定数组中某个数据的值: int intArray[5]; intArray[2] = 2; 数组是从零开始索引的。也就是说,数组被初始化之后,其中第一个数据的索引为0,如上例所示,arrayVals[0]=2,0为数组第一个元素2的索引号,以此类推,在这个包含6个元素的数组中,5是最后一个元素7的索引号,即arrayVals[5]=7,而arrayVals[6]是无效的,它将会是任意的随机信息(内存地址)。 程序32先创建了一个数组,然后在for循环中,将数组中的每一个数据送到串口打印。 1/******************************************************** 2* 程序3-2: 数组的使用 3*********************************************************/ 4void setup() 5{ 6//定义长度为10的数组 7int intArray[10] = {1,2,3,4,5,6,7,8,9,10}; 8int i; 9for(i = 0; i < 10; i = i + 1) //循环遍历数组 10{ 11Serial.println(intArray[i]); //打印数组元素 12} 13} 14void loop() 15{ 16} (7) 字符串。字符串的定义方式有两种: 一种是以字符型数组的方式定义的,另一种是用String类型定义的。 以字符型数组方式定义的语句为: char字符串名称[字符个数]; 以字符型数组方式定义字符串的使用方法与数组的使用方法一致,有多少个字符就占用多少字节的存储空间。 在大多数情况下都使用String类型来定义字符串。该类型提供了一些操作字符串的成员函数,使字符串使用起来更为灵活。其定义语句为: String字符串名称; 字符串既可以在定义时赋值,也可以在定义以后赋值。假设定义一个名为str的字符串,则下面两种方式是等效的: String str; str= "Arduino"; 或者 String str = "Arduino"; 3.2.3数据运算 最常用的Arduino运算符包括赋值运算符、算术运算符、关系运算符、逻辑运算符及递增/减运算符。 (1) 赋值运算符。 =(等于)为指定某个变量的值,如A=x,将变量x的值放入变量A中。 +=(加等于)为加上某个变量的值,如B+=x,将变量B的值与变量x的值相加,将二者的和放入变量B中,与B=B+x表达式相同。 -=(减等于)为减去某个变量的值,如C-=x,将变量C的值减去变量x的值,差放入变量C中,与C=C-x表达式相同。 *=(乘等于)为乘以某个变量的值,如D*=x,将变量D的值与变量x的值相乘,积放入变量D中,与D=D*x表达式相同。 /=(除等于)为除以某个变量的值,如E/=x,将变量E的值除以变量x的值,商放入变量E中,与E=E/x表达式相同。 %=(取余等于)为对某个变量的值取余数,如F%=x,将变量F的值除以变量x的值,余数放入变量F中,与F=F%x表达式相同。 &=(与等于)为对某个变量的值按位进行与运算,如G&=x,将变量G的值与变量x的值进行AND运算,结果放入变量G中,与G=G&x表达式相同。 |=(或等于)为对某个变量的值按位进行或运算,如H|=x,将变量H的值与变量x的值进行OR运算,结果放入变量H中,与H=H|x表达式相同。 ^=(异或等于)为对某个变量的值按位进行异或运算,如I^=x,将变量I的值与变量x的值进行XOR运算,结果放入变量I中,与I=I^x表达式相同。 <<=(左移等于)为将某个变量的值按位进行左移,如J <<=n,将变量J的值左移n位,与J=J<<n表达式相同。 >>=(右移等于)为将某个变量的值按位进行右移,如K >>=n,将变量K的值右移n位,与K=K>>n表达式相同。 (2) 算术运算符。 +(加)为对两个值求和,如A=x+y,将变量x与y的值相加,和放入变量A中。 -(减)为对两个值相减,如B=x-y,将变量x的值减去变量y的值,差放入变量B中。 *(乘)为对两个值相乘,如C=x*y,将变量x与y的值相乘,积放入变量C中。 /(除)为对两个值相除,如D=x/y,将变量x的值除以变量y的值,商放入变量D中。 %(取余)为对两个值做取余运算,如E=x%y,将变量x的值除以变量y的值,余数放入变量E中。 (3) 关系运算符。 ==(相等)为相等关系运算符, 如x==y,若变量x与y的值相等,则其结果为1,不相等则其结果为0。 !=(不相等)为不相等关系运算符,如x!=y,若变量x与y的值不相等,则其结果为1,相等则其结果为0。 <(小于)为小于关系运算符,如x<y,若变量x的值小于变量y的值,则其结果为1,否则其结果为0。 > (大于)为大于关系运算符,如x>y,若变量x的值大于变量y的值,则其结果为1,否则其结果为0。 <=(小于或等于)为小于或等于关系运算符,如x<=y, 若变量x的值小于或等于变量y的值,则其结果为1,否则其结果为0。 >=(大于或等于)为大于或等于关系运算符,如x>=y, 若变量x的值大于或等于变量y的值,则其结果为1,否则其结果为0。 (4) 逻辑运算符。 &&(与运算)为对两个表达式的布尔值进行按位与运算,如(x>y)&&(x<z),若变量x的值大于变量y的值并且若变量x的值小于变量z的值,则其结果为1,否则其结果为0。 ||(或运算)为对两个表达式的布尔值进行按位或运算,如(x>y)||(x<z), 若变量x的值大于变量y的值或者变量x的值小于变量z的值,则其结果为1,否则其结果为0。 !(非运算)为对某个布尔值进行非运算,如!(x>y), 若变量x的值大于变量y的值,则其结果为0,否则其结果为1。 (5) 递增/减运算符。 ++ (加1)为将运算符左边的值自动增1,如x++,将变量x的值加1,表示在x使用后,再使x值加1。 --(减1)为将运算符左边的值自动减1,如x--,将变量x的值减1,表示在使用x后,再使x值减1。 3.3程序结构 任何复杂的算法都可以由顺序结构、循环结构及选择结构这3种基本结构组成,在构造算法时也仅以这3种结构作为基本单元。一个复杂的程序可以被分解为若干个结构和若干层子结构,从而使程序结构的层次分明、清晰易懂,易于进行正确性的验证和纠正程序中的错误。 3.3.1顺序结构 在3种程序结构中,顺序结构是最基本、最简单的程序组织结构。在顺序结构中,程序按语句的先后顺序依次执行。一个程序或者一个函数在整体上是一个顺序结构,由一系列语句或者控制结构组成。这些语句与控制结构都按先后顺序运行。 程序33中的loop()函数的4条语句就是顺序执行的。 1/******************************************************** 2* 程序3-3: 顺序结构 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; 6void setup() 7{ 8pinMode(ledPin,OUTPUT); 9} 10void loop() 11{ 12digitalWrite(ledPin,HIGH); //点亮LED 13delay(delayTime); //延时 14digitalWrite(ledPin,LOW); //熄灭LED 15delay(delayTime); //延时 16} delay()函数使程序暂停设定的时间(ms),例如,delay(500)即为延时500ms。 3.3.2选择结构 选择结构又称为选取结构或分支结构。编程过程经常需要根据当前的数据做出判断后,再进行不同的选择。这时就会用到选择结构,即针对同一个变量,根据不同的值,程序执行不同的语句。 选择语句有以下两种形式。 (1) if语句。 if语句是最常用的选择结构实现方式,当给定的表达式为真时,就会执行其后的语句。if语句有3种结构形式。 第一种是简单分支结构,语法结构为: if(表达式) { 语句; } 程序34通过改变延时时间来控制小灯由慢到快进行闪烁,到达一定的频率后恢复初始频率。 1/******************************************************** 2* 程序3-4: if语句的使用 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; 6void setup() 7{ 8pinMode(ledPin,OUTPUT); 9} 10void loop() 11{ 12digitalWrite(ledPin,HIGH); //点亮小灯 13delay(delayTime); //延时 14digitalWrite(ledPin,LOW); //熄灭小灯 15delay(delayTime); 16delayTime = delayTime - 100; //每次将延时时间减少0.1s 17if(delayTime < 100) 18{ 19delayTime = 1000; //当延时时间少于0.1s时,重设为1s 20} 21} 该程序用到了if条件判断语句,每次运行到if语句时都会进行判断,在delayTime>=100时,大括号里面的delayTime=1000是不执行的,进入下一次循环; 当delayTime<100时,delayTime=1000被执行,delayTime 的值变为1000,进入下一次循环。 第二种是双分支结构,语法结构为: if(表达式) { 语句1; } else { 语句2; } 该结构增加了一个else语句,当给定表达式的结果为假时,便会运行else 后的语句。程序35与程序34实现的功能相同,但利用了双分支结构。 1/******************************************************** 2* 程序3-5: 双分支结构if语句的使用 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; 6void setup() 7{ 8pinMode(ledPin,OUTPUT); 9} 10void loop() 11{ 12digitalWrite(ledPin,HIGH); //点亮小灯 13delay(delayTime); //延时 14digitalWrite(ledPin,LOW); //熄灭小灯 15delay(delayTime); 16if(delayTime < 100) 17{ 18delayTime = 1000; //当延时时间少于0.1s时,重设为1s 19} 20else 21{ 22delayTime = delayTime - 100; //每次将延时时间减少0.1s 23} 24} 第三种结构为多分支结构,可以判断多种情况,语法结构为: if(表达式1) { 语句1; } else if(表达式2) { 语句2; } else if(表达式3) { 语句3; } else { 语句4; } ... 程序36可使小灯的闪烁频率在不同的时间段内保持一定的闪烁频率,达到一定的时间后,重新恢复初始的闪烁频率。 1/******************************************************** 2* 程序3-6: 多分支结构if语句的使用 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; 6void setup() 7{ 8pinMode(ledPin,OUTPUT); 9} 10void loop() 11{ 12digitalWrite(ledPin,HIGH); //点亮小灯 13delay(delayTime); //延时 14digitalWrite(ledPin,LOW); //熄灭小灯 15delay(delayTime); 16if(delayTime > 800 && delayTime <=1000) 17{ 18delayTime = delayTime - 100; //每次将延时时间减少0.1s 19} 20else if(delayTime > 500 && delayTime <=800) 21{ 22delayTime = delayTime - 50; //每次将延时时间减少0.05s 23} 24else if(delayTime > 200 && delayTime <=500) 25{ 26delayTime = delayTime - 20; //每次将延时时间减少0.02s 27} 28else 29{ 30delayTime = 1000; //将延时时间重新设定为1s 31} 32} (2) switch…case语句。 处理比较复杂的问题时,可能会存在很多选择分支的情况,如果还使用if的结构编写程序,则会使程序冗长,可读性差,此时可以使用switch…case语句。switch…case语句的语法结构为: switch(表达式1) { case常量表达式1: 语句1; break; case常量表达式2: 语句2; break; case常量表达式3: 语句3; break; ... default: 语句n; break; } switch结构会将switch 语句后的表达式与case后的常量表达式进行比较,如果相符,则运行常量表达式所对应的语句; 如果不相符,则会运行default后的语句。 程序37判定一个给定值,当给定值为1时,红灯闪烁; 当给定值为2时,绿灯闪烁; 当给定值为3时,蓝灯闪烁。 1/******************************************************** 2* 程序3-7: 多分支结构switch语句的使用 3*********************************************************/ 4int ledRed = 5; 5int ledGreen = 6; 6int ledBlue = 7; 7int num = 1; //可以改变该值为2、3,观察不同灯的闪烁情况 8void setup() 9{ 10pinMode(ledRed,OUTPUT); 11pinMode(ledGreen,OUTPUT); 12pinMode(ledBlue,OUTPUT); 13} 14void loop() 15{ 16switch(num) 17{ 18case 1: 19digitalWrite(ledRed,HIGH); 20delay(200); 21digitalWrite(ledRed,LOW); 22break; 23case 2: 24digitalWrite(ledGreen,HIGH); 25delay(200); 26digitalWrite(ledGreen,LOW); 27break; 28case 3: 29digitalWrite(ledBlue,HIGH); 30delay(200); 31digitalWrite(ledBlue,LOW); 32break; 33} 34} 3.3.3循环结构 (1) for循环语句。 for循环语句可以控制循环的次数,语法结构为: for(初始化; 条件检测; 循环状态) { 程序语句; } 初始化语句是对变量进行条件初始化。条件检测语句是对变量的值进行条件判断。如果为真,则运行在for循环语句大括号中的内容; 如果为假,则跳出循环。执行完大括号中的语句后,接着执行循环状态语句,然后重新执行条件检测语句。 程序38利用for循环,让小灯每闪烁20次,就暂停3s。 1/******************************************************** 2* 程序3-8: for循环语句的使用 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 100; //定义小灯闪烁间隔delayTime为0.1s 6int count; //定义计数器变量 7void setup() 8{ 9pinMode(ledPin,OUTPUT); 10} 11void loop() 12{ 13for(count=0; count<20; count++) 14{ 15digitalWrite(ledPin,HIGH); 16delay(delayTime); 17digitalWrite(ledPin,LOW); 18delay(delayTime); 19} 20delay(3000);//延时3s 21} (2) while循环语句。 while循环语句的语法为: while(条件语句) { 程序语句 } 当条件语句为真时,则执行循环中的程序语句; 否则跳出while循环,执行后续语句。 程序39利用while循环,完成与程序38相同的功能(小灯每闪烁20次就暂停3s)。 1/******************************************************** 2* 程序3-9: while循环语句的使用 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 100; //定义小灯闪烁间隔delayTime为0.1s 6int count; //定义计数器变量 7void setup() 8{ 9pinMode(ledPin,OUTPUT); 10} 11void loop() 12{ 13count = 0; 14while(count<20) 15{ 16digitalWrite(ledPin,HIGH); 17delay(delayTime); 18digitalWrite(ledPin,LOW); 19delay(delayTime); 20count ++ ; 21} 22delay(3000);//延时3s 23} 程序38与程序39的缺点是: 虽然可以在一个loop()函数中,通过for或while循环来完成闪灯20次后延时3s的要求,但是loop()函数的执行时间过长。而在应用中,经常会在loop()函数中检查是否有中断或者其他信号,如果单次loop()执行时间较长,那么不可避免地会增加程序的响应时间。因此,比较而言,采用if语句和count计数器更好些。 程序清单310如下: 1/******************************************************** 2* 程序3-10: 使用if语句和count计数器的闪灯程序 3********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; //定义延时变量delayTime为1s 6int delayTime2 = 3000; //定义延时变量delayTime2为3s 7int count=0; //定义计数器变量并初始化为0 8void setup() 9{ 10pinMode(ledPin,OUTPUT); 11} 12void loop() 13{ 14digitalWrite(ledPin,HIGH); 15delay(delayTime); 16digitalWrite(ledPin,LOW); 17delay(delayTime); 18count ++; 19if(count==20) 20{ 21delay(delayTime2); //当计数器数值为20时,延时3s 22count=0; 23} 24} 3.4函数的使用 3.4.1自己封装函数 以闪灯为例,LED灯要闪烁20次,可以将闪灯这个功能封装到一个函数中,当多次需要闪灯时,便可以直接调用这个闪灯函数了。 1/******************************************************** 2* 程序3-11: 自己封装函数 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; //定义延时变量delayTime为1s 6int delayTime2 = 3000; //定义延时变量delayTime2为3s 7int count; 8void setup() 9{ 10pinMode(ledPin,OUTPUT); 11} 12void loop() 13{ 14for(count=0; count<20; count ++) //调用20次闪烁函数 15{ 16flash(); 17} 18delay(delayTime2); //延时3s 19} 20void flash() //定义无参数的闪灯函数 21{ 22digitalWrite(ledPin,HIGH); 23delay(delayTime); 24digitalWrite(ledPin,LOW); 25delay(delayTime); 26} 在该程序里,调用的flash()函数实际上就是LED闪烁的代码,相当于程序运行到这个函数时,便跳入到4行闪灯代码中,函数非常简单。 有些函数需要接收参数才能执行特定的功能。在这个例子中,flash()函数很简单,它没有任何返回值,而且也没有任何参数。 3.4.2函数中的参数传递 所谓函数参数,就是函数中需要传递值的变量、常量、表达式、函数等。接下来的例子会将闪灯函数改造一下,使其闪烁时间可以变化。 1/******************************************************** 2* 程序3-12: 函数中的参数传递 3*********************************************************/ 4int ledPin = 13; 5int delayTime = 1000; //定义延时变量delayTime为1s 6int delayTime2 = 3000; //定义延时变量delayTime2为3s 7int count; 8void setup() 9{ 10pinMode(ledPin,OUTPUT); 11} 12void loop() 13{ 14for(count=0; count<20; count++) 15{ 16flash(delayTime); //调用20次闪烁灯光的函数,延时为1s 17} 18delay(delayTime2); //延时3s 19} 20void flash(int delayTime3)//定义具有参数的闪灯函数 21{ 22digitalWrite(ledPin,HIGH); 23delay(delayTime3); 24digitalWrite(ledPin,LOW); 25delay(delayTime3); 26} 在改进的闪灯例子中,flash()函数接收一个整型的参数delayTime3,称为形参,全名为形式参数。形参是在定义函数名和函数体时使用的参数,目的是用来接收调用该函数时传递的参数,值一般不确定。形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束并返回主调用函数后,则不能再使用该形参变量。 loop()函数中flash()接收的参数delayTime称为实参,全名为实际参数。实参是传递给形参的值,具有确定的值。实参和形参在数量上、类型上、顺序上应严格一致,否则将会发生类型不匹配的错误。 3.4.3非空类型的函数 如果是非空类型的函数,那么在构造函数时应注意函数的返回值应和函数的类型保持一致,在调用该函数时,函数返回值应和变量的类型保持一致。 下面的程序中包含一个比较两个整数大小的函数Max(),并给出了这个具有返回值的函数的定义和调用。 1/******************************************************** 2* 程序3-13: 非空类型的函数 3*********************************************************/ 4//定义求两个数最大值的函数 5int Max(int a,int b) 6{ 7if(a>=b) 8{ 9return a; //a>=b时返回a 10} 11else 12{ 13return b; //a<b时返回b 14} 15} 16void setup() 17{ 18int x=Max(10,20); //调用Max()函数 19Serial.println(x); 20} 21void loop() 22{ 23}