ARDUINO Подскажите новичку с millis

JamToJum

✩✩✩✩✩✩✩
29 Окт 2020
7
0
Все привет. Вот сижу я уже второй день, голова сохнет. Никак не пойму этот millis. Пересмотрел кучу роликов в Ютубе, читал заметки ардуинщика, что только не делал не получается мне как-то обмудрить ситуацию.
Дело вот какое: есть два реле, одно реле пускает напряжение на аккумулятор 12 вольт 7 секунд, отключается и ждёт полсекунды, потом включается второе реле - на нем стоит лампа накаливания, которая разряжает аккумулятор 2 секунды и тоже отключается на по секунды. И так нужно делать по кругу, пока на аккумуляторе не появиться 12.5 Вольт.

Есть три светодиода - индикация режимов. Все это управляется одной кнопкой.
Вот, собственно, код:
C++:
butt1.tick();
    
  if (butt1.isStep(0)) {
    digitalWrite (LED_1, HIGH);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, LOW);
  }

  if (butt1.isStep(1)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, HIGH);
    digitalWrite (LED_3, LOW);
    while (voltage < 12.5) {
            digitalWrite(RELAY_CHARGE, HIGH);
            delay (7000);
            digitalWrite(RELAY_CHARGE, LOW);
            delay (500);
            digitalWrite(RELAY_DISCHARGE, HIGH);
            delay (2000);
            digitalWrite(RELAY_DISCHARGE, LOW);
            delay (500);
        }       
  }
    
  if (butt1.isStep(2)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, HIGH);
  }

  if (butt1.isStep(3)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, LOW);
  }
}
Этот режим должен быть зациклен в while, до тех пор, пока из аналог. пина не поступит 12.5 вольт , а после остановить работу этого режима.

Проблема в том что delay мне не дают переключать режимы работы. Я не прошу переписать код, я прошу помочь разобраться с милисами.

Подскажите как сделать также, но только на миллис
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
631
150
А в чем конкретно-то проблема с millis() ? Ведь если читал, смотрел про неё, то почему не используешь? И не delay() тебе мешает. Вот как по твоему ардуинка в цикле while (voltage < 12,5) узнает, что уже 12,5 вольт или даже больше? В таком виде она будет крутить этот цикл бесконечно.
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Всё же разобраться или написать код?
В Вашем случае надо просто осознать что такое milis() и как вообще всё должно работать. Ну допустим вместо делай вы сделаете милис, тогда вы столкнётесь с другими граблями, а может и не одни грабли. У Вас в корне неправильный подход... Начнём с того, что необходимо кнопкой переключать переменную (флаг), и уже этот флаг отрабатывать в цикле loop.
Я бы сделал как о так
C++:
butt1.tick();
 
  if (butt1.isStep(0)) {
    digitalWrite (LED_1, HIGH);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, LOW);
    flag_start = false;        //Отключаем заряд-разряд при других режимах

  }

  if (butt1.isStep(1)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, HIGH);
    digitalWrite (LED_3, LOW);
    flag_start = true;             //Устанавливаем флаг запуска заряд-разряд
    time_start = millis();        //Запоминаем время старта
//    while (voltage < 12.5) {
//            digitalWrite(RELAY_CHARGE, HIGH);
//            delay (7000);
//            digitalWrite(RELAY_CHARGE, LOW);
//            delay (500);
//            digitalWrite(RELAY_DISCHARGE, HIGH);
//            delay (2000);
//            digitalWrite(RELAY_DISCHARGE, LOW);
//            delay (500);
//        }    
  }
 
  if (butt1.isStep(2)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, HIGH);
    flag_start = false;
  }

  if (butt1.isStep(3)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, LOW);
    flag_start = false;
  }

  if (flag_start){
    if (millis()-time_start < 7000){
        digitalWrite(RELAY_CHARGE, HIGH);
    } elseif (millis()-time_start < 7500) {
        digitalWrite(RELAY_CHARGE, LOW);
    } elseif (millis()-time_start < 9500) {
        digitalWrite(RELAY_DISCHARGE, HIGH);
    } elseif (millis()-time_start < 10000) {
        digitalWrite(RELAY_DISCHARGE, LOW);
    } else {
        time_start = millis();
        if (voltage >= 12.5) {
            flag_start = false;
        }
    }
  }
Только надо не забыть объявить time_start и flag_start

@viktor1703, Судя по коду, вольтаже где то считывается выше, поэтому при запуске цикл фактически бесконечный, так что думаю тут мешает подход к задачи и непонимание сего...
@JamToJum, я бы посоветовал поискать тут тему СтарикаПохабыча про "помигаем светодиодом", думаю она была бы для Вас очень полезна.
 
