Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Здесь пришлось оформить чтение из часов отдельно, прямым обращением к процедурам обмена через 12С (см. файл i2c.prg в приложении 3), т. к. часы имеют специальный и очень удобный протокол. Если вы им один раз даете команду на чтение (значение адреса Oblioioooi), то они начинают выдавать последовательно все значения регистров, начиная с того, к которому было последнее обращение прошлый раз. Здесь мы начинаем с регистра секунд и заканчиваем регистром года. Чтобы остановить выдачу, нужно в последнем чтении не выдавать подтверждение (АСК).

Прочитанные значения складываются в память (в исходном BCD-виде), и отдельно, в процедуре Rclockini, распаковываются для индикации. Об индикации мы тут подробно говорить не будем, вы уже знаете, как ее организовать (см. главу 8), остановимся на применении полученных значений времени для наших целей своевременной записи температуры и давления.
Сначала нам потребуется еще обеспечить ход времени в МК (в память МК должны все время попадать текущие значения времени) и научиться устанавливать часы: пока мы их только "заводили" и устанавливали секунды. Тут следует сказать несколько слов о том, как, наилучшим образом организовать совместную работу часов и МК. Можно, конечно, при каждом обновлении времени (у нас — каждую секунду) просто "тупо" читать значения из RTC, но это нецелесообразно со многих точек зрения: процедура долгая (несколько миллисекунд займет), и к тому же только в одном случае из 60 меняются не только значения самих секунд, но и старшие единицы. Зачем занимать МК пустыми действиями? Поэтому мы поступим так же, как это делается в ПК — в МК, пока он нормально работает, время будет отсчитываться само по себе, но не по его внутренним прерываниям, а по прерыванию от часов, тогда показания будут строго синхронизированы. А полностью время читаем из часов только при запуске МК в процедуре RESET, ну и еще в ситуации, если нам зачем-нибудь приходится запрещать прерывания (например, во время длинной процедуры чтения значений из внешней памяти). Отдельно необходимо вести календарь: чтобы не загромождать программу (календарь — довольно громоздкая штука), для этого можно обновлять значения даты чтением из часов, например, ежесуточно в полночь.

Более того, при таком подходе мы в принципе имеем возможность автоматического исправления ошибок самих часов: достаточно включить сторожевой таймер (см. главу 14), который бы отслеживал наличие внешнего прерывания, и если оно по каким-то причинам не наступило, реинициализировать часы, пользуясь значениями времени из МК. Реализацию этой идеи я оставляю читателям (для этого необходимо на случай сбоя сохранять текущие значения времени-даты в EEPROM).

Для счета времени установим отдельный регистр-счетчик секунд и запомним, что его нельзя трогать:
.def count sek = г2б ;счетчик секунд

Стоило бы начать с последней задачи — как установить нужное время, но мы ее разберем в главе 13, когда будем говорить про обмен через UART. Предположим, что часы установлены и идут сами по себе, в памяти МК имеются значения времени, записанные туда при установке, есть еще регистр countsek, в котором отдельно хранятся значения секунд в нормальном (а не BCD) цифровом формате. Осталось заставить МК отсчитывать время — сам контроллер никогда не "узнает", который сейчас час.

Для этого мы и припасли прерывание от часов, происходящее раз в секунду. Отключим опять Timerl, и оставим инициализацию TimerO (ldi temp, (I«TOIEO) и out TiMSK,temp). В секции прерываний для внешнего прерывания INT 0 (во второй строке, сразу после rjmp RESET) поставим rjmp EXTINTO, а в начальную загрузку впишем инициализацию внешнего прерывания INTO (листинг 12.9).

Листинг 12.9
;==*=== внешнее прерывание INTO
ldi temp, (1«ISC01) /прерывание. INTO по спаду
out MCUCR,temp
ldi temp, (1«INT0) /разрешение. INTO out GICR,temp
ldi temp,$FF /на всякий случай сбросить все прерывательные флаги out GIFR,temp

Запись данных
Теперь, если часы работают, у нас каждую секунду будет происходить прерывание INT 0. В нем мы сначала займемся счетом времени, а потом записью во внешнюю flash-память каждые три часа. Для этого придется организовать довольно громоздкую процедуру сравнения времени с заданным. В нашем измерителе мы будем писать с т. н. метеорологическим интервалом — каждые три часа, начиная с нуля часов.
Но писать в память в определенные моменты времени — это еще не все. Метеоданные имеют смысл, только если они привязаны к абсолютному времени. Если же мы будем просто заполнять память, как сейчас, то при чтении данных мы не узнаем, когда именно была произведена первая запись. Но даже если мы запишем время включения прибора на бумажке (точно, зная интервал, остальные кадры нетрудно привязать к абсолютному времени), то учесть отключения питания мы все равно не сможем. Зачем тогда было придумывать такой хитрый механизм сохранения адреса при сбоях?

Но и сохранять в памяти время каждого измерения нецелесообразно — оно займет минимум 5 байтов, в нашем случае больше, чем сами данные. Поэтому мы поступим следующим образом: при начальной загрузке устанавливаем некий флаг (назовем его "флаг первичной записи"), который покажет, что это первая запись после включения питания:

/установка флага первичной записи
sbr Flag,8 ;бит 3 регистра Flag



     
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru