В этой программе мы разберем замену функции delay. Функцию delay(m) уместно использовать в простых программах, выполняющих одну задачу. Точнее в тех программах, у которых все ресурсы контроллера отданы выполнению одной задаче. Если мы поставим значительное время задержки “m = 1000”, к примеру, то наша программа будет находиться в ожидании большую часть времени. Мы же напишем таймер, позволяющий выполнять наш код только через заданные интервалы времени. Обратите внимание, работа программы не останавливается, т.к. отсутствует функция delay(), при этом цикл loop работает и мы можем использовать свободное время процессора выполняя другие задачи.
Кстати, отказаться от задержек нельзя. К примеру: слишком частый опрос датчика температуры DS18B20 приводит к его локальному разогреву и, как следствие, выдаче неверных значений температуры.
Имеет ли смысл использовать массив unsigned long arTimers[]? Попробуйте найти ответ сами, на занятии мы это разберём.
#define RED 9 //выбрали пины
#define GREEN 10
#define BLUE 11
#define LEVEL_A 20 //определяем уровни переходов
#define LEVEL_B 100
#define LEVEL_C 120
#define LEVEL_D 160
#define LEVEL_MAX 180 //значение этой переменной может зависит от
// напряжения питания и датчика
const int pollingDelay = 100; //задержка таймера
int water = 0;
unsigned long arTimers[]={0, 0};
bool nStat=1; //состояние перехода
unsigned int dT=0; //интервал времени для таймера;
int arPins[] = {RED, GREEN, BLUE};
int dL = 0; //отклонение уровня от фиксированных точек A,B или C,D. Используем для расчета скважности ШИМ.
//******************************
void setup() {
// инициализация портов. Номера подключаемых пинов заданы в массиве, а определены через define
for (int i = 0; i < sizeof(arPins); i++) {
pinMode(arPins[i], OUTPUT);
}
pinMode(A0, INPUT); // к входу A0 подключим датчик уровня
Serial.begin(9600); // подключаем монитор порта для отладки
}
//***************************** установка времени задержки таймера
int setTimer(int dt, int nTimer){ //dt - длительность задержки, nTimer - номер таймера
if(arTimers[nTimer] == 0){ //если таймер не включен
arTimers[nTimer] = millis() + dt; //задаем значение - сумма текущего времени
} //и заданного времни ожидания
}
//*****************************
bool getTimer(int nTimer){
unsigned long nMillis = millis();
if(arTimers[nTimer] <= nMillis){ //проверяем состояние таймера
arTimers[nTimer] = 0; //если время истекло, сбрасываем заданное значение, освобождаем таймер.
}
return arTimers[nTimer] != 0; //возвращаем логическое состояние таймера, если включен - true
}
//*****************************
void loop() {
//в начале цикла получаем значение уровня воды
if(!getTimer(0)){
water = analogRead(A0); // значение переменной "water" находится в интервале от 0 до 1023
if (water < LEVEL_B) { //определяем в каком режиме должны находиться режимы светодиодов
if(water < LEVEL_A){ //в зависимости от того, в какой интервал попадает значение переменной water
digitalWrite(RED,LOW); //интервал от 0 до A
digitalWrite(GREEN,LOW);//выключили светодиод
digitalWrite(BLUE, HIGH);//включили светодиод
} else {
digitalWrite(RED,LOW); //интервал от A до B
dL = map(water, LEVEL_A, LEVEL_B, 1, 256);
analogWrite(GREEN, dL); //включили светодиод в режиме ШИМ
dL = 256 - dL;
analogWrite(BLUE, dL); //включили светодиод в режиме ШИМ
}
} else { //больше уровня B
digitalWrite(BLUE, LOW); //выключили синий светодиод, см. график
if(water < LEVEL_C){ // уровень между B и C
digitalWrite(RED,LOW); //выключили красный светодиод
digitalWrite(GREEN,HIGH); //включили зелёный светодиод
} else {
if(water < LEVEL_D){ // уровень между С и D
dL = map(water - LEVEL_C, LEVEL_C, LEVEL_D, 1, 256);
analogWrite(RED, dL);//включили красный светодиод в режиме ШИМ
dL = 256 - dL;
analogWrite(GREEN, dL);//включили зелёный светодиод в режиме ШИМ
} else { //уровень больше D
digitalWrite(RED,HIGH); //включили красный светодиод
digitalWrite(GREEN,LOW);//выключили зелёный светодиод
}
}
}
setTimer(pollingDelay, 0);
Serial.println(water); // выводим значение датчика на монитор
}
}