首页 理论教育 Arduino单片机开发教程:switch语句

Arduino单片机开发教程:switch语句

时间:2023-10-23 理论教育 版权反馈
【摘要】:switch语句具有以下语法:使用上述嵌套if讨论中的myDay示例,每个case语句块对应于一周中的某一天。最后一个case语句块将用于case 7。在switch语句中,case语句块以冒号字符开头,并扩展到break语句。break语句使程序控制跳转到switch语句右括号后的第一个语句。笔者比较喜欢switch语句,因为即使遵循正常的编码风格约定,也很少需要水平滚动源代码窗口。此外,由于switch和break语句实际上都会生成汇编语言跳转指令,因此执行的if测试不会像使用级联if语句块那样冗余。

Arduino单片机开发教程:switch语句

switch语句具有以下语法:

使用上述嵌套if讨论中的myDay示例,每个case语句块对应于一周中的某一天。最后一个case语句块将用于case 7。如果表达式1不知何故,它的值不是1到7,那么可能会执行默认语句块(default)发出某种错误消息或条件(例如,红色LED亮起)。换句话说,如果expression1不匹配任何大小写值,则执行默认语句块(default)。你可以思考对于没有相应大小写值的任何值,设置default语句块做其他处理。

表达式1的计算结果必须为整型数据类型。也就是说,expression1可以是byte、char、int或long(包括它们的无符号对应项)——它不能是浮点类型(float或double),也不能是引用数据类型(例如,string)。虽然Arduino C也接受布尔值expression1的数据类型,这在我看来是可疑的,不建议使用它。毕竟,布尔值不是真就是假,所以ifelse语句块可以工作。

请注意,括号不用于描述case语句块。在switch语句中,case语句块以冒号字符开头,并扩展到break语句。

那么,一旦程序控制处理了break语句,它会去哪里呢?break语句使程序控制跳转到switch语句右括号后的第一个语句。在上面的语法指南中,流程被发送到任意语句,其中//这是开关出现在源代码中后的下一个语句。

如果你忘记了给定case的break语句,那么程序的执行将转到下一个case语句。这可能是程序中错误的潜在来源。但是,有时两个case值可能需要执行相同的程序语句。

笔者比较喜欢switch语句,因为即使遵循正常的编码风格约定,也很少需要水平滚动源代码窗口。此外,由于switch和break语句实际上都会生成汇编语言跳转指令,因此执行的if测试不会像使用级联if语句块那样冗余。尽管在某些情况下必须使用级联if,但交换机几乎总是一个更好的选择。

现在让我们看看如何提高修改后的Blink程序的分数。如果回顾清单4-1,你会发现以下语句:

int led1=13;

int led2=12;//This is for the second LED

如果你是一名初级程序员,那么数字13和12对你来说有意义吗?笔者不这么认为。因此,笔者称之为幻数,因为它们是程序中的常数,本身没有明显的意义。

如果我们将代码更改为:

#define IOPIN13 13

#define IOPIN12 12

int led1=IOPIN13;

int led2=IOPIN12;//This is for the second LED

现在,数据定义至少让笔者对数值12和13在程序中的含义有了一些了解,而且我认为它使led1和led2的用途更加明确。

当编译器接管并开始编译你的程序代码时,你可以认为它实际上两次通过代码。在第一个过程中,编译器会查找它必须先处理的指令,它实际上可以开始编译你的程序代码。这些指令称为预处理器指令。

因为它们必须经过“预处理”,编译器才能完成它的工作。Arduino C不支持所有标准的C预处理器指令。表4-3给出了Arduino C的预处理器指令。

请注意,预处理器指令实际上不是语句,因为它们不是以分号结尾的。因此,它们必须按照下面的示例所示编写。

表4-3 Arduino C预处理器指令