Изменено:

viktor1703

★★★✩✩✩✩
9 Дек 2021
631
150
@viktor1703, Судя по коду, вольтаже где то считывается выше
Судя по коду этого я не вижу, может опыта в программировании у меня мало, а может и в правду лыжи не едут и я не могу отличить переменную voltage от вызова функции измерения напряжения, например, voltage()
 
  • Лойс +1
Реакции: DAK

JamToJum

✩✩✩✩✩✩✩
29 Окт 2020
7
0
@viktor1703, аналоговый пин через делитель напряжения в переменную флоат вольтаж измеряет безконечно пока вольтаж на акуме не изменится до 12.5 вольт тогда вайл сбросится
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@viktor1703, Просто видно, что код не сначала loop выдернут, я бы всем новичкам советовал полностью код вставлять, чтобы не гадать каким образом что где реализовано и на какие грабли ещё можно наступить.
@JamToJum, Вы сильно заблуждаетесь, в Вашем случае она измеряется бесконечно до того, как вы вошли в процедуру заряд разряд, там она вообще не измеряется
 
  • Лойс +1
Реакции: viktor1703

JamToJum

✩✩✩✩✩✩✩
29 Окт 2020
7
0
Код вольтметра брал из интернета, под себя подгонял, калькулятором определил номинал резисторов. Но на мультиметре большая ошибка в измерении либо резисторы некачественные и реально у меня получилось не 13.5 вольт а 12.5 вольт на акуме а на Пине 5 вольт
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
631
150
@viktor1703, аналоговый пин через делитель напряжения в переменную флоат вольтаж измеряет безконечно
В каком месте? Начинается цикл:
пока (переменная вольтаж < 12,5) {
включаешь реле1;
ждёшь 7 с;
выключаешь реле1;
ждёшь 0,5с;
включаешь реле2;
ждёшь 2с;
выключаешь реле2; }
и так до бесконечности.
А когда же в этом цикле ты измеряешь напряжение и перезаписываешь переменную вольтаж?
 
Изменено:

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@JamToJum, Лучше попробуйте сперва разобраться с тем, что написано выше (в том числе почитайте ветку), и уже потом изменённый код сюда, не важо работает он или нет, хотя бы будет понятно что вы действительно пытаетесь разобраться с этим делом...
 

JamToJum

✩✩✩✩✩✩✩
29 Окт 2020
7
0
@DAK,можна подробнее как вы определили какие тайминг в милис ставить. А то не хочется каждый раз с этим людей поднимать...
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@JamToJum, Да я с таймингами накосячил, я их не определял, я взял ваши и накосячил:), уже поправил код 7000+500+2000+500
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
631
150
@JamToJum, вот здесь недавно обсуждали этоу пресловую функцию millis(). Хотя не совсем то что нужно. Там про переполнение счётчика речь идёт.
 
Изменено:

JamToJum

✩✩✩✩✩✩✩
29 Окт 2020
7
0
@viktor1703,я был там и читал этот пост - искал может найду похожую ситуацию на мою, и буду реализовывать

Я в программировании не полный ноль, но только начинаю с этим разбираться. Немного теории, берусь делать какой-то проект и уже по ходу дела что не понимаю начинаю изучать и практиковаться.

Мне так проще видел то чего я не знаю и начинать изучать

@DAK, спасибо за пример, но всё-таки лучше разобраться нежели написать готовое человеку, и он снова с этаким придет на форум.

Это мой файл
 

Вложения

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@JamToJum, Давайте сделаем немного иначе, Вы все свои последовательные сообщения выше объедините в одно, так как получите от модератора (правила форума), а код лучше оформить как в Вашем первом посту, в этом случае появится нумерация строк и на неё уже можно будет ссылаться, так нам удобнее будет Вам показывать на те или иные места в коде.

UPD:
Посмотрел файл
Всё намешано....
Начинайте последовательно, подключите ко порт и пишите туда показания напряжения (будет весело), я не думаю что это так работает, как вы хотите. Из каких резисторов у вас собран делитель напряжения? Сперва с этим разберитесь, потом уже милис....
 
Изменено:

viktor1703

★★★✩✩✩✩
9 Дек 2021
631
150
А где же перевод из значения 10 бит АЦП (0...1023) в напряжение (0...12,5 вольт). Если просто присваивать переменной voltage значение из АЦП, то условие будет удовлетворяться, если на А7 будет ниже 0,58 вольт.
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Меня другое тревожит
int analogPin = A7;
float voltage = analogRead(analogPin);

Как на это компилятор отреагирует я не знаю, но может правильнее сделать
#define ANALOG_PIN A7;
float voltage=analogRead(ANALOG_PIN)*k; //k-коэффициент преобразования.

