Arduino -- 一个return引出的运行机制

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_36955622/article/details/94726384

自从接触Arduino以来,我们就被灌输了一个理念~
.ino 文件中:

  • setup函数中,做引脚模式初始化配置,串口波特率配置等;且该函数只在板子上电或复位之后运行一次。
  • loop函数,放置需要一直运行的操作,因为被告知该函数在setup函数之后会一直循环运行下去。

其他的全局变量、全局函数可以定义在setup函数、loop函数前面或是后面,即使是在setup函数、loop函数后面定义的,也不需要在开头做函数声明,不会导致编译出错可以正常调用。


直到一天突发奇想,loop函数一直在循环,那么我在loop函数中直接执行return,是不是就直接结束 “loop循环” 从而退出了自身进程?!!?
所以我简单改了Blink程序,添加return如下:

void setup()
{
	pinMode(13,OUTPUT);
}

void loop()
{
	digitalWrite(13,HIGH);
	delay(1000);
	digitalWrite(13,LOW);
	delay(1000);

	return;
	delay(2000);
}
测试结果推导:

1)程序执行一遍LED亮灭,遇到 return 后板子退出进程,处于“裸跑”状态;
2)程序连 return 后面的语句一同执行,并且一直循环,无视 return 存在;
3)程序一直循环LED亮1秒灭1秒操作,不执行 return 后的操作;

实际测试结果

结果证实第三种推导是正确的:程序一直循环执行亮1灭1的操作,return在程序中确实有退出loop函数的作用,但是loop函数又再次神奇的“运行”起来了。
由此推断loop函数不是一个自身循环的函数,应该是在某个地方一直被循环调用了,return都不能阻止这个程序的“循环”。

Arduino所用的编程语言是C\C++,正常来说应该能找到main.c文件已经main函数。通过在安装目录中的搜寻,确实找到了main.c的踪迹,路径是 Arduino\hardware\arduino\avr\cores\arduino,是个cpp文件。
在这里插入图片描述
main.cpp内容也比较简单,如下:

#include <Arduino.h>

// Declared weak in Arduino.h to allow user redefinitions.
int atexit(void (* /*func*/ )()) { return 0; }

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }

void setupUSB() __attribute__((weak));
void setupUSB() { }

int main(void)
{
	init();

	initVariant();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}
运行机制

在这里我们看到了熟悉的main函数,在main函数中,除了一些必要的初始化函数调用外,终于看到了setup函数及loop函数的踪影;setup函数在main函数中被调用一次,而不一样的是loop函数被放在for循环里面,这就能解释得通为何Arduino的运行机制中setup函数只运行一次,随后一直在运行loop了,而在loop函数中加入return之后,虽然是退出了当前的loop函数的执行,但是在for循环语句的作用下,又再次被循环调用;
因此,在loop函数中加入return的作用可以理解成相当于添加了continue的作用,在当前位置退出“loop循环”,直接直接开始下一次的“loop循环”,大概道理是一样的。
在for循环中,除了循环执行loop函数,还有一个串口事件的监控,因为跟loop函数同为一个循环体,所以会导致有时候的串口处理不够及时。

在下也有个猜想,搞清楚了Arduino的运行机制(实质上还是运行main函数),改了setup、loop的函数名以及在Arduino.h中的声明,或者自己新建函数在main函数中以同样的形式被调用,也许可以让自己的初始化函数、自己定义的循环函数运行起来。不过对于这套相对成熟的运行机制,这样的想法貌似没什么必要。


还有个彩蛋,在main.cpp所在的目录中,还能看到串口定义的相关文件,串口0 - 串口3的定义文件都在;甚至还是能看到wiring_analog文件和wiring_digital文件,我们熟悉的digitalRead、digitalWrite函数和analogRead、analogWrite、pinMode函数的定义都在这些文件中,算是另外的收获吧。
但是目前还没弄懂的是main.cpp是怎么能调用到setup函数和loop函数所在的.ino文件的,以及在.ino文件中定义的全局变量和全局函数,如果在setup和loop中没有被调用,是否会占用内存,有知道这些问题答案的读者可以在评论区说一说,互相学习,十分感谢。

猜你喜欢

转载自blog.csdn.net/qq_36955622/article/details/94726384