Arduino语言引用(使用IDE中的帮助引用或http://arduino.cc/it/Reference/HomePage online)声明只支持“定义”和“包含”。然而,使用表4-3中的预处理器指令并没有在Arduino 1.0编译器中产生编译错误。这就提出了一个问题:使用其他预处理器指令是否安全?回答是“否”。除#if指令及其变体外,你真的没有太多选择。然而,由于Arduino IDE源于开放源代码系列,因此该编译器很可能是Gnu C编译器的派生版本,Gnu C编译器坚如磐石。因此,如果必须使用其中一个“不受支持的”预处理器指令,请继续。如果你后来发现你的项目突然开始引起大家的不满,那么你可能需要重新审视一下。

这里重要的是要注意#define preprocessor指令提供了一种以更有意义的方式定义常量的方法。那又怎么样?好吧,让我们看看define给变量带来的另一个好处。假设程序代码中包含以下内容:

int minCarFine=125;

int minTruckFine=125;

int minMotorcycleFine=125;

现在假设国家通过了一项法律,小车罚款最低是50元。在全局范围内搜索125并替换为50。例如,如果你的代码有一个常量8125,那么它将通过全局搜索更改为8150,并替换可能不是你想要执行的操作。

假设你写了:

#define MINCARFINE 125

#define MINTRUCKFINE 125

#define MINCYCLEFINE 125

int minCarFine=MINCARFINE;

int minTruckFine=MINTRUCKFINE;

int minMotorcycleFine=MINCYCLEFINE;

第一件好事是神奇的数字从源代码中消失了。第二,代码实际上比以前更容易阅读。第三,如果真的改变了罚款,我们可以在程序中的一个地方,做出以下改变:

#define MINTRUCKFINE 50

并重新编译程序,使用小车罚款的所有实例都正确更改为新值。没有容易出错的搜索和替换。编译器为你完成所有工作。好东西。(www.xing528.com)

关于预处理器指令,你需要记住的另一件事是,任何#define都是源代码中的文本替换……没有其他内容。因此,所有#定义都是一个无类型的数据声明:它们在符号表中没有左值,也没有检查它们的数据类型。事实上,一旦预处理器完成传入,就不再存在任何#define。它们都被适当的常数所取代。因此,如果你做了一些傻事,比如:

#define VALUE 3.333

//some code

int myValue=VALUE;//Oops!

最后一条语句试图将一个浮点数放入一个int变量。显然,这可能不是程序员想要的,但是Arduino C编译器没有“抱怨”。编译器只是将myValue的值截断为3。

(1)初始化步骤。

回想一下,初始化步骤用于建立我们希望程序运行的环境。因为我们希望使用上一个程序中的两个LED,所以需要初始化控制LED的I/O引脚。我们还知道,我们需要生成一系列随机数,它们是从哪里来的?

每当你需要在程序中使用某个值或对象时,你应该做的第一件事就是确定是否有其他人已经为该对象创建了代码。首先要检查的是Arduino语言参考。果然,似乎有一个随机数生成器可用。在上面通过检查,我们可以看到一个名为randomSeed()的函数以及random()。进一步查阅资料告诉我们random()产生一系列伪随机数。

伪随机数?这意味着,尽管数列的分布是随机分布,每次使用random()时将获得相同的值。虽然这很好,在调试程序时,当我们完成程序测试时,这显然不是我们想要的。阅读randomSeed()文档,我们发现可以为随机数生成器“播种”,在开始时使用唯一值,然后使用random()为该值生成一组唯一的随机数种子。因此,在初始化步骤中使用randomSeed()似乎是合适的。

我们还需要一些工作变量来存储程序中的各种值。

(2)输入步骤。

在这一步中,我们需要收集解决手头任务所需的所有数据。程序使用的唯一数据是随机数生成器生成的随机数。

(3)处理步骤。

我们的程序需要检查随机数值并确定它是正面还是反面。随机数生成器生成的数值不是正面或反面。此外,还包括以下数据类型:

从随机数生成器返回的是一个长字符串。因为没有“正面”或“反面”数据类型,所以我们需要发明我们自己的。因为掷硬币有一个二元结果(即只有两种可能的状态:正面或反面),我们可以将随机数视为奇数或偶数结果。模2的任意数结果为1或0,具体取决于数字是奇数还是偶数。完美地,我们将处理奇数数字作为正,偶数作为反。

(4)输出步骤。

事实证明,输出(或显示)步骤是最复杂的步骤。这个过程并不困难,只是很忙。我们的目标是当数字为奇数(即正)时点亮一个LED,当数字为偶数(即反)时点亮另一个LED。因此,我们似乎应该将两个LED关闭一秒钟左右,然后根据生成的随机数打开相应的LED几秒钟。然后,我们应该一遍又一遍地重复这个过程。

(5)终止步骤。

因为我们没有做任何花哨的事情,而且程序被设计为永远运行(直到断电或出现故障),所以没有终止步骤(我们将在本章后面向你展示如何强制程序结束)。

现在,在查看清单4-2中的代码之前,先加载IDE并编写代码。代码如下:

代码清单4-2.The HeadsOrTails code

我们从一系列#定义和数据定义开始程序:

#define HEADIOPIN 13

#define TAILIOPIN 12

#define PAUSE 3000

#define REST 2000

int head=HEADIOPIN;

int tail=TAILIOPIN;

long randomNumber=0L;

注意:#定义去除程序中的许多幻数,使代码更具可读性。如果我们想改变投币之间的停顿,那么我们所需要做的就是改变#定义并重新编译程序。(当然,你还必须将编译后的代码再次上传到开发板。)

接下来,我们运行setup()代码:

这些语句只是建立程序中使用的I/O引脚及其模式。最后函数调用使用analogRead(0)返回的值作为随机数生成器的种子。你可以在以下位置联机阅读analogRead()函数的完整文档。

参考前面提到的URL或直接从IDE(帮助参考)获得的URL。然而,基本上函数读取引脚0上的电压,并将其映射到介于0和1023之间的值。不管那个值是多少,它都是用于为随机数生成器设定种子。完成后,我们准备好了输入和处理步骤,如loop()函数中所示。图4-5显示了使用相同方法运行的程序面包板,但使用了不同的开发板。

图4-5 2路LED闪烁例子

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