Я не даром сказал, надо цеплять к ком порту, и voltage сделать int, посмотреть сколько это вылетит в ком порт при 12и5 Вольтах и в условие просто поставить это значение (были бы данные о резисторах можно было ориентировочно прикинуть)
 

Normalek

★✩✩✩✩✩✩
6 Авг 2021
140
39
как то так правда там реле через npn надо пускать и светодиоды надо на резистор повесить
 
Изменено:
  • Ну такое -1
Реакции: DAK

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@Normalek, Нельзя так, зачем делать ссылки куда то, где ещё надо регистрироваться, неужели нельзя просто сюда выложить скрин с экрана и код программы? В дополнение написать что есть такая ссылка, но по ней надо регистрироваться!
 

Normalek

★✩✩✩✩✩✩
6 Авг 2021
140
39
@DAK, что визуально видно было
C++:
int val = 0;
uint8_t mod = 0;
uint32_t _millis;


#define V_BIT 9
#define LED_BIT 8
#define _COFI 5.75

void setup() {
  Serial.begin(4800);
  pinMode(A0, INPUT);
  pinMode(V_BIT, OUTPUT);
  digitalWrite(V_BIT, LOW);
  pinMode(LED_BIT, OUTPUT);
  digitalWrite(LED_BIT, LOW);
}

void loop() {
  _millis = millis()- _millis;
  if((mod == 1 && _millis > 7000) || (mod == 2 && _millis > 2000)) {
    _millis = millis();
    mod = 0;
    digitalWrite(LED_BIT, LOW);
    digitalWrite(V_BIT, LOW);
  }
  else {
    if(_millis > 100) {
        float _volt = analogRead(A0) * 5 / 1024.0 * _COFI;
        if(_volt > 12.55) {
          digitalWrite(V_BIT, LOW);
          digitalWrite(LED_BIT, HIGH);
        }
        else if(_volt < 12.45) {
          digitalWrite(LED_BIT, LOW);
          digitalWrite(V_BIT, HIGH);
          mod = 1;
        }
      else {
        digitalWrite(LED_BIT, LOW);
        digitalWrite(V_BIT, LOW);
      }
        _millis = millis();
        Serial.println(_volt);
    }
  }
}

/*#include <SoftwareSerial.h>

int val = 0;
uint8_t mod = 0;
uint32_t _millis;
//#include <SoftwareSerial.h>

#define V_BIT PB3
#define LED_BIT PB0
#define _COFI 0.95

SoftwareSerial Serial(1, 3);
void setup() {
  Serial.begin(4800);
  pinMode(PB2, INPUT);
  pinMode(V_BIT, OUTPUT);
  digitalWrite(V_BIT, LOW);
  pinMode(LED_BIT, OUTPUT);
  digitalWrite(LED_BIT, LOW);
}

void loop() {
  _millis = millis()- _millis;
  if((mod == 1 && _millis > 7000) || (mod == 2 && _millis > 2000)) {
    _millis = millis();
    mod = 0;
    digitalWrite(LED_BIT, LOW);
    digitalWrite(V_BIT, LOW);
  }
  else {
    if(_millis > 100) {
        float _volt = analogRead(PB2) * 5 / 1024.0 * _COFI;
        if(_volt > 12.55) {
          digitalWrite(V_BIT, LOW);
          digitalWrite(LED_BIT, HIGH);
        }
        else if(_volt < 12.55) {
          digitalWrite(LED_BIT, LOW);
          digitalWrite(V_BIT, HIGH);
          mod = 1;
        }
      else {
        digitalWrite(LED_BIT, LOW);
        digitalWrite(V_BIT, LOW);
      }
        _millis = millis();
        Serial.print(int(_volt));
    }
  }
}
/*

/*#define F_CPU 8000000UL
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#define V_BIT _BV(PB3)
#define LED_BIT _BV(PB0)
#define _COFI 0.95

int main(void);

uint32_t _millis = 0;
uint16_t _1000us = 0;


ISR(TIM0_OVF_vect) {
  _1000us += 256;
  while (_1000us > 1000) {
    _millis++;
    _1000us -= 1000;
  }
}

int main(void) {
  DDRB |= V_BIT;
  PORTB &= V_BIT;

  DDRB |= LED_BIT;
  PORTB &= ~LED_BIT;

  ADCSRA|=(1<<ADEN);
  ADMUX=0x01;
  ADCSRB=0x00;
  ADCSRA|=(1<<ADSC)|(1<<ADATE);

  TCCR0B |= (1<<CS01);
  TIMSK  |= 1<<TOIE0;
  sei();
  uint8_t mod = 0;
  for(;;) {
    int adc_l=ADCL;
    int adc_val=(ADCH<<8)|adc_l;
    if((mod == 1 && _millis > 7000) || (mod == 2 && _millis > 2000)) {
       _millis = mod = 0;
       PORTB &= ~V_BIT;
       PORTB &= ~LED_BIT;
    }
    else {
       if(_millis > 100) {
          float _volt = adc_val * 5 / 1024.0 * _COFI;
          if(_volt > 12.55) {
             PORTB &= ~V_BIT;
             PORTB |= LED_BIT;
             mod = 2;
          }
          else if(_volt < 12.55) {
            PORTB &= ~LED_BIT;
            PORTB |= V_BIT;
            mod = 1;
          }
          else {
          PORTB &= ~V_BIT;
       PORTB &= ~LED_BIT;
          }
          _millis = 0;
       }
    }
    TIFR|=(1<<TOV0);
  }
};*/
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@JamToJum, это претензия?
Я же написал Вам... Вы думаете от хорошей жизни, сам регулярно получаю по шее за такие штуки как несколько сообщений подряд....
Но это всё не по теме.. У вас получилось что-нить сделать? Переписать код и разобраться во всём этом деле? Посмотрели значение voltage при 12,5 Вольт получается?
 

