Atmega Millis с кварцевым кристаллом

Я последовал за ним https://www.arduino.cc/en/Tutorial/ArduinoToBreadboard это руководство по программированию моего Atmega 328p для работы на макетной плате с кварцевым кристаллом 16 МГц и двумя конденсаторами 22 Пф. Я хочу запрограммировать цифровые часы без RTC (код ниже). Поэтому я написал свой код с помощью millis () и установил время точно на время моего мобильного телефона. Через две минуты Atmega пришла примерно на четверть минуты раньше, но, похоже, осталась там. Это почему? Разве он не использует кристалл? Должен ли я программировать его по-другому? Или он останется на этой разнице во времени и будет работать более или менее точно сейчас?

Мой код:

#define ZERO 0b01110111
#define ONE 0b00000110
#define TWO 0b10110011
#define THREE 0b10010111
#define FOUR 0b11000110
#define FIVE 0b11010101
#define SIX  0b11110101
#define SEVEN 0b00000111
#define EIGHT 0b11110111
#define NINE 0b11010111
#define SECOND 1000
static int changed = 0;

static int led01 = 1;
static int led02 = 3;

static int led11 = 4;
static int led12 = 5;

static int state = 0;
static int selP = 0;

static int blink = 0;
static int btn_1 = 0, btn_2 = 0;

static long last = millis();
static long tm = 0;

static int seconds = 0, minutes = 45, hours = 13;

static const int DATAH1 = 2, ST_CPH1 = 3, SH_CPH1 =4;
static const int DATAH2 = 5, ST_CPH2 = 6, SH_CPH2 =7;

static const int DATAM1 = 11, ST_CPM1 = 12, SH_CPM1 =13;
static const int DATAM2 = A0, ST_CPM2 = A1, SH_CPM2 =A2;

static const char numbers[10] = {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE};
void setup()
{
  pinMode(DATAH1, OUTPUT);
  pinMode(ST_CPH1, OUTPUT);
  pinMode(SH_CPH1, OUTPUT);

  pinMode(DATAH2, OUTPUT);
  pinMode(ST_CPH2, OUTPUT);
  pinMode(SH_CPH2, OUTPUT);

  pinMode(DATAM1, OUTPUT);
  pinMode(ST_CPM1, OUTPUT);
  pinMode(SH_CPM1, OUTPUT);

  pinMode(DATAM2, OUTPUT);
  pinMode(ST_CPM2, OUTPUT);
  pinMode(SH_CPM2, OUTPUT);

  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
}


// main loop
void loop()
{
  long curr = millis();
  tm += curr-last;
  if(tm < 0 || tm > 900000){
    tm = 0;
  }
  last = curr; 
  if(digitalRead(9) == LOW){
    if(!btn_1){
      if(state == 0){
        state = 1;
        selP = 0;
      }else{
        if(selP >= 3) state = 0;
        else selP++;
      }
      tm = 0;
      blink = 0;
    }
    btn_1 = 1;
  }else btn_1 = 0;

  if(state == 0){ //ZEIT LAEUFT
    if(tm >= SECOND){
      seconds+=tm/SECOND;
      tm = tm%SECOND;
      changed = 1;
    }
    if(seconds >= 60){
      minutes += seconds/60;
      seconds = seconds%60;
    }
    if(minutes >= 60){
      hours += minutes/60;
      minutes = minutes%60;
    }
    if(hours >= 24){
      hours = 0;
    }
  }else{ //UHR STELLEN
    if(tm>=500){
        blink = blink?0:1;
        tm = 0;
        changed = 1;
      }
    if(digitalRead(10) == LOW){
      if(!btn_2){
        changed = 1;
        switch(selP){
          case 0: 
            hours+=10;
            if(hours >= 24) hours -= 20;
            break;
          case 1:
            if(hours/10 < 2){ //in else case zaehlt man die 2. Ziffer nur noch bis 3, da 24 kein Bestandteil mehr ist
              if(hours%10 == 9){
                hours-= 9;
              }else hours++;
            }else{
              if(hours%10 == 3){
                hours-= 3;
              }else hours++;
            }
          break;
          case 2:
            minutes+=10;
            if(minutes >=60) minutes = 0;
          break;
          case 3:
             if(minutes%10 == 9){
              minutes-= 9;
            }else minutes++;
        }
      }
      btn_2 = 1;
    }else btn_2 = 0;
  }
  if(changed){
    led01 = hours/10;
    led02 = hours%10;
    led11 = minutes/10;
    led12 = minutes%10;
    byte str[4];
    str[0] = numbers[led01];
    str[1] = numbers[led02];
    str[2] = numbers[led11];
    str[3] = numbers[led12];
    if(blink){
      str[selP]=str[selP]|(1<<3);
    }
    digitalWrite(ST_CPH1, LOW);
    shiftOut(DATAH1, SH_CPH1,MSBFIRST, str[0]);
    digitalWrite(ST_CPH1, HIGH);

    digitalWrite(ST_CPH2, LOW);
    shiftOut(DATAH2, SH_CPH2,MSBFIRST, str[1]);
    digitalWrite(ST_CPH2, HIGH);

    digitalWrite(ST_CPM1, LOW);
    shiftOut(DATAM1, SH_CPM1,MSBFIRST, str[2]);
    digitalWrite(ST_CPM1, HIGH);

    digitalWrite(ST_CPM2, LOW);
    shiftOut(DATAM2, SH_CPM2,MSBFIRST, str[3]);
    digitalWrite(ST_CPM2, HIGH);
  }
}

, 👍1

Обсуждение

Я измерил время с помощью таймера, и время между двумя минутами кажется ровно минутой. Так почему же первоначальная разница?, @Sprinklerkopf

Может быть, вы могли бы упростить свой код, используя [RTC_Millis()](https://adafruit.github.io/RTClib/html/class_r_t_c___millis.html), который уже реализует логику часов на основе millis ()., @Edgar Bonet


1 ответ


1

Я не вижу в этом коде ничего, что позволяло бы вам устанавливать время. Вы устанавливаете его, жестко кодируя цифры. Это нормально, но для компиляции и загрузки на плату требуется некоторое время, и плата начнется в то время, когда вы жестко запрограммированы. Если плата не сможет запустить программу в течение нескольких секунд во время загрузки, то, очевидно, она будет отключена на несколько секунд.

Будет почти невозможно точно угадать, в какое время программа начнет работать. Возможно, вы могли бы установить время на несколько минут в будущем, загрузить, а затем отключить и подождать ровно до этого времени, чтобы подключить плату и запустить ее. Помните, что у загрузчика есть пара секунд, прежде чем программа начнет работать. Это может потребовать некоторых проб и ошибок.

Или вы можете написать там код, который позволяет вам устанавливать время через последовательный монитор или что-то в этом роде.

,

Мне кажется, что конструкция "switch" / "case" заключается в установке времени с помощью кнопок., @Edgar Bonet

Ну ладно. Теперь я понимаю эту часть. Там я запутался. Удалите ответ, я думаю., @Delta_G

Извините, я студент - IT и привык писать код, а не строить вещи- так что да, вот почему мой код такой грязный :) . Таким образом, вы говорите, что глобальный статический long last = millis() имеет значение из-за времени запуска? могу ли я предотвратить это, поставив его в конце setup()? Я также мог бы установить его в первой итерации цикла, @Sprinklerkopf

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