Использование millis() для отчета времени

Тема в разделе "Arduino & Shields", создана пользователем Alexium, 12 сен 2014.

  1. Alexium

    Alexium Нуб

    Хочу использовать функцию millis() для синхронизации времени через заданный интервал. К самой синхронизации вопросов нет. Использую GPRS-шилд и регулярно снимаю с него время командой AT+CCLK?. Все работает, как надо, но... Боюсь, проблемы, с которыми я столкнулся, когда попытался сделать ежечасовую синхронизацию с помощью отсчета прошедшего количества миллисекунд, выходят за пределы моих скромных познаний в электронике. Если кратко, то в одной секунде не 1000 миллисекунд, а чуть больше 1002. Я бы хотел попросить вас подсказать мне максимально точное число, основанное на характеристиках контроллера Arduino Uno или на тонкостях функционирования программ.

    Подробнее.
    Если я использую каноничные значения, то Ардуино производит синхронизацию времени несколько раньше, чем нужно. Путем приблизительных расчетов сделал вывод, что погрешность составляет примерно 125 миллисекунд на минуту или секунда в 8 минут. Соответственно на уровне часа отставание уже больше (примерно 7 секунд). Хотя код способен самоподстраиваться и в целом погрешность не будет выходить за пределы часа, хотелось бы заставить Ардуино более точно отсчитывать время.

    Про код.
    На этапе setup я провожу первичную синхронизацию времени вышеназванной командой, вывод которой переводится в int формат и вставляется в формулу определения времени, прошедшего с начала часа:
    Код (Text):
    synchTime = (unsigned long) ((m[0]-'0')*10+m[1]-'0')*60*1000+((s[0]-'0')*10+s[1]-'0')*1000;
    Затем высчитывается, сколько осталось времени до конца часа:
    Код (Text):
    synchPeriod += 3600000UL-synchTime;
    // += Потому что ранее в теряется секунда на delay и она там же компенсируется
    // увеличением значения synchPeriod на 1000
    И полученное значение используется в условии:
    Код (Text):
    if (currMillis - synchMillis >= synchPeriod){
    synchMillis = currMillis;
    // Здесь повторяется код для синхронизации, но только synchPeriod
    // задается уже конктретно 3600000, а не прибавлением.
    // Потерянная секунда почему-то перестает играть роль
    }
    К функционированию кода претензий нет. Они есть к моменту срабатывания условия.
     
  2. Pi-Tone

    Pi-Tone Нерд

    на счет 1002 милисекунды. единица измерения 1 секунда = 1000мс. А в ардуино эта частота я так понимаю задается кварцем на 16mhz, у этих кварцевых резонаторов есть своя погрешность, вот эта погрешность и дает о себе знать
     
  3. Alexium

    Alexium Нуб

    А поточнее определить эту погрешность можно? Гуглил, но ничего понятного не нашел.

    Кстати, у меня там выше в коде ляп: перевод символа в int неправильно работал из-за кривого задания unsigned long. Исправился.
     
  4. Pi-Tone

    Pi-Tone Нерд

    я не уверен но я так понимаю что эта погрешность в каждом резонаторе своя. у кого то быстрее на доли мегагерц у кого то медленее и в итоге у одного 1 секунда (реального времени) = 998мс, а у кого то 1002.
     
    Alexium нравится это.
  5. Megakoteyka

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

    Можно подстроечным кондером подгонять частоту в небольших пределах.
     
  6. Unixon

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

    У кварцев настройка точнее, так не должно быть. Там типичные значения погрешности 10^-6 ~ 10^-9. т.е. за одну секунду они могут уйти максимум на такт, но никак не на несколько миллисекунд, это же не керамические резонаторы с точностью 10^-3 и тем более не 5% конденсаторы.
     
  7. geher

    geher Гуру

    В реальности погрешность частоты может определяться емкостью в цепи резонатора. А это может быть в итоге и больше 5% конденсатора.