[英]Arduino 'time out' function using a millis timer
我编程的时间不长,我只想使用 Arduino UNO 板扩展电子工程。
我已经开始了一个基于 Steve Hoefer 在 Grathio 上的 Secret Knock Detecting Door Lock 的新项目,我想实现以下内容:
( http://grathio.com/2009/11/secret_knock_detecting_door_lock/ ) ( http://grathio.com/assets/secret_knock_detector.pde )
如果全局值等于 0 并且有效的敲击模式为真,则使用毫秒而不是延迟使黄色 LED 闪烁 4 次,以便它仍然可以“收听”。
如果在 6 秒内未听到另一个有效的爆震模式,它将超时并将全局重置为 0,以便它可以确认初始真实模式并闪烁黄色 LED。
如果在 6 秒内听到另一个有效的敲击模式,则增加一个计数器。
如果计数器等于 1,则等待另一个有效的敲击模式,如果在 6 秒内为真,则再次增加计数器并且不闪烁黄色 LED。
否则,超时并重置所有值。
依此类推,直到计数器大于或等于 4 时触发主 LED 阵列。
一旦成功敲击 4 次,我希望它触发我构建的主 LED 阵列。
该项目的灵感来自客机上使用的测试面板。 我见过他们很多,并认为这将是一个开始和了解时间的好地方。
有一些问题,因为我不希望每次都重置 millis() 并且我使用的是按钮而不是爆震检测脚本中的布尔值,所以我不会迷失在代码中。
我知道这不会在 50 秒后响应,这是一个初学者的错误,但如果我按住按钮证明了我所拥有的。 下面的代码在第一次 digitalRead HIGH 或 true boolean 之后也没有超时(我正在为此苦苦挣扎)。
int inPin = 2; // input pin switch
int outPin = 3; // output pin LED
long currentTime = 0; // counter
long nextTime = 0; // counter
long lastTime = 0; // counter
int patternCounter = 0; // build up
int globalValue = 0; // lock out
int breakIn = 0; // waste of time?
void setup()
{
pinMode(inPin, INPUT);
pinMode(outPin, OUTPUT);
Serial.begin(9600);
Serial.println("GO");
}
void loop(){
// boolean true, switch just for testing
if (digitalRead(inPin)==HIGH&&globalValue==0&&breakIn==0) {
Serial.println("CLEARED 1st");
delay (500); // flood protection
globalValue++;
breakIn++;
if (globalValue>0&&breakIn>0){
currentTime = millis(); // start a 'new' counter and 'listen'
if (currentTime<6000) { // less than
if (digitalRead(inPin)==HIGH) { // and true
Serial.println("CLEARED 2nd"); // cleared the stage
delay (500); // flood protection
patternCounter++;
} // if counter less
} // if true or high
if (currentTime>6000) {
Serial.println("TIMEOUT waiting 2nd"); // timed out
globalValue = 0;
patternCounter = 0;
breakIn = 0;
} // if more than
} // global master
}
// 3rd attempt
if (globalValue==1&&patternCounter==1){ // third round
nextTime = millis(); // start a 'new' counter and 'listen'
if (nextTime<6000) { // less than
if (digitalRead(inPin)==HIGH) { // and true
Serial.println("CLEARED 3rd");
delay (500); // flood protection
patternCounter++;
} // if counter less
} // if true or high
if (nextTime>6000) {
Serial.println("TIMEOUT waiting 3rd"); // timed out
globalValue = 0;
patternCounter = 0;
} // if more than
} // global master
// 4th attempt and latch
if (globalValue==1&&patternCounter==2){ // last round
lastTime = millis(); // start a 'new' counter and 'listen'
if (lastTime<6000) { // less than
if (digitalRead(inPin)==HIGH) { // and true
digitalWrite(outPin, HIGH); // LED on
Serial.println("CLEARED 4th ARRAY"); // cleared the stage
delay(500); // flood protection
} // true or high
} // counter
if (lastTime>6000) {
Serial.println("TIMEOUT waiting 4th"); // timed out
globalValue = 0;
patternCounter = 0;
} // if more than
} // global and alarm
} // loop end
这是当前的草图,我知道我使用的计数器几乎毫无意义。
任何帮助将不胜感激!
这是一个很大的问题,所以我可能不明白你的问题,但下面的代码是一个问题:
currentTime = millis(); // start a 'new' counter and 'listen'
if (currentTime<6000) { // less than
.....
}
您是否了解millis()
不可能“重置”,而这仅仅是一个返回程序启动以来毫秒数的函数? 只要程序正在运行,它就会继续增加(直到它翻转,但这是一个单独的问题)。 所以在上面的代码中,'currentTime' 只会非常非常短暂地小于 6000(6 秒),然后再也不会(除了毫秒重置的翻转条件)。
因此,使用millis()
跟踪时间的典型方式是,在setup
中,将其当前值存储到变量中并将超时时间值添加到其中:
// timeoutAmount is defined at head of program. Let's say it is 6000 (6 seconds)
nextUpdate = millis() + timeoutAmount;
然后在loop
中您可以进行检查:
if (millis() >= nextUpdate){
nextUpdate = millis() + timeoutAmount; // set up the next timeout period
// do whatever you want to do
}
使用delay()
时也要小心——它很容易用于流量控制,但对于任何有不止一件事的程序来说,它可能会导致混乱和难以解决问题。
哦 - 使用芯片上的内置计时器触发中断有更复杂的计时方法,但最好先掌握事情的窍门。
在你的帮助下,我想出了下面的草图。
草图几乎可以完成我想要的一切......
当它在第 1 次、第 2 次(inCount = 1)或第 3 次(inCount = 2)按钮按下后超时(T/O)时,我希望它恢复到开始,而不必再次按下它并循环 triggerFlash 两次.
要么在超时内实施另一个“等待和倾听”,以将其移动到第二个(inCount = 1)等,但我认为这可能会导致问题。
我知道闪光灯中使用了延迟,但将更改为millis(),我只是想获得基本功能和理解。
常量 int switchPin = 2; // 输入引脚的编号 const int BswitchPin = 4; // 输入引脚的编号 const int outPin = 3; const int thePin = 5;
long startTime; // the value returned from millis when the switch is pressed
long escapeTime; // the value returned from millis when in time out
long duration; // variable to store the duration
int inCount = 0;
int dupe = 0;
void setup()
{
pinMode(switchPin, INPUT);
pinMode(outPin, OUTPUT);
pinMode(thePin, OUTPUT);
digitalWrite(switchPin, HIGH); // turn on pull-up resistor
Serial.begin(9600);
Serial.println("Go");
digitalWrite(outPin, HIGH);
}
void loop()
{
if(inCount==0&&digitalRead(switchPin) == LOW)
{
// here if the switch is pressed
startTime = millis();
while(inCount==0&&digitalRead(switchPin) == LOW)
; // wait while the switch is still pressed
long duration = millis() - startTime;
if (duration<4000) {
Serial.println("1");
triggerFlash();
inCount++;
}
} // master 1
if (inCount>0&&inCount<4&&digitalRead(switchPin) == LOW)
{
// here if the switch is pressed
startTime = millis();
while(inCount>0&&inCount<4&&digitalRead(switchPin) == LOW)
; // wait while the switch is still pressed
long duration = millis() - startTime;
delay(500); // flood protection
if (duration>4000) { // script an escape here - formerly if (while will loop the condition)
Serial.println("T/O");
triggerFlash();
inCount = 0;
}
if (duration<4000) {
dupe = inCount + 1;
Serial.println(dupe);
inCount++;
}
}
if (inCount>=4) {
digitalWrite(thePin, HIGH);
}
} // loop
void triggerFlash() {
int i = 0;
for (i=0; i < 8; i++){
digitalWrite(outPin, LOW);
delay(100);
digitalWrite(outPin, HIGH);
delay(100);
}
}
任何想法都非常感谢! (用改进的计数进行了编辑)
上面的代码实际上是错误的。 请小心millis(),因为它们会在一段时间后翻转。 它只是长型。 因此,如果 millis+timeout 接近 max(long) 并且 millis() 将翻转并从零开始计数,即使实际发生超时,millis()>=nextupdate 也会为假。
正确的方法是:
unsigned long start = millis();
unsigned long timeout = MY_TIMEOUT_HERE;
...
//check if timeout occured
unisgned long now = millis();
unsigned long elapsed = now - start;
if(elapsed > timeout)
//do whatever you need to do when timeout occurs
我只是实现了 Arduino 库。 希望对您的问题有所帮助。 我让它像 javascript 中的 setTimeout 和 setInterval 一样工作。 你可以在这里下载, Github
这是我的代码示例您可以在Tinkercad中看到它的实际效果
/*
Author : Meng Inventor
Contact : https://www.facebook.com/MLabpage
15 July 2022
*/
#include "simple_scheduler.h"
#define LED1_PIN 7
#define LED2_PIN 6
#define LED3_PIN 5
#define GREEN_LED_PIN 4
Task_list job_queue;
void setup()
{
Serial.begin(115200);
pinMode(LED1_PIN, OUTPUT);
pinMode(LED2_PIN, OUTPUT);
pinMode(LED3_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
// setInterval will run repeatly for every given time period (ms)
job_queue.setInterval(blink_green, 1000);
job_queue.setInterval(led1_on, 2000);
}
unsigned long timer = millis();
void loop()
{
job_queue.update();
}
void led1_on(){
digitalWrite(LED1_PIN, HIGH);
job_queue.setTimeout(led1_off, 250); //setTimeout will run once after given time period (ms)
}
void led1_off(){
digitalWrite(LED1_PIN, LOW);
job_queue.setTimeout(led2_on, 250);//setTimeout will run once after given time period (ms)
}
void led2_on(){
digitalWrite(LED2_PIN, HIGH);
job_queue.setTimeout(led2_off, 250);//setTimeout will run once after given time period (ms)
}
void led2_off(){
digitalWrite(LED2_PIN, LOW);
job_queue.setTimeout(led3_on, 250);//setTimeout will run once after given time period (ms)
}
void led3_on(){
digitalWrite(LED3_PIN, HIGH);
job_queue.setTimeout(led3_off, 250);//setTimeout will run once after given time period (ms)
}
void led3_off(){
digitalWrite(LED3_PIN, LOW);
}
void blink_green() {
digitalWrite(GREEN_LED_PIN,HIGH);
job_queue.setTimeout(blink_green_off, 500);
}
void blink_green_off() {
digitalWrite(GREEN_LED_PIN,LOW);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.