ARDUINO задержка без delay помогите.

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
Здравствуйте. Может кому то это покажется смешно, но не мне. Ну не как не могу понять как и где правильно писать в коде эти задержки. Подскажите в чем мои ошибки, почему в данном коде светодиод загорается при достижении температуры 24 градуса мгновенно, а не с задержкой в 2 секунды.
C++:
uint32_t btnTimer = 0;
if (temp >= 24 && millis() - btnTimer > 2000)
{
    digitalWrite(13, HIGH);
    btnTimer = millis();
 }
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,282
945
58
Марий-Эл
Потому что первый раз Вы инициализируете btnTimer нулём.
А millis() уже мог нащёлкать очень большую цифру. Например 45000, а 45000-0 больше чем 2000
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
Как же правильно инициализировать? Даже если убрать ноль, по моему по умолчанию все одно будет ноль.
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
При такой инициализации светодиод вообще перестал зажигаться, да оно и есть как то странно, мы присваиваем btnTimer, millis() и потом от millis() вычитаем btnTimer которой и была присвоена millis() . Я не берусь это утверждать , я всего лишь ученик. Потому и пытаюсь разобраться.
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,725
482
мы присваиваем btnTimer, millis(
Правильно, тем самым фиксируем значение millis(). А сама millis () не стоит на месте, а инкрементируется. Только присвоение нужно делать где-нибудь раньше, скажем в сетапе, и переменную обьявить глобальной. А вообще, что Вам мешает почитать или посмотреть уроки Гайвера вместо того, чтобы задавать глупые вопросы?
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
При объявлении в сетап , зажигается мгновенно, без задержки. Перечитано и пересмотрено много, да вот только все основано на том что бы поморгать светодиодом, а как применить задержку в практике не поморгать, а конкретно сделать задержку, как по таймеру например, не могу догнать. Данный код на таймерах работает исключительно, но ведь можно как то и на миллис.
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
Только если он не 100500 строк.
Эдуард код имеет 175 строк, это мой первая в жизни код , над которым борюсь уже не один месяц. Некий такой БК для авто. Код сейчас сформирую , выложу, только не пинайте со всех сторон, не уверен что все там прописано правильно, но как в сказке " я же только учусь"

C++:
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <SimpleTimer.h>
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
#define FLOWSENSORPIN 2 // пин для датчика расхода

volatile uint16_t pulses = 0 ; // считает сколько импульсов
volatile uint8_t lastflowpinstate; // отслеживает состояние пина FLOWSENSORPIN
float flowMilliLitres ;    // поток.
int liters = 0 ;
uint16_t n = 0;
int address = 0;

volatile unsigned long timerPrew = 0;
volatile bool countOn = 0;

int analoginput = 0 ;
float volt ;
float vout ;

SimpleTimer timer;

byte gradus[8] = {0b00110, 0b01001, 0b01001, 0b00110, 0b00000, 0b00000, 0b00000, 0b00000};   // символ градуса
byte ulitsa[8] = {0b00100, 0b01010, 0b10001, 0b11111, 0b10001, 0b10001, 0b11111, 0b00000};   // символ улица
byte dvigatel[8] = {0b01110, 0b00100, 0b00110, 0b10101, 0b11101, 0b10101, 0b00110, 0b00000}; // символ двигатель

#define ONE_WIRE_BUS 6 // линия данных подключена к цифровому выводу 15 Arduino

OneWire oneWire(ONE_WIRE_BUS);      // настройка объекта oneWire для связи с любым устройством OneWirе
DallasTemperature sensors(&oneWire);// передать ссылку на oneWire библиотеке DallasTemperature

// адреса двух датчиков DS18B20
uint8_t sensor1[8] = { 0x28, 0x86, 0x49, 0x16, 0xA8, 0x01, 0x3C, 0x67 }; // адрес 1го датчика
uint8_t sensor2[8] = { 0x28, 0xFF, 0xA6, 0xBF, 0x72, 0x15, 0x03, 0xBD }; // адрес 2го датчика

void button() //функция, вызываемая нажатием кнопки (прерыванием на 2-м пине)
{
  if ((millis() - timerPrew) >= 200) //счетчик на 200 мс для борьбы с дребезгом
  {
    countOn = 0;
    timerPrew = millis();
  }
  if (countOn == 0) //"флажок" для разрешения подсчета
  {
    EEPROM.write(address, 0);                      // пишим в ЭН нули.
    (address, liters = 0 );       // по адресу присваеваем значение ноль.
    countOn = 1;    //запрет подсчета после первого срабатывания кнопки
  }
}
void pulsesi () {
  pulses ++;
  if (pulses == 450 ) {
    pulses = 0;
    liters ++;
  }
}
// Прерывание вызывается один раз в миллисекунду, ищет любые импульсы от датчика!
ISR(TIMER2_COMPA_vect) {
  uint8_t x = digitalRead(FLOWSENSORPIN);
  if (x == lastflowpinstate) {
    return; // nothing changed!
  }
  if (x == HIGH) {
    pulsesi () ;
  }
  lastflowpinstate = x;
}

void useInterrupt(boolean v) {
  if (v) {
    OCR2A = 0xAF;
    TIMSK2 |= _BV(OCIE2A);
  }
  else { // не вызывать функцию прерывания больше
    TIMSK2 &= ~_BV(OCIE2A);
  }
}

void setup() {
  pinMode(5, OUTPUT);
  pinMode(13, OUTPUT);
  sensors.begin();            // инициализация библиотеки
  lcd.createChar(0, gradus);  // Функция создает пользовательский символ lcd.createChar(num, data)lcd: переменная типа LiquidCrystal
  lcd.createChar(1, ulitsa);  // num: номер пользовательского символа, который необходимо создать (от 0 до 7)
  lcd.createChar(2, dvigatel);// data: данные о пикселах пользовательского символа

  lcd.begin(16, 2);
  lcd.clear();
  EEPROM.get(address, liters);
  lcd.setCursor (0, 1);
  lcd.print (liters);
  delay(500);
  pinMode(FLOWSENSORPIN, INPUT);
  digitalWrite(FLOWSENSORPIN, HIGH);
  lastflowpinstate = digitalRead(FLOWSENSORPIN);
  pinMode(3, INPUT);// pin кнопки на вход.
  attachInterrupt(1, button,  RISING); //прерывание по LOW - HIGH

  useInterrupt(true);
}
void printTemperature(DeviceAddress deviceAddress) //функция получения температуры с датчиков
{
  float tempC = sensors.getTempC(deviceAddress);   // переменная для хранения температуры
  lcd.print(tempC, 1);                             //1 выдает десятые, без 1 сотые
  lcd.write(byte(0));                              // выводит определенный пользовательский символ
  lcd.print("C");
}
//Функция паузы
void Led_ON() {
  digitalWrite(13, HIGH); // ваше действие
  digitalWrite(5, LOW);//включение/выключение светодиода
}
void Led_OFF() {
  digitalWrite(13, LOW);  //выключение светодиода
  digitalWrite(5, HIGH); //включение
}
void Led_ON1() {
  digitalWrite(4, HIGH); //включение светодиода
}
void Led_OFF1() {
  digitalWrite(4, LOW);  //выключение светодиода
}

void loop() {
  timer.run();
  sensors.requestTemperatures();// запускаем измерение температуры на всех датчиках
  lcd.setCursor(0, 0);          // выставляем курсор
  lcd.write(byte(1));           // выводит определенный пользовательский символ
  printTemperature(sensor1);    // выводим тепературу 1го датчика
  lcd.setCursor(8, 0);
  lcd.write(byte(2));
  printTemperature(sensor2);    // выводим тепературу 2го датчика

  EEPROM.put(address, liters);

  cli();
  n = pulses;
  sei();
  flowMilliLitres = n;
  flowMilliLitres /= 7.5 ;
  flowMilliLitres /= 60.0;

  //vout = analogRead(analoginput);      //читаем значение входа А0.
  //volt = vout * 5.0 / 1024.0 / 0.194;  // вычисляем результат напряжения.

  lcd.setCursor(4, 1);
  lcd.print(flowMilliLitres); lcd.print("mL");
  lcd.setCursor(0, 1);
  lcd.print(liters); lcd.print("L");
  lcd.setCursor (10, 1);
  lcd.print (volt);  lcd.print ("V");                    // выводим результат измерения напряжения.

  float temp = (sensors.getTempCByIndex(1));

  if (temp >= 24) {
    timer.setTimeout(2000, Led_ON);
  }
  else
  {
    (temp <= 24);
    timer.setTimeout(2000, Led_OFF);
  }

  if (temp >= 50)// перегрев
  {
    timer.setTimeout(2000, Led_ON1);
  }
  else
  {
    (temp <= 50);
    timer.setTimeout(2000, Led_OFF1);
  }
}
 
Изменено:

PiratFox

★★★★★✩✩
13 Фев 2020
1,725
482
C++:
uint32_t btnTimer = 0;
if ((temp >= 24) && ((millis() - btnTimer) > 2000)) // !!! Скобки надо ставить !!!
{
    digitalWrite(13, HIGH);
    btnTimer = millis();
 }
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
Только здесь через таймер и библиотеку, а я пытаюсь найти другой метод, может конечно и зря.

@PiratFox,
Не помогло.
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
А как вы поняли
Именно так, температуру я вижу на LCD16х2, а контроль по подключенным светодиодам. пальцем грею датчик ds18b20, по экрану смотрю за температурой и наблюдаю светодиод. Но это так временно, пока эксперименты, потом там будут другие задачи.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,191
1,281
Москва
@Sascha.,
btnTimer вот эту переменную надо делать равной миллис на момент достижения 24 градусов, т.е. в проверке температуры.
Причем объявить ее надо с присвоением ей нуля , а делать ее равной миллис надо только если она до этого была нулем. И не забыть сделать обратное действие. когда температура снизилась меньше 24 сделать ее равной нулю. Арбайтен!
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
А так будет работать?
C++:
uint32_t btnTimer = 0;
boolean flag=false;
if ((temp >= 24) && !flag) {
    flag=true;
    btnTimer = millis();
 }
if (flag && ((millis()-btnTimer)>2000)) {
    digitalWrite(13,HIGH);
}
 

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
@Старик Похабыч,
Я правильно Вас понял.
В сетап
uint32_t btnTimer = 0;
В проверке
if (temp >= 24) { uint32_t btnTimer = millis();
((millis() - btnTimer) > 2000);
digitalWrite(13, HIGH);
btnTimer = millis();
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,191
1,281
Москва
Неть!
В сетап
uint32_t btnTimer = 0;
и эта переменная будет видна только в setup. Делайте ее глобальной

В проверке
if (temp >= 24) { uint32_t btnTimer = millis();
1) Второй раз объявляете переменную, которая должна УЖЕ быть
2) И я же сказал, надо менять значение если btnTimer равен нулю! А где проверка ? нет ее. Тогда при КАЖДОМ моменте при t больше 24 будет новое значение переменной и как вывод никогда не загорится диод. Только когда температура упадет ниже 24 на более чем 2 секунды.

((millis() - btnTimer) > 2000);
digitalWrite(13, HIGH);
btnTimer = millis();
}
А тут зачем btnTimer = millis(); ? что бы мигало ?

