本篇为译文,略有删减,原文链接见文末。推荐理由:平时关于Arduino函数功能和各种模块使用的教程很多,却鲜有关于Arduino编程方法和思路的教程。而本篇文章从最基本的示例切入,深入浅出地介绍了Arduino的多任务、状态机、面向对象以及定时器、中断等概念,非常适合提升和开阔初学者Arduino编程的思维方式。
当Arduino初学者掌握了基本的点亮LED,简单的一些传感器和舵机扫动,下一步就要面对的是更大更复杂的项目。这些项目需要初学者学会“东拼西凑”,即把简单的代码片段拼成一个能用的整体。很多初学者最初的苦恼就是,明明很多代码片段自己能跑起来,为什么拼在一起就无法运行了?
Arduino其实是一个没有操作系统(OS)的单核处理器系统,每次只能跑一个程序。不像PC或者树莓派那样,Arduino没有办法同时运行多个程序,但这并不意味着在Arduino上无法处理多任务。我们只需要使用一些特殊的方法。因为Arduino没有操作系统,我们需要手动构建一些框架。
避免使用delay()
使用延时函数delay()可能是很多人第一个学会的Arduino函数。使用delay()控制时间虽然简单粗暴,但它也是你添加更多功能的“拦路虎”。delay()函数的问题是它会霸占整个处理器。
在你使用延时delay()相应的时间段里,Arduino不会对任何输入有反应。你不能处理数据,也不能修改任何输出。延时函数100%地霸占了处理器。所以如果你的代码片段里用了delay(),这段时间里你什么都做不了。比如经典的Blink示例代码:
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
This example code is in the public domain.
*/
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
在舵机扫臂(Sweep)示例中,同样使用了delay()函数来控制Sweep的速度。如果把Blink和Sweep两个示例代码直接接起来,我们可以发现LED的闪动和舵机扫臂并不是同时进行的。
#include
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup()
{
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop()
{
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
for(pos = 0; pos <= 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for(pos = 180; pos>=0; pos-=1) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}
那么不用delay()延时函数,如何控制程序时间呢?
使用millis()函数控时
控制程序执行时间的一个最简单的技巧就是制定时间规划并时刻监控着时间。尽量避免使用delay()函数,需要我们自己时刻检查系统时间,了解执行不同任务的时间点,同时保证其他任务也能被执行。一个很简单的例子就是Arduino IDE自带的BlinkWithoutDelay示例。
代码和连接图如下:
/* Blink without Delay
Turns on and off a light emitting diode(LED) connected to a digital
pin, without using the delay() function. This means that other code
can run at the same time without being interrupted by the LED code.
The circuit:
* LED attached from pin 13 to ground.
* Note: on most Arduinos, there is already an LED on the board
that's attached to pin 13, so no hardware is needed for this example.
created 2005
by David A. Mellis
modified 8 Feb 2010
by Paul Stoffregen
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
*/
// constants won't change. Used here to
// set pin numbers:
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
}
void loop()</