JamToJum

✩✩✩✩✩✩✩
29 Окт 2020
7
0

@DAK,
Да, вольтаж работает на ура. Я с ним разобрался сразу же. И у меня он был рабочий. Я выводил в сериал-порт значение. Все там в порядке. Ещё не разбирался с кодом либо времени сейчас немного, да и воскресение сегодня.
А так как заблочен был, доступа почитать то что вы мне ответили небыло. Отдыхаю немного сегодня. Взавтра начну
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
Ну что тут сказать, вот ваш код:
C++:
#define BTN_PIN 2      //кнопка
#include <GyverButton.h> //
GButton butt1(BTN_PIN);
#define LED_1 8   //светодиод 1
#define LED_2 9   //светодиод 2
#define LED_3 10  //светодиод 3
#define RELAY_CHARGE 5
#define RELAY_DISCHARGE 6
int analogPin = A7; // вольтметр иаксимум 12.5 вольт
float voltage = 0;

void setup() {
  butt1.setDebounce(40);
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  pinMode(LED_3, OUTPUT);
  pinMode(BTN_PIN, INPUT);
  pinMode(RELAY_CHARGE, OUTPUT);
  pinMode(RELAY_DISCHARGE, OUTPUT);

}

void loop() {
    
/////Вольтметр/////   
   float voltage = analogRead(analogPin);

//////////

  butt1.tick();
    
  if (butt1.isStep(0)) {
    digitalWrite (LED_1, HIGH);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, LOW);
  }

  if (butt1.isStep(1)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, HIGH);
    digitalWrite (LED_3, LOW);
    while (voltage < 12.5) {
            digitalWrite(RELAY_CHARGE, HIGH);
            delay (7000);
            digitalWrite(RELAY_CHARGE, LOW);
            delay (500);
            digitalWrite(RELAY_DISCHARGE, HIGH);
            delay (2000);
            digitalWrite(RELAY_DISCHARGE, LOW);
            delay (500);
        }       
  }
    
  if (butt1.isStep(2)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, HIGH);
  }

  if (butt1.isStep(3)) {
    digitalWrite (LED_1, LOW);
    digitalWrite (LED_2, LOW);
    digitalWrite (LED_3, LOW);
  }
}
Вам уже писали выше, что Ваше условие сработает при 0,58 Вольт на пине, я не пересчитывал, но думаю там всё правильно посчитали.
Каким образом вольтаж у вас нормально работает, я не знаю, наверное так же, как бесконечный цикл. Я не исключаю что вы делителем на резисторе поиграли так, что на аналоговый пин приходит о.58 когда на батарее 12,5, но это просто не правильный подход.
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
631
150
условие сработает при 0,58 Вольт на пине, я не пересчитывал, но думаю там всё правильно посчитали.
Давайте вместе пересчитаем, если что - поправляйте.
Измеряем напряжение, строка 26
C++:
float voltage = analogRead(analogPin);
То есть в переменную voltage пишем значение из АЦП без каких-либо преобразований. Так? Смотрим далее, строка 42
C++:
while (voltage < 12.5)
Так как из АЦП приходят целые числа, то условие будет выполняться только когда в voltage будет не больше 13, то есть 12 удовлетворяет условию. Верно? Теперь считаем 1023 - это 5 вольт, а 12 - это 5 х 12 / 1203 = 0,058651 вольт на ноге A7. Что том с делителем напряжения я не знаю, но тоже интересно
 
Изменено: