attiny13 и millis()

Тема в разделе "Микроконтроллеры AVR", создана пользователем DrProg, 17 авг 2015.

  1. DrProg

    DrProg Вечный нерд

    Столкнулся с проблемой, что millis() на attiny13 не работает. Delay() работает, а что с millis() не знаю, то проскакивает, то останавливается. Пробовал на двух МК, на разных ножках. Подключены без кварца на 1,2Мгц.
     
    Последнее редактирование: 17 авг 2015
    ИгорьК нравится это.
  2. DrProg

    DrProg Вечный нерд

    Это адский адъ, но я понял причину, хотя не понял почему и как с этим бороться. Дело в типе данных long, который я традиционно присваиваю счетчикам миллисекунд. Он не работает. Подставляю int, все заводится, правда через минуту с небольшим остановливается, ибо переполняется. А long глючит сразу и намертво. Альтернатива в виде uint32_t так же не работает.

    Происходит это только на attiny13 другие тини не пробовал, т.к. пока не имею), Мега и Уно работают отлично. У 13, вероятно, какие то ограничения по памяти.

    Вопрос знатокам: как побороть? Первое что пришло в голову мне это оставить int, но каким то образом программно скидывать таймер при опасной близости к переполнению. События у меня происходят раз в секунду, вполне возможно успевать. Но не знаю как сбрасывать, возможно ли это и правильно ли. Какие могут быть еще варианты?
     
    ИгорьК нравится это.
  3. Tomasina

    Tomasina Сушитель лампочек Модератор

    попробуй макрос DO_EVERY, но с int вместо long. Там переполнение учтено.
     
  4. DrProg

    DrProg Вечный нерд

    Решение интересное, обязательно изучу и попробую. Но в данном случае программа уже размером на 85% памяти, боюсь не влезет еще одно библиотека. Само по себе странно что long так себя ведет именно в этих условиях. Думаю, что сбрасывать таймер научусь, но это костыли конечно.
     
    ИгорьК нравится это.
  5. Tomasina

    Tomasina Сушитель лампочек Модератор

    Там не библиотека, а макрос, он много не займет.
    Другое дело, что если занято 85% - может в процессе расчетов с long происходит перерасход памяти? Уберите из скетча лишнее и проверьте на минимальном коде.
     
  6. DrProg

    DrProg Вечный нерд

    Проверял на мигалке через таймер, глючит так же. Да и врядли несколько байт так критично. Даже не знаю где искать причину. В IDE для разных МК разные определения что ли?
     
    Последнее редактирование: 17 авг 2015
    ИгорьК нравится это.
  7. Megakoteyka

    Megakoteyka Оракул Модератор

    Могут быть фокусы компилятора.
     
  8. DrProg

    DrProg Вечный нерд

    То есть сделать что то вряли можно?

    Таймер обнулять так?
    Код (Text):
    TCNT1 = 0;
     
    ИгорьК нравится это.
  9. Megakoteyka

    Megakoteyka Оракул Модератор

    Давайте ваш код посмотрим для начала. Возможно, вы просто что-то упустили.
     
  10. DrProg

    DrProg Вечный нерд

    Вечером скину. Но писал его на Меге, все работало как должно.
     
    ИгорьК нравится это.
  11. geher

    geher Гуру

    В качестве решения можно попробовать следующее:
    1. Переменную для хранения возвращаемого millis() значения объявить как unsigned int (важный момент, тип должен быть беззнаковым).
    2. Для получения текущего значения счетчика использовать millis()&0x0000FFFF.
    Т.е. примерно так:
    unsigned int time=millis()&0x0000FFFF;
    Таким образом в теории мы уходим от возможного переполнения при присваивании и получаем счетчик миллисекунд, сбрасываемый каждые 65 с копейками секунд.
    Понятно, что измеряемые интервалы в этом случае не должны превышать минуту. А еще лучше будет ограничение ужесточить, и отменять не более чем полуминутные интервалы.
     
  12. DrProg

    DrProg Вечный нерд

    Беззнаковый и использовал, мало времени как ни крути. Второй совет интересный, попробую, но получается раз в минуту (или полминуты) будем иметь секунду непредсказуемой длины.
     
    ИгорьК нравится это.
  13. geher

    geher Гуру

    Почему непредсказуемой? Там в теории такая же логика обработки переполнений, как и в случае с unsigned long.

    Только переход через ноль чаще будет происходить.

    Т.е. 2-65534 будет 4, если не ошибаюсь.
     
  14. DrProg

    DrProg Вечный нерд

    Ну вот считалось показание миллисекунд в переменную, а через полсекунды оно бац и обнулилось. Думаете правильно отнимет?
    А может лучше бы обнулять принудительно перед очередным считыванием раз в минуту, например?
     
    ИгорьК нравится это.
  15. Unixon

    Unixon Оракул Модератор

    Что у вас за код для ATtiny ?
     
  16. DrProg

    DrProg Вечный нерд

    Привожу код. Программка по сути секундомер обратного отсчета, Есть двухразрядый индикатор, есть светодиодная шкала. На индикаторе горит некая цифра (в данном случае 20), на шкале шесть черточек. Сначала каждую секунду убывают цифры на индикаторе до 0, после чего тухнет один светодиод (или палочка на светодиодной шкале), индикатор вновь возвращается в исходную и так далее пока не погаснут все палочки шкалы. Это спортивный таймер, 6 подходов по N секунд. Недоделан немного, ибо хочу добавить паузу и выбор режима в начале, а еще добавить звуковое оповещение, но это мелочи, главное разобраться с таймером.

    Индикатор работает динамически, поэтому delay никак не прокатит. Аноды индикатора управляются первым сдвиговым регистром, катоды - вторым и им же светодиодная шкала.
    Код (Text):
    //#define MEGA // закаментить если TINY

    #if defined(MEGA)
    #define DATA_PIN    13
    #define LATCH_PIN  12
    #define CLOCK_PIN  11
    #else
    #define DATA_PIN    PB4
    #define LATCH_PIN  PB1
    #define CLOCK_PIN  PB0
    #endif


    byte segment [11] = {
      0b01111011, 0b00010001, 0b10111010, 0b10111001, 0b11010001,
      0b11101001, 0b11101011, 0b00110001, 0b11111011, 0b11111001,
      0b00000000,
    };

    byte sekond;
    byte train = 6;
    unsigned long timerSekond;                      // тот самый таймер

    byte timeOfTrain = 20;

    void setup() {
      pinMode(DATA_PIN, OUTPUT);
      pinMode(CLOCK_PIN, OUTPUT);
      pinMode(LATCH_PIN, OUTPUT);
      sekond = timeOfTrain;
      timerSekond = millis()+1000;
    }

    void loop() {
      setDisp (train, sekond);
      if (timerSekond <= millis()) {
        sekond--;
        if (sekond == 0) {
          sekond = timeOfTrain;
          train--;
          if (train == 0) stopTrain();
        }
        timerSekond = millis()+1000;
      }
    }

    void stopTrain() {                          // закончили тренеровку
      digitalWrite(LATCH_PIN, LOW);
      writeByte(0b10101000);
      writeByte(0b01010011);
      digitalWrite(LATCH_PIN, HIGH);
      while (true);
    }

    void setDisp (byte ledsOn, byte timeSet) {  // динамический секундомер и обратный отсчет
      byte leds = 0;
      for (int i = 0; i < ledsOn; i++) bitSet(leds, (i + 2));
      leds++;
      digitalWrite(LATCH_PIN, LOW);
      writeByte(leds);
      writeByte(segment[timeSet / 10]);
      digitalWrite(LATCH_PIN, HIGH);
      leds++;
      digitalWrite(LATCH_PIN, LOW);
      writeByte(leds);
      writeByte(segment[timeSet % 10]);
      digitalWrite(LATCH_PIN, HIGH);
    }



    void writeByte(byte byteW) {                  // аналог shiftOut, работает чуть быстрее
      for (int i = 0; i <= 7; i++)
      {
        digitalWrite(DATA_PIN, (bitRead(byteW, i)));
        digitalWrite(CLOCK_PIN, HIGH);
        digitalWrite(CLOCK_PIN, LOW);
      }
    }
    В случае типа long секундомер сразу выставляется в 16 и замирает навеки. В случае int работает хорошо 1 минуту и 10 секунд.
     
    ИгорьК нравится это.
  17. Tomasina

    Tomasina Сушитель лампочек Модератор

    Код (Text):
    #if defined(MEGA)
    #define DATA_PIN    13
    #define LATCH_PIN  12
    #define CLOCK_PIN  11
    #else
    #define DATA_PIN    PB4
    #define LATCH_PIN  PB1
    #define CLOCK_PIN  PB0
    #endif
    если это убрать, работает? Помнится, был какой-то глюк в IDE с обработкой #if
     
  18. DrProg

    DrProg Вечный нерд

    Да, я каментил полностью, не в этом дело.

    Вот как выкрутился пока не подскажут что получше:
    Код (Text):
    //#define MEGA // закаментить если TINY

    #if defined(MEGA)
    #define DATA_PIN    13
    #define LATCH_PIN  12
    #define CLOCK_PIN  11
    #else
    #define DATA_PIN    PB4
    #define LATCH_PIN  PB1
    #define CLOCK_PIN  PB0
    #endif


    byte segment [11] = {
      0b01111011, 0b00010001, 0b10111010, 0b10111001, 0b11010001,
      0b11101001, 0b11101011, 0b00110001, 0b11111011, 0b11111001,
      0b00000000,
    };

    byte sekond;
    byte train = 6;
    unsigned int timerSekond;                      // тот самый таймер

    byte timeOfTrain = 20;

    void setup() {
      pinMode(DATA_PIN, OUTPUT);
      pinMode(CLOCK_PIN, OUTPUT);
      pinMode(LATCH_PIN, OUTPUT);
      sekond = timeOfTrain;
      timerSekond = millis() % 60000;          // <--  костыль
    }

    void loop() {
      setDisp (train, sekond);
      if (((millis() % 60000) - timerSekond) >= 1000) {
        sekond--;
        if (sekond == 0) {
          sekond = timeOfTrain;
          train--;
          if (train == 0) stopTrain();
        }
        timerSekond = millis() % 60000;
      }
    }

    void stopTrain() {                          // закончили тренеровку
      digitalWrite(LATCH_PIN, LOW);
      writeByte(0b10101000);
      writeByte(0b01010011);
      digitalWrite(LATCH_PIN, HIGH);
      while (true);
    }

    void setDisp (byte ledsOn, byte timeSet) {  // динамический секундомер и обратный отсчет
      byte leds = 0;
      for (int i = 0; i < ledsOn; i++) bitSet(leds, (i + 2));
      leds++;
      digitalWrite(LATCH_PIN, LOW);
      writeByte(leds);
      writeByte(segment[timeSet / 10]);
      digitalWrite(LATCH_PIN, HIGH);
      leds++;
      digitalWrite(LATCH_PIN, LOW);
      writeByte(leds);
      writeByte(segment[timeSet % 10]);
      digitalWrite(LATCH_PIN, HIGH);
    }



    void writeByte(byte byteW) {                  // аналог shiftOut, работает чуть быстрее
      for (int i = 0; i <= 7; i++)
      {
        digitalWrite(DATA_PIN, (bitRead(byteW, i)));
        digitalWrite(CLOCK_PIN, HIGH);
        digitalWrite(CLOCK_PIN, LOW);
      }
    }
    Работает. :rolleyes:
     
    ИгорьК нравится это.
  19. Unixon

    Unixon Оракул Модератор

    Здесь нет кода таймера. Где обработчик прерывания и счетчик millis ?
     
  20. DrProg

    DrProg Вечный нерд

    Зачем прерывания если можно без них? А счетчик есть.

    Да, у tiny13 вроде бы один таймер? Он мне нужен для шим в дальнейшем.
     
    Последнее редактирование: 18 авг 2015
    ИгорьК нравится это.