arduino
Тайм-менеджмент
Поиск…
Синтаксис
unsigned long millis ()
unsigned long micros ()
void delay (беззнаковые длинные миллисекунды)
void delayMicroseconds (беззнаковые длинные микросекунды)
См. Заголовок elapsedMillis для конструкторов и операторов этого класса. Короче:
- elapsedMillis elapsedMillisObject; создает объект для отслеживания времени с момента его создания или с тех пор, как какой-либо другой явно установленный момент времени
- elapsedMillisObject = 0; сбросить время, отслеживаемое объектом, с «с тех пор»
- unsigned long deltaT = elapsedMillisObject; позволяет посмотреть время отслеживания
- elapsedMillisObject + = и - = работают как ожидалось
замечания
Блокировка против неблокирующего кода
Для очень простых эскизов может быть целесообразным писать код блокировки с использованием delay()
и delayMicroseconds()
. Когда ситуация усложняется, использование этих функций может иметь некоторые недостатки. Некоторые из них:
- Время от времени процессора: более сложным эскизам может понадобиться процессор для чего-то еще, ожидая окончания мигания светодиода.
- неожиданные задержки: когда
delay()
вызывается в подпрограммах, которые явно не называются, например, в библиотеках, которые вы включаете. - отсутствующие события, которые происходят во время задержки, и не обрабатываются обработчиком прерываний, например нажатием кнопок: кнопка может быть нажата на 100 мс, но это может быть затенено
delay(500)
.
Детали реализации
millis()
обычно полагается на аппаратный таймер, который работает со скоростью, которая намного выше 1 кГц. Когда millis()
, реализация возвращает некоторое значение, но вы не знаете, сколько лет оно на самом деле. Возможно, что «текущая» миллисекунда только началась или закончится сразу после этого вызова функции. Это означает, что при расчете разницы между двумя результатами от millis()
вы можете отключиться от нуля почти до нуля и почти миллисекунды. Используйте micros()
если требуется более высокая точность.
Взгляд в исходный код elapsedMillis
показывает, что он действительно использует millis()
внутри, чтобы сравнить два момента времени, поэтому он также страдает от этого эффекта. Опять же, есть альтернатива elapsedMicros
для более высокой точности, из той же библиотеки.
блокировка blinky с задержкой ()
Один из самых прямых способов сделать светодиод мигает: включите его, подождите немного, выключите его, подождите снова и повторите бесконечно:
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500
void setup()
{
pinMode(OUTPIN, OUTPUT); // sets the digital pin as output
}
void loop()
{
digitalWrite(OUTPIN, HIGH); // sets the pin on
delayMicroseconds(PERIOD); // pauses for 500 miliseconds
digitalWrite(OUTPIN, LOW); // sets the pin off
delayMicroseconds(PERIOD); // pauses for 500 milliseconds
// doing other time-consuming stuff here will skew the blinking
}
Тем не менее, ожидание, как это сделано в приведенном выше примере, отнимает процессорные циклы, потому что он просто сидит там в цикле, ожидая определенного момента времени, чтобы пройти мимо. Это то, что неблокирующие способы, используя millis()
или elapsedMillis
, делают лучше - в том смысле, что они не сжигают столько возможностей оборудования.
Неблокирующее blinky с библиотекой elapsedMillis (и классом)
Библиотека elapsedMillis предоставляет класс с тем же именем, который отслеживает время, прошедшее с момента его создания или установленное на определенное значение:
#include <elapsedMillis.h>
#define OUTPIN LED_BUILTIN
#define PERIOD 500
elapsedMillis ledTime;
bool ledState = false;
void setup()
{
// initialize the digital pin as an output.
pinMode(OUTPIN, OUTPUT);
}
void loop()
{
if (ledTime >= PERIOD)
{
ledState = !ledState;
digitalWrite(OUTPIN, ledState);
ledTime = 0;
}
// do other stuff here
}
Вы можете видеть в примере, что объекту ledTime
присваивается ноль при переключении светодиодного вывода. На первый взгляд это может показаться неудивительным, но это имеет эффект, если происходит много времени:
Рассмотрим ситуацию, когда сравнение между ledTime
и PERIOD
выполняется после 750 миллисекунд. Тогда установка ledTime
в ноль означает, что все последующие операции переключения будут 250 ms «late». Если, напротив, PERIOD
был ledTime
из ledTime
, светодиод увидит один короткий период, а затем продолжит мигать, как будто ничего не произошло.
Неблокирующий мигающий с миллисом ()
Это очень близко к примеру из документов arduino :
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500 // this is in milliseconds
int ledState = LOW;
// millis() returns an unsigned long so we'll use that to keep track of time
unsigned long lastTime = 0;
void setup() {
// set the digital pin as output:
pinMode(OUTPIN, OUTPUT);
}
void loop() {
unsigned long now = millis();
if (now - lastTime >= PERIOD) // this will be true every PERIOD milliseconds
{
lastTime = now;
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
}
digitalWrite(OUTPIN, ledState);
}
// now there's lots of time to do other stuff here
}
Использование millis()
таким образом - для операций времени неблокирующим способом - это то, что требуется довольно часто, поэтому для этого используйте библиотеку elapsedMillis
.
Измерьте, как долго что-то заняло, используя elapsedMillis и elapsedMicros
#include <elapsedMillis.h>
void setup() {
Serial.begin(115200);
elapsedMillis msTimer;
elapsedMicros usTimer;
long int dt = 500;
delay(dt);
long int us = usTimer;
long int ms = msTimer;
Serial.print("delay(");Serial.print(dt);Serial.println(") took");
Serial.print(us);Serial.println(" us, or");
Serial.print(ms);Serial.println(" ms");
}
void loop() {
}
В этом примере объект elapsedMillis
объект elapsedMicros
используются для измерения того, как долго что-то заняло, создав их непосредственно перед тем, как выполняется выражение, которое мы хотим выполнить, и получим их значения впоследствии. Они будут показывать несколько разные результаты, но результат в миллисекундах не будет отключен более чем на одну миллисекунду.
Более 1 задачи без задержки ()
Если вам нужно выполнить несколько заданий несколько раз в разные интервалы, используйте этот пример в качестве отправной точки:
unsigned long intervals[] = {250,2000}; //this defines the interval for each task in milliseconds
unsigned long last[] = {0,0}; //this records the last executed time for each task
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //set the built-it led pin as output
Serial.begin(115200); //initialize serial
}
void loop() {
unsigned long now = millis();
if(now-last[0]>=intervals[0]){ last[0]=now; firstTask(); }
if(now-last[1]>=intervals[1]){ last[1]=now; secondTask(); }
//do other things here
}
void firstTask(){
//let's toggle the built-in led
digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN)?0:1);
}
void secondTask(){
//say hello
Serial.println("hello from secondTask()");
}
Чтобы добавить еще одну задачу для выполнения каждые 15 секунд, увеличьте intervals
переменных и last
:
unsigned long intervals[] = {250,2000,15000};
unsigned long last[] = {0,0,0};
Затем добавьте оператор if
для выполнения новой задачи. В этом примере я назвал его thirdTask
.
if(now-last[2]>=intervals[2]){ last[2]=now; thirdTask(); }
Наконец, объявите функцию:
void thirdTask(){
//your code here
}