Real time clock windows
В статье описан пример работы с внешним устройством в операционной системе Windows 10 Iot. В качестве компьютера, поддерживающего Windows 10 Iot, использована плата Raspberry PI 2-3. А подключать будем микросхему часов реального времени DS-3231 по интерфейсу I2C. В проекте реализуем возможность устанавливать время и дату, а также считывать текущие значения и выводить их на экран.
Краткое описание возможностей микросхемы:
- поддерживает 24 часовой формат и 12 часовой (AM/PM);
- ведет счет дня недели;
- имеется будильник 2 шт.;
- встроен датчик температуры с разрешением 0.25°;
- есть вывод — триггер для внешних устройств.
Передача даты и времени происходит в двоично-десятичном формате. Двоично-десятичный код— форма записи чисел, при которой каждый десятичный разряд числа (цифра) записывается в виде его четырёхбитного двоичного кода. Например, десятичное число 31110 будет записано в двоично-десятичном коде как 0011 0001 0001BCD. Этот формат используется, потому что это упрощает вывод чисел на индикацию — вместо последовательного деления на 10 (для выделения цифры в десятичном числе) требуется просто вывести на индикацию каждый полубайт. Аналогично, проще ввод данных с цифровой клавиатуры. (Wikipedia)
Для начала нужно подключить DS-3231 к Raspberry PI согласно схеме.
Приступим к коду. Подключаем пространство имен и создаем необходимые переменные.
Создаем метод, в котором настраивается подключение DS-3231 к I2C интерфейсу
Далее – метод настройки таймера
Создаем событие загрузки формы и прописываем в нем инициализацию I2C, таймера и переменных
Пройдемся по выше описанному событию и рассмотрим, что там происходит
- Инициализируем массивы и структуру
- Настраиваем I2C
- Настраиваем таймер
Далее все внимание переключаем на событие таймера
Рассмотрим метод, считывающий с микросхемы температуру
На картинке мы видим, как располагаются данные в регистрах по адресу 0x11, 0x12.
Вроде с температурой разобрались, теперь переходим в времени и дате. Разберем метод GetData();
В методе GetData(); есть три незнакомых метода, рассмотрим их по порядку.
Рассмотрим метод ConvertBcdToDec();
Допустим, на вход метода поступает двоично-десятичное число 0011 0001BCD. Как видно, это число 3110. Разберем, как метод получит ответ 31.
Первое действие – (data >> 4) – это сдвиг вправо на 4, после него от числа останется 0000 00112 (или 310).
Полученное число умножается на 1010 – результат 3010.
Следующее действие — (0x0F & data) – это побитовое И чисел 0000 11112 и 0011 00012. В итоге получим 0000 00012 (или 110).
Последнее действие – складываем 3010 и 110, получаем 3110. Готово.
Теперь Вам не составит труда разобрать метод, который, наоборот, конвертирует данные из десятичного в двоично-десятичный формат
Далее метод, который возвращает день недели
Ну вот собственно и все готово для считывания времени, даты, дня недели и температуры.
Еще нужно рассмотреть, как устанавливать время и дату, для этого добавим на форму кнопку, обработчик события по нажатию на кнопку будет выглядеть так
Далее рассмотрим сам метод SetDateTime();
Ну вот мы и рассмотрели, как формируются и передаются/принимаются данные.
Проект можно скачать по ссылке
Real time clock windows
Здравствуйте.
Вопрос такого плана: какова предельная точность таймера, работающего на винде ?
Вопрос может не точный/не понятный .
Суть — на шарпе я добился точности счёта в 100 мкс. Хочу выше. Какой предел ? Как добиваться ?
Это зависит от того как эту точность мерить.
В системе есть несколько таймеров.
RDTSC
RTC
PM-Timer (ACPI-timer)
PIT
Дискретность, то с какой частотой отдаёт счётчик таймер.
PIT(i8254) — PROGRAMMABLE INTERVAL TIMER, программируемый интервальный таймер
В таймере есть три канала, которые можно запрограммировать на разные режимы. Такой таймер может выдавать импульс или генерировать прерывания с частотой p/M
где M константа от 1 до 65536. p= 1,19318 МГц – стандартная =f/12 – реальная частота
Значение после сброса для M=65536 пропусков, отсюда
F= р/65536 =18,2065074 Гц
PM TIMER(ACPI TIMER)
PM-Power Manadger
Устройство контроля энергии энергосберегающего контроля питания и аварийного отключения имеет два встроенных счетчик для обеспечения своих нужд по обработки прерываний. Счетчик этот специфический и не имеет строгого адреса он не позволяет вызывать прерывания IRQ но служит таймером высокой частоты. Этот таймер вызывает SMI прерывания. Которые в свою очередь обрабатывается БИОС’ом в специальном режиме процессора SMM. SMI имеет наивысший приоритет среди прерываний. Для реализации ОС реального времени нет ничего страшнее SMI. Он сбивает обработку других таймеров. Но его можно отключить.
APIC TIMER
APIC расширенный контролер прерываний он снабжен таймером с большой частотой. Частота зависит от частоты процессора. Частота делится на константу 2,4,8,16,32,64,128.
HPET — High Precision Event Timers
Частота у HPET больше чем у PIT(i8254). Позволяет подменить каналы старого таймера PIT(i8254). частота стандартная 14,31818 и может быть выше константа считывается.
RTC — Real Time Clock, часы реального времени.
Компьютер снабжен часами и батарейкой. На старых компьютерах такого не было. И каждый день начинался с чистого листа. Оператор включал электронную вычислительную машину и вводил дату и время. С появлением RTC все стало проще. Теперь компьютер умный он научился сам узнавать время. RTC подключен к генератору с частотой 32.768 КГц. Но сам генерирует прерывания с частотой в зависимости от делителя от 2Гц до 8КГц через степень двойки.
——————————————————
RDTSC — частота порядка 2٫4 ГГц
Частота в большинстве компьютеров постоянна, не меняется во время работы.
Дискретность 4-16 тактов процессора. Что равносильно 1-7 нс.
RTC
Опорная частота 32.768 КГц
Дискретность по умолчанию 1024 Гц. Что равносильно 0,9765625 мс.
PM-Timer (ACPI-timer)
Опорная частота 3,579545 МГц.
Дискретность по умолчанию 3,579545 МГц. Что равносильно 279 нс.
PIT
Опорная частота 1,1918 МГц.
Дискретность от 1/1193180 до 65536/1193180. В зависимости от ОС и её настроек.
65536/1193180 = 54٫92 мс (или 18٫2 Гц).
18076/1193180 = 15٫149432 мс (или 66٫009 Гц).
1193/1193180 = 0٫9984 мс (или 1000 Гц).
Теперь про ошибки PPM это сколько раз кварцевый резонатор ошибётся на 1 милион раз. В ЭВМ типично стоит 2 резонатора.
Один питает RTC другой питает всё остальное.
Тот который стоит в RTC имеет точность 100-150 ppm
Тот который питает PIT и всё остальное имеет порядка 30-50 ppm.
Чем больше температура тем больше ошибок делает кварцевый резонатор.
Точность. Что определяет точность? Точность определяет число значащих цифр в числе и чем их больше, тем точнее число. Точнее таймер
0,5/1431818=0,000000349=0,35*10^-6 это значит, что ошибка будет проявляться через 1 миллионов итераций
0,5/14318=0,35*10^-4 при такой точности ошибка будет заметна при 10 тыс. итераций
0,5/32768=0,15*10^-4 аналогично.
Цифры цифрами, но что они значат в реалии? В стуках 60*60*24=86 400 секунд
Это цифра превышает 10 тыс. Это значит что ошибка в сутках для RTC
,будет составлять 0,15*10^-4*86400=1.32 c.
Тут было выбрано абсолютная ошибка 0,5 из расчета того, что таймер генерирует с заданной частотой. На самом деле это не совсем так погрешность любого кварцевого генератора составляет 30-50 миллионных, для более точных на порядок.
И того имеем погрешность
30*10^-6*86400=2.6 с
50*10^-6*86400=4.32 с
Практика показывает, что оно так и есть ошибка порядка 3,5-4,5 с
Ошибка носит систематический характер.
За неделю набегает полминуты 4*7=28 с.
Почему мы не видим эту ошибку? Всё очень просто каждый день раз в 4 часа виндоус обращается к серверу времени и проводит синхронизацию ваших часов. Сервер времени подключён к системе единого времени(СЕВ)
Все часы в мире ежедневно подстраиваются от часов с атомным стандартом частоты. Эти специальные часы имеют ошибку 10^-14. Для наглядности 1 ppm это 10^-6
Функции FileTime(), DateTime() — как правило привязаны к RTC. Имеют точность 1 секунда.
GetTickCount() — привязан к PIT. Всегда имеет усредненную точность 15٫16 мс (там периодическая последовательность dT = 15 15 15 15 15 16 мс). Тут под словом всегда имеется в виду что в ходе моих экспериментов расхождений не выявлено.
Для игр стоит использовать мультимедийный таймер функции timeGetTime(), timeKillEvent(), и timeSetEvent(). Он уже будет гарантированно работать с точностью 15,16 мс. И при настройке системы 1 мс.
timeBeginPeriod(1); // Устанавливаем время срабатывания мультимедийного таймера в 1мс
Этот параметр влияет на все программы в ОС. Так что не удивляйтесь если другая программа сделала это раньше вас.
Функции
QueryPerformanceFrequency(Freq);
QueryPerformanceCounter(Coun1);
Эти функции привязываются к самому быстрому таймеру по версии ОС и не зависят от частоты процессора. Встречал разные варианты, всё чаще последний вариант.
PIT, ACPI-Timer, APIC-Timer (для краткости аналог RDTSC).
ассемблерная команда
asm
RDTSC
end;
На разных ядрах счётчики RDTSC несинхронны. Поэтому если ОС решит перекинуть вас с ядра на ядро то разница RDTSC()-LastTime может оказаться отрицательной.
Я уже писал о дискретности в 2 нс. Так вот при включении виртуализации значения этого счётчика можно перепрограммировать как захочет гипервизор. Обычно виртуальные машины перехватывают обращение к этому таймеру и его дискретность доходит снижается до 1-10 мкс.
RDP dog
Компьютерные часы
Итак, нас интересует учет и использование времени на компьютерах или точнее на отдельных узлах-будь то персональный компьютер, сервер, виртуальный компьютер или иное устройство которому нужно точное время. Для этого придумали протокол NTP, который мы не будем рассматривать здесь. В основном он использует алгоритм Марзулло, который мы тоже не будем рассматривать здесь.
Так уж повелось, что любой компьютер имеет встроенные часы. В обычном компьютере имеется 2 реализации часов:
- часы реального времени (Real Time Clock — RTC, CMOS clock, hardware clock);
- системные часы (system clock, software clock);
Часы реального времени представляют собой отдельную микросхему, питающуюся от литиевой батарейки (от нее питается также CMOS, хранящий настройки BIOS), и работают независимо от того, включен компьютер или нет. Физически RTC состоят из тактового генератора (кварц) и запоминающего устройства (микросхемы, участка памяти) куда периодически записываются значения времени (точнее количество «тиков»).
Большинство RTC использует кварцевый резонатор, но некоторые используют частоту питающей сети!
Узлу(компьютеру) удобнее отсчитывать время в промежутках (секундах, которые формируются из тактов, генерируемых кварцем и измеряемых в герцах). Стабильность частоты типичного кварцевого генератора невелика (например, зависит от температуры, напряжения, механических деформаций и т.д.), к тому же базовая частота меняется от кристалла к кристаллу (что может приводить к уходу системных часов на 40 секунд в день). В большинстве случаев используется кварцевый резонатор на частоте 32768 Гц. Та же частота используется в кварцевых часах. Такая частота обеспечивает 2 15 циклов в секунду, что очень удобно для простых двоичных счётчиков.
За работу системных часов отвечает операционная система. И здесь мы сталкиваемся с первой проблемой- во время работы системы она выполняет множество задач. В результате чего, при сильной загрузке процессора операционная система просто не успевает точно вести часы. Часы начинают отставать. Именно поэтому необходима синхронизация времени и согласование RTC и SYS.
Согласование хода аппаратных и системных часов увеличивает точность хода, но недостаточно для некоторых задач. Системные часы серверов должны быть согласованы (синхронизированы) между собой с большой точностью (при небольшой загрузке — доли секунды), иначе невозможно отслеживать последовательность событий, разбирать журналы сообщений и т.д. Чем больше плотность событий (загрузка сервера), тем более точной должна быть синхронизация. При синхронизации обычно используется система времени UTC.
ОС при загрузке считывает текущее время из RTC, после чего ведет свой счетчик времени (системные часы) самостоятельно основываясь на подсчете количества специальных регулярных прерываний (timer interrupt), обычно 100 Гц (1024 Гц). Системное время обслуживается ядром ОС. Системное время выражается в числе секунд (или микросекунд или наносекунд) после 00:00:00 1 Января 1970 года (Linux) или после 1 Января 1601 (Windows). Эти даты называются началом Эры (Epoch). Эра это базовая дата, от которой ведется отсчет времени узлом. RTC может использовать свою базовую дату, установленную производителем BIOS или производителем самой платы.
Чтение и запись RTC, согласование RTC и системного времени осуществляются как BIOS так и ОС.
Учитывая частоту обновления счетчика «тиков» времени RTC имеют точность в районе 1 секунды, а системные часы могут иметь точность до 1 мс.
Таким образом, показания этих часов могут и будут отличаться друг от друга (и от реального времени).
А реальное время, как говорилось первой части, мы сами себе выдумали. J
В Windows, например, разница между RTC и SYS может составлять не больше 1 минуты, в случае превышения этого лимита ОС корректирует значение RTC по значению SYS. Где находится настройка этого интервала неизвестно.
Каждый раз перед выключением демон hwclock сравнивает аппаратное и системное время (последнее принимается за наиболее точное) и вычисляет погрешность аппаратных кварцевых часов в день. Вычисленное значение погрешности записывается в файл /var/lib/hwclock/adjtime . Если hwclock не использовался больше суток, то он, на всякий случай, вычисляет новое значение погрешности.
Специальный скрипт корректирует аппаратные часы в соответствии с вычисленной погрешностью каждый час. Если вы видите, что ваши аппаратные часы идут все более и более неверно, то, вероятнее всего, в файле /var/lib/hwclock/adjtime записано неверное значение погрешности.
Это происходит если на аппаратных часах время изначально было установлено неверно или ваш временной стандарт (см. выше) не такой как у другой операционной системы, используемой на компьютере. Чтобы исправить это, удалите /var/lib/hwclock/adjtime и настройте время на всех ваших часах.
Системное время рассчитывается ядром, начиная с полуночи первого января 1st 1970 по стандарту UTC. Начальное значение системных часов рассчитываается исходя из показаний часов аппаратных (после корректировки погрешности и пересчета на местный часовой пояс UTC) при включении и идут независимо от аппаратных. Ядро Linux отслеживает системные часы, подсчитывая прерывания таймера. Как и аппаратные, они не являются идеально точными. Иногда системные часы могут потерять точность, если ядро сбрасывает прерывания. Но показания системынх часов можно сделать точными с помощью NTP. NTP будет регулировать частоту прерываний и количество тактов в секунду для уменьшения дрейфа системных часов. Эти значения могут быть скорректированы с помощью приложения adjtimex из AUR.
Производители разработали технологию счетчиков HPET(таймер событий высокой точности), но они не стали популярны по ряду причин.
А для обычных задач вполне подошла бы утилита Clockmon. К сожалению, она была разработана в 2002 году и не работает на x64 системах. Покажу, что она умеет на картинках.
Как видно утилита показывает разницу между RTC и SYS.
Но она также умеет синхронизировать эти часы с точностью до миллисекунды. Причем с заданным интервалом может делать это постоянно.
Жаль, что разработчика программы теперь не найти.
Итак, как уже стало ясно, RTC и SYS работают в явно взаимодействии с друг другом. Общий алгоритм совместной работы часов таков:
Служба Windows Time
Служба времени[W32Time] обеспечивает точность системных часов во время работы Windows. Однако у разных узлов разные требования к точности часов. И первое, что нужно понимать про службу времени Windows то, что она не предназначена для поддержки высокой точности системных часов. Под словами высокая точность предполагается расхождение времени между партнерами около миллисекунды. Служба времени Windows не способна обеспечить точность синхронизации (а не хода часов, час идут довольно точно, если правильно синхронизированы) даже в пределах 1-2 секунд!! Шокированы? Давайте разберемся, почему так.
Во- первых, служба w32time появилась в Windows 2000 для поддержки протокола аутентификации Kerberos v5 и только. Напомню, по умолчанию необходимо обеспечить отклонение времени между контроллерами и членами домена не больше 5 минут. Т.е. системные часы членов домена должны быть не идеально точными, а синхронизированными.
Кстати, в Windows 4.0 и ранее не было поддержки NTP, вместо него использовался протокол SNTP. Для этого использовался предок службы времени- TimeServ.
В общем, в тех.задании не требовалось, разработчики и не сделали. А нам рекомендуют пользоваться сторонними решениями, например списочек поставщиков на сайте Национального института по стандартизации и технологиям
Сама служба представляет собой библиотеку w32time.dll которая реализует все необходимые функции, причем как клиентские, так и серверные. Два в одном, так сказать. По умолчанию серверные функции службы отключены, и узел не выступает как источник времени. Однако если хост- контроллер домена, то служба времени на нем автоматически включена. Часть процесса DCPromo это активация серверной части службы w32time.
В общем, в области службы времени и протокола NTP царит полная демократия, в отличие от доменых политик AD(как мы дальше увидим). Все могут со всеми. Каждый узел выступает и сервером и клиентом(за исключением самого- пре самого точного, да и тот небось синхронизируется с атомами или нейтрино).
Утилиты
Прежде чем мы углубимся в тонкости службы W32Time, давайте познакомимся с утилитами, которые позволяют нам работать с настройками этой службы.
Это Regedit, групповые политики, команда Net time и утилита w32tm.
- Regedit позволяет изменять настройки службы в реестре, т.е. там где они и хранятся, но только для локального компьютера. Конечно можно экспортировать REG-файл или подключиться к удаленному реестру, но сейчас не об этом. Настройки службы хранятся по адресу:
Для того, чтобы настройки возымели результат, необходимо перезапустить службу, или заставить ее перечитать настройки.