Answers:
首先,让我们看一些可能出问题的示例。
void setup() {
int status;
pinMode(13, OUTPUT);
digitalWrite(13, status);
}
正如Edgar Bonet在评论中所指出的那样,status
C ++编译器并未隐式初始化像上面代码中所示的局部变量。因此,以上代码的结果是不确定的。为避免这种情况,请确保始终将值分配给局部变量。
全局变量和静态变量有些不同:
保证全局和静态变量都可以通过C标准初始化为0。
来源: AVR Libc参考手册-常见问题-我不应该初始化所有变量吗?
这意味着您不必担心在代码中将它们初始化为0。实际上,您应该避免使用它,因为初始化可能会浪费内存。仅将它们初始化为非0的值。
int array[10];
int v = array[100];
array[-100] = 10;
这里的第一个问题是,您不知道将为v分配什么,但更糟糕的是,您不知道对分配给-100的位置搞砸了什么array
。
void doSomething( void ) {
for (int i = 0; i < 1000; i++);
}
void setup ()
{
void (*funcPtr)( void );
funcPtr = &doSomething;
funcPtr(); // calls doSomething();
funcPtr = NULL;
funcPtr(); // undefined behavior
}
的第一个呼叫funcPtr()
实际上将是的呼叫doSomething()
。像第二个这样的调用可能导致不确定的行为。
好吧,例如,您可能会用完RAM。还有什么。无论如何,我认为您的程序将继续运行,可能不是您希望的那样。
在计算机系统中,通常在各个级别处理此类问题:
Arduino仅对编译器提供有限的保护,可能没有其他保护。好消息是它们不是多任务的,所以唯一受影响的程序就是您的程序。无论如何,这些错误中的任何一个都将导致错误的行为。
这些假设是我上面提到的所有问题,都是运行时问题。
如果程序中出现运行时错误,该怎么办?
该程序将继续,发生的情况将取决于运行时错误的副作用。调用null函数指针可能会使程序跳转到未知位置。
程序的执行会停止吗?
不,它会继续前进,好像没有什么特别的事情发生,可能是您未曾打算做的。它可能会重置或行为异常。它可能会将某些输入变成输出,并烧掉一两个传感器(但这极不可能)。
有什么办法可以让Arduino告诉我错误是什么?
我不这么认为。正如我之前所说,保护机制并不存在。语言没有运行时支持,没有操作系统,也没有硬件检查越界内存访问(引导加载程序也不算在内)。您只需要对程序小心,并可以设置自己的安全网。
缺乏保护的原因可能是因为Arduino控制器价格太便宜,内存太少并且不应运行太重要的东西(是的,AVR似乎在某处声明您不使用通常使用的MCU。生命支持系统中的Arduino)。
有一种机制可以使MCU摆脱不稳定状态,它是看门狗定时器。如果您要实现一些将在循环中重复运行的代码,而这些代码的运行时间不会超过某个固定时间,则可以将此时间设置为看门狗周期并启用计时器。
然后,您必须在循环中重复重置计时器。如果您的代码冻结在永远不会结束的某些条件循环中,则看门狗将计数为零,并最终复位MCU。
这样,您将丢失数据,但是如果以中断模式运行AVR WDT,则可以在复位MCU之前存储一些数据。
因此,看门狗定时器可以保护您的代码免于意外的无尽循环。
您需要一个类似这样的硬件调试器。但是通常您会看到程序没有按预期的方式运行,因此必须查看代码的该部分以识别问题。
一种常见/快速/简便的方法是添加打印语句以打印出变量或任何值,这样您就可以知道程序到了代码中的正确位置。这将帮助您进一步隔离问题。
我相信VisualMicro内置了一些调试功能。