当你想让代码在一个不变的时间间隔后执行时,你可以很简易的用delay()函数来实现。
但是,这只是让程序暂停一个特定的时间段。特别是如果你需要同时让处理器做其他处理时,这么做同时也是一种浪费。
回顾:
先让我们来看看原来的程序吧:
void setup(){
pinMode(9,OUTPUT);//选取9号引脚接电调信号线
/*油门行程校准(i<=1000时,整个循环用时3-4秒)*/
//该循环运行时会伴有“哔-哔-”油门最高点确认音
for(int i=0;i<=1000;i++){
digitalWrite(9,HIGH);
delayMicroseconds(2000);//高电平持续2000微秒(油门最高点,脉宽为2毫秒)
digitalWrite(9,LOW);
delayMicroseconds(18000);
}
//该循环运行时会伴有N声短鸣声(表示锂电池节数)和“哔-”油门最低点确认音
for(int i=0;i<=1000;i++){
digitalWrite(9,HIGH);
delayMicroseconds(1000);//高电平持续1000微秒(油门最低点,脉宽为1毫秒)
digitalWrite(9,LOW);
delayMicroseconds(19000);
}
/*现在可以加大高电平持续时间,即加大油门,实现电机的启动 */
//该循环运行的时间即电机低速转动的时间,进一步证明了i<=1000时,整个循环用时3-4秒
for(int i=0;i<=1000;i++){
digitalWrite(9,HIGH);
delayMicroseconds(1100);//油门1100
digitalWrite(9,LOW);
delayMicroseconds(18900);
}
}
//loop()函数使油门保持在1600
void loop(){
for(int i=0;i<=1000;i++){
digitalWrite(9,HIGH);
delayMicroseconds(1600);
digitalWrite(9,LOW);
delayMicroseconds(18400);
}
}
之前我们制作的水下机器人的简单工作思路是利用控制高低电平持续时间产生PWM信号,控制推进器运动。
但是后来我们发现这个方法虽然可以控制推进器运动与调速,但是推进器程序运行过程中会占用整个程序大部分的时间(因为我们是用delay()函数来实现的,会让程序暂停在一个特定的时间段),导致其他程序未按预期执行。
因此我们计划利用多线程(严格来说arduino是类多线程)来实现多段程序的同时处理,但是网上的多线程对于小白来说不太友好,最简单的多线程库SCoop也不知因什么原因无法使用(很多小白都出现这种情况)。
上面我们也说了,我们是通过使用delay()函数控制高低电平持续时间产生PWM信号,控制推进器运动。
既然delay()函数在使用过程中,它会霸占整个处理器,那么可不可以不用delay()延时函数,控制程序时间呢?
诶,你还别说,还真有!
这里就要引入一个状态机的概念了——State Machine
简单来说就是用变量记住了当前状态和前一次的状态。在每次loop时,程序通过millis()获取当前时间戳来判断是否需要改变的状态。
还不理解嘛?可以看看这篇文章——arduino定时器控制舵机_Arduino如何多任务(上)
这样一来我们的思路就清晰了:可以设置previousMillis变量和currentMillis变量,利用millis()函数获取当前的时间戳,并记录好当前的状态,每经过一段时间就改变高低电平的状态,达到控制pwm的目的。如下:
unsigned long previousMillis = 0; //设置PreviousMillis用于与CurrentMillis比较,计时总个周期时间
//前面初始化过于简单因此省略
void loop() {
unsigned long currentMillis = millis();
int dif2 = currentMillis - previousMillis;
//Serial.print("此时差:");
//Serial.println(dif2);
if (dif2 >= LOW_TIME) {
previousMillis = currentMillis;
Serial.println("执行了转换高电平程序");
ESC_State = HIGH;
}
......//执行了转换高电平程序同上
}
完整程序链接:PWM_millis.ino
当然,除此之外,还有一种思路,就是不在程序端利用延迟产生PWM信号,而是通过FlexiTimer2库(定时器中断),利用板子里的定时器来让中断定时发生,可以精确控制时间,产生PWM信号。
在写程序之前,需要先在Arduino开发环境中导入一个库,即FlexiTimer2(网上还有一些其他的定时器的库,例如MsTimer2库),这个库可以在官网上下载。然后直接打开“项目—加载库—添加一个.ZIP库”。
这里需要特别说明的是,每一类型的Arduino开发板的中断引脚不同,Mega 2560开发板有2,3,21,20,19,18共六个中断引脚,而我们使用的arduino UNO就只有2,3两个中断引脚。
关于FlexiTimer2库这里不做详细讲解,详细请看官方文档:
简单来说:
FlexiTimer2::set(unsigned long ms, void (*f)()) 设置定时器中断,(时长,中断函数);
FlexiTimer2::start() 开始计时;
FlexiTimer2::stop() 结束。
具体如何实现大家可以自己后续再思考思考。
实际上想产生PWM的方法有很多,关键在于自己思考,这里由于时间和精力的原因不再过多阐述。