помогите с таймером

Тема в разделе "Arduino & Shields", создана пользователем issida, 23 май 2016.

  1. issida

    issida Нерд

    Таймер на несколько включений в день по расписанию на одном канале без экрана. Используется Arduino Pro Mini и DS1307. С одним включением и выключением работает нормально.
    Код (C++):

    #include <Wire.h> //Подключаем библиотеку для использования I2C интерфейса с модулем RTC
    #include <RTClib.h> //Подключаем библиотеку для использования модуля часов реального времени RTC
    RTC_DS1307 RTC; //Создаем переменную класса - для использования RTC
    const int led = 11; //Используем цифровой ПОРТ 13 для ПЕРВОГО канала релейного модуля

    // Массивы со временм включения и выключения
    long onh[]={16,16,16,16}; //Часы включения
    long onm[]={19,19,19,19}; // Минуты
    long ons[]={0,5,10,15}; //Секунды
    long time_on = 0;
    long offh[]={16,16,16,16}; //Часы выключения
    long offm[]={19,19,19,19};  //Минуты
    long offs[]={3,8,13,19}; //Секунды
    long time_off = 0;

    void setup(){
    Serial.begin(9600);
    pinMode(led,OUTPUT); //Инициализируем порт для ПЕРВОГО канала как ВЫХОД
    analogWrite(led,0); //Устанавливаем на входах модуля НИЗКИЙ уровень
    Wire.begin(); //Инициируем I2C интерфейс
    RTC.begin(); //Инициирум RTC модуль
    }

    void loop()
    {
    DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла
    long utime = myTime.unixtime(); //сохраняем в переменную - время в формате UNIX
    utime %= 86400; //Сохраняем в этой же переменной остаток деления на кол-во секнд в сутках,
    //Это дает количество секунд с начала текущих суток

    for (int a = 0; a < 4; a++){                                 // изменить цифру на кол-во раз ключения
    long time_on = ((onh[a]*3600)+(onm[a]*60)+ons[a]);          //Рсчет секунд для включения
    Serial.println(time_on);          
    long time_off = ((offh[a]*3600)+(offm[a]*60)+offs[a]);      //Рсчет секунд для выключения
    Serial.println(time_off);
    if ((utime >= time_on) && (utime <= time_off)) {
    analogWrite(led,255); //Устанавливаем на ПЕРВОМ канале ВЫСОКИЙ уровень
    }
    else //во всех остальных случаях
    {
    analogWrite(led,0); //Устанавливаем на ПЕРВОМ канале НИЗКИЙ уровень
    }
    }
    }

     
    Если добавить оставшиеся включения, получается абракадабра. В таком варианте кода цикл считает массивы по кругу не дожидаясь выполнения условия. И из-зи этого появляется мерцание . Нужно заставить посчитать первые элементы массивов, дождаться, когда выполнится условие, включить и выключить led, посчитать вторые элементы массивов, дождаться, когда выполнится условие, включить и выключить led и т.д.Как это увязать?
     
  2. AlexU

    AlexU Гуру

    Включение/выключение светодиода необходимо вынести за пределы цикла:
    Код (C++):
    #include <Wire.h> //Подключаем библиотеку для использования I2C интерфейса с модулем RTC
    #include <RTClib.h> //Подключаем библиотеку для использования модуля часов реального времени RTC
    RTC_DS1307 RTC; //Создаем переменную класса - для использования RTC
    const int led = 11; //Используем цифровой ПОРТ 13 для ПЕРВОГО канала релейного модуля

    // Массивы со временм включения и выключения
    long onh[]={16,16,16,16}; //Часы включения
    long onm[]={19,19,19,19}; // Минуты
    long ons[]={0,5,10,15}; //Секунды
    long time_on = 0;
    long offh[]={16,16,16,16}; //Часы выключения
    long offm[]={19,19,19,19};  //Минуты
    long offs[]={3,8,13,19}; //Секунды
    long time_off = 0;

    void setup(){
    Serial.begin(9600);
    pinMode(led,OUTPUT); //Инициализируем порт для ПЕРВОГО канала как ВЫХОД
    analogWrite(led,0); //Устанавливаем на входах модуля НИЗКИЙ уровень
    Wire.begin(); //Инициируем I2C интерфейс
    RTC.begin(); //Инициирум RTC модуль
    }

    void loop()
    {
    DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла
    long utime = myTime.unixtime(); //сохраняем в переменную - время в формате UNIX
    utime %= 86400; //Сохраняем в этой же переменной остаток деления на кол-во секнд в сутках,
    //Это дает количество секунд с начала текущих суток

    bool doLedOn = false;

    for (int a = 0; a < 4; a++){                                 // изменить цифру на кол-во раз ключения
      long time_on = ((onh[a]*3600)+(onm[a]*60)+ons[a]);          //Рсчет секунд для включения
      Serial.println(time_on);      
      long time_off = ((offh[a]*3600)+(offm[a]*60)+offs[a]);      //Рсчет секунд для выключения
      Serial.println(time_off);
      if ((utime >= time_on) && (utime <= time_off)) {
        doLedOn = true;
      }
    }
    if (doLedOn) {
      analogWrite(led,255); //Устанавливаем на ПЕРВОМ канале ВЫСОКИЙ уровень
    } else //во всех остальных случаях
    {
      analogWrite(led,0); //Устанавливаем на ПЕРВОМ канале НИЗКИЙ уровень
    }
    }
     
     
    issida и Alexey Zhigalo нравится это.
  3. issida

    issida Нерд

    Заработало. Спасибо. Потребовалось также немного усложнить программу. По достижении времени выполнить увеличение и уменьшение шим.
    Код (C++):
    #include <Bounce2.h> // подключаем библиотеку
    #include <Wire.h> //Подключаем библиотеку для использования I2C интерфейса с модулем RTC
    #include <RTClib.h> //Подключаем библиотеку для использования модуля часов реального времени RTC
    RTC_DS1307 RTC; //Создаем переменную класса - для использования RTC
    long onh[]={20,20,20,20}; //Часы включения
    long onm[]={50,50,50,50}; // Минуты
    long ons[]={0,10,20,30}; //Секунды
    long time_on = 0;
    long offh[]={20,16,16,16}; //Часы выключения
    long offm[]={50,50,50,50};  //Минуты
    long offs[]={5,15,25,30}; //Секунды
    long time_off = 0;
    int t = 0; // начало счетчика(не имеет значения, но лучше не трогать)
    int tpwm = 1; // величина счетчика, устанавливает длительность шим
    int onb = 0; // устанавливает начальное значение включения
    int one = 255; // устанавливает конечное значение включения
    int offb = 255; // устанавливает начальное значение выключения
    int offe = 0; // устанавливает конечное значение выключения
    const int switchPin = 8; // пин кнопки
    const int ledPin = 11; // пин светодиода
    int cnt = 0; // счётчик нажатий
    int c = 0 ; // переменная для восстановления начальных значений вкл и выкл
    Bounce b = Bounce(); // инстанциируем объект Bounce

    void setup() {
      Serial.begin(9600);
      pinMode(switchPin, INPUT);
      digitalWrite(switchPin, HIGH); // включаем подтягивающий резистор
      pinMode(ledPin, OUTPUT);
      analogWrite(ledPin,0); //Устанавливаем на входах модуля НИЗКИЙ уровень
      b.attach(switchPin); // объект Bounce будет слушать кнопку на пине switchPin
      b.interval(5); // устанавливаем время задержки в [мс]
      Wire.begin(); //Инициируем I2C интерфейс
      RTC.begin(); //Инициирум RTC модуль
    }

    void loop() {
    DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла
    long utime = myTime.unixtime(); //сохраняем в переменную - время в формате UNIX
    utime %= 86400; //Сохраняем в этой же переменной остаток деления на кол-во секнд в сутках,
    //Это дает количество секунд с начала текущих суток
    for (int a = 0; a < 4; a++){
    long time_on = ((onh[a]*3600)+(onm[a]*60)+ons[a]);
    long time_off = ((offh[a]*3600)+(offm[a]*60)+offs[a]);
    if (utime==time_on) {
      c = onb;
          while(c < one)
          {
          t++;
          if(t>tpwm) t=0;
          if(t==1)c++;
          Serial.println(c);
            {
          analogWrite(ledPin, c);// иначе - зажигаем светодиод
            }
          }
     
    }
    else if (utime==time_off) {
    c = offb; // запоминание начального значения
          while(c > offe)
          {
          t++;
          if(t>tpwm) t=0;
          if(t==1)c--;
          Serial.println(c);
            {
          analogWrite(ledPin, c);// гасим светодиод
            }
          }
     
    }
    }
    /* if (b.update() && b.read() == 0) { // если зарегистрировано событие и кнопка нажата,
        cnt += 1; // инкрементируем счётчик нажатий
        if (cnt %2 == 0)  //если четное, то гасим
        {
          c = offb; // запоминание начального значения
          while(offb > offe)
          {
          t++;
          if(t>tpwm) t=0;
          if(t==1)offb--;
          Serial.println(offb);
            {
          analogWrite(ledPin, offb);// гасим светодиод
            }
          }
        offb = c ;
        }
        else
        {
          c = onb;
          while(onb < one)
          {
          t++;
          if(t>tpwm) t=0;
          if(t==1)onb++;
          Serial.println(onb);
            {
          analogWrite(ledPin, onb);// иначе - зажигаем светодиод
            }
          }
         onb = c ;
        }
    }
    */

    }
    первый раз включился от 0 до 255, выключился 255 - 0, и потом 3 раза только включается 0 - 255. От кнопки код работал правильно.
     
  4. AlexU

    AlexU Гуру

    Код (C++):
    long onh[]={20,20,20,20}; //Часы включения
    ...........
    long offh[]={20,16,16,16}; //Часы выключения
    Внимательно смотрим и сравниваем последние три элемента массивов 'onh[]' и 'offh[]'.
     
  5. Limoney

    Limoney Гик

    не по делу
    if(t>tpwm)t=0;
    if(t==1)c++;
    Serial.println(c);
    {
    analogWrite(ledPin, c);// иначе - зажигаем светодиод
    }
     
  6. issida

    issida Нерд

    Работает же, хоть и криво. Совсем недавно взялся за это дело.
     
  7. fogary

    fogary Гик

    Код (C++):
    long onh[]={20,20,20,20};
    . . .
    int offb = 255;
    int offe = 0;
    Извиняюсь, что не совсем по теме, но может объясните, в чем выгода использовать для подобных переменных избыточный тип данных? Логичнее, на первый взгляд, было бы здесь использовать тип byte.
     
  8. issida

    issida Нерд

    byte сэкономил 280 байт памяти
     
  9. Limoney

    Limoney Гик

    посмотрите на условие в мониторе порта.
    Наверное, делаете плавно нарастающий и плавно спадающий ШИМ просто подсчет от минимума к максимуму выполняется быстро, поэтому ШИМ выйдет на максимум и аналогично на минимум быстро.
    Можно применить delayMicroseconds
     
  10. issida

    issida Нерд

    Limoney, код заработал, ошибка по невнимательности в указании времени в массивах.
    Код (C++):
    if(t>tpwm)t=0;
    if(t==1)c++;
    Serial.println(c);
    {
    analogWrite(ledPin, c);// иначе - зажигаем светодиод
    }
    Не хочу использовать delay и millis, первый по причине остановке всей программы, второй - не хочу делать рестарт каждые 50 дней. Или можно как-нибудь более красиво выйти из положения?