Или делайте проще . Глобальная переменная btnTimer получает значения всегда, когда температура ниже 24.
Тогда как только разница будет в 2 сек загорится диод. Как только опуститься - сразу потухнет
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,191
1,281
Москва
@Sascha.,
Для начала так:
C++:
// вот тут переменная будет глобальной и видна будет и в setup и в loop. при этом ее значение будет сохраняться все время работы мк
uint32_t btnTimer = 0;
void setup()
{
...
}

void loop()

{
...
// все ! запомнили нужное время!
if (temp >= 24)
{
if (btnTimer == 0)btnTimer = millis();
}

if  ((millis() - btnTimer) > 2000);   digitalWrite(13, HIGH);
...
}
А потом посмотрите про обнуление

Но что бы не было обнуления можно сделать так: (второй совет):
C++:
void loop()
{
...
if (temp <24) btnTimer = millis();
if  ((millis() - btnTimer) > 2000);   digitalWrite(13, HIGH);
..
}
 
Изменено:

Sascha.

✩✩✩✩✩✩✩
15 Авг 2020
39
2
void setup() // вот тут переменная будет глобальной и видна будет и в setup и в loop. при этом ее значение будет сохраняться все время работы мк uint32_t btnTimer = 0;
Я конечно извиняюсь, но глобально это по моему до сетап.