从一个简单的 arduino 程序说起:
/*BlinkTurns 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 seconddigitalWrite(led, LOW); // turn the LED off by making the voltage LOWdelay(1000); // wait for a second
}
这个程序的主体,提供了 setup() 和 loop() 二个函数。setup 函数做一些初始化的工作,在系统上电或复位后,此函数只会执行一次。 loop 函数会在 setup 之后一直循环运行。
在了解如何使用之后,其背后的机制是怎样的呢,那么,可以到安装目录下打开代码文件:C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino\main.cpp 代码如下:
#include <Arduino.h>int main(void)
{init();#if defined(USBCON)USBDevice.attach();
#endifsetup();for (;;) {loop();if (serialEventRun) serialEventRun();}return 0;
}
相信您看到了这段代码,就该知道 setup 和 loop 函数的前世今生了吧。我们所写的setup 和 loop 函数是这两个函数的定义。这两个函数在 main ( )主程序中已经预调用了。 在 loop 函数运行之后,我们还会看到 serialEventRun 的函数,此函数的功能是当串口有数据过来的时候,它可以调用Arduino的另一个函数 serialEvent。
打开 Arduino IDE , 选择菜单:文件 -> 示例 -> 04.Communication -> SerialEvent 具体看下面的代码:
/*Serial Event exampleWhen new serial data arrives, this sketch adds it to a String.When a newline is received, the loop prints the string andclears it.A good test for this is to try it with a GPS receiverthat sends out NMEA 0183 sentences.Created 9 May 2011by Tom IgoeThis example code is in the public domain.http://www.arduino.cc/en/Tutorial/SerialEvent*/String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is completevoid setup() {// initialize serial:Serial.begin(9600);// reserve 200 bytes for the inputString:inputString.reserve(200);
}void loop() {// print the string when a newline arrives:if (stringComplete) {Serial.println(inputString);// clear the string:inputString = "";stringComplete = false;}
}/*SerialEvent occurs whenever a new data comes in thehardware serial RX. This routine is run between eachtime loop() runs, so using delay inside loop can delayresponse. Multiple bytes of data may be available.*/
void serialEvent() {while (Serial.available()) {// get the new byte:char inChar = (char)Serial.read();// add it to the inputString:inputString += inChar;// if the incoming character is a newline, set a flag// so the main loop can do something about it:if (inChar == '\n') {stringComplete = true;}}
}
此代码的功能是:系统上电后,接收串口的输入数据并发送回去,类似 echo。系统的实现是通过在主循环判断全局变量 stringComplete 的状态来决定是否发送接收到的数据。而 stringComplete 的状态是在 serialEvent 这个函数里赋值的。根据 serialEvent 函数注释看,此函数的调用是在每次 loop 函数运行之后才执行的。再回到我们之前的代码:
for (;;) {loop();if (serialEventRun) serialEventRun();}
通过上面的代码,可以很明确的看出 serialEventRun 函数是在 loop 函数之后执行的。如果我们有多个串口,比如 2560 的板子提供了4个串口,那么 serialEventRun 函数又是如何处理的呢,我们打开代码文件:C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino\HardwareSerial.cpp 找到 serialEventRun 函数的实现,代码如下:
void serialEventRun(void)
{
#ifdef serialEvent_implementedif (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implementedif (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implementedif (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implementedif (Serial3.available()) serialEvent3();
#endif
}
serialEventRun 的函数体中是依次的调用 serialEvent() serialEvent1() serialEvent2() serialEvent3() 函数的。如果您的应用需要通过多个串口读写数据,那么在使用 serialEvent 函数的过程中,就要考虑接受的数据长度以及函数的处理时间,否则极有可能会导致其它串口的接收缓冲区满而影响应用。