Юрий Ревич - Занимательная микроэлектроника
- Название:Занимательная микроэлектроника
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2007
- Город:Санкт-Петербург
- ISBN:978-5-9775-0080-7
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Юрий Ревич - Занимательная микроэлектроника краткое содержание
Для широкого круга радиолюбителей
Занимательная микроэлектроника - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
def count_sek = r26;счетчик секунд
Теперь начнем с последней задачи: как установить нужное время? Для этого напишем процедуру (листинг 16.15), которая будет вызываться из компьютера по команде $A1. А по команде $А2будем читать значение часов.
Листинг 16.15
…
Gcykle
cpi temp,0xA1 ;установить RTC + 6 байт BCD, начиная с секунд
breq ргос_А1
cpi temp,0xA2 ;читать часы в комп.
breq ргос_А2
…
rjmp Gcykle
proc_A1: ;А1 установка часов
rcall SetTime
rjmp Gcykle
proc_A2: ;А2 читать часы в комп. из памяти
rcall ReadTime;
rjmp Gcykle
…
;Процедура преобразования BCD в HEX, специально для времени HEX_time:
;на входе в ZL адрес секунды, часы или минуты на выходе в temp hex-значение,
ld temp,Z;
andi temp,0b11110000 ;распаковываем — старший
swap temp ;старший в младшей тетраде
mul temp,mult10 ; умножаем на 10 в r0 результат
ld temp,Z;
andi temp,0b00001111 ; младший
add temp,r0 ;получили hex
ret
Sclock: ;получить из компьютера 6 байт и записать в память
ldi ZH, 0x01 ;старший RAM
ldi ZL,Sek ;Ram
rcall in_com
st Z+,temp ;sek
rcall in_com
st Z+,temp ;min
rcall in_com
st Z+,temp ;hour
rcall in_com
st Z+,temp ;data
rcall in_com
st Z+,temp ;month
rcall in_com
st Z,temp ;year
push cnt ;сохраняем cnt на всякий случай
rcall SetClk ;переписываем в часы
pop cnt
ret
Setclk: ;установить часы
sbis PinC,pSDA ;линия занята
rcall err_i2c
ldi ZH,0x01
ldi ZL,Sek ;адрес секунд в памяти
ldi ClkA,0 ;регистр секунд ld DATA,Z+ ;извлекаем секунды
rcall write_i2c ;секунды записываем
brcs stops
ldi ClkA,1 ;регистр минут
ld DATA,Z+ ;извлекаем минуты
rcall write_i2c ;минуты записываем
brcs stopS
ldi ClkA,2 ;регистр часов
ld DATA,Z+
rcall write_i2c ;записываем часы
brcs stopS
ldi ClkA,4 ;регистр даты (день недели пропускаем)
ld DATA,Z+
rcall write_i2c ;записываем дату
brcs stopS
ldi ClkA,5 ;регистр месяца
ld DATA,Z+
rcall write_i2c ;месяц записываем
brcs stopS
ldi ClkA,6 ;регистр года
ld DATA,Z
rcall write_i2c ;год записываем
brcs stopS
ldi ClkA,7 ;регистр установок — на всякий случай
ldi DATA, 0Ь00010000
rcall write_i2c
brcs stopS
ldi temp,$AA ;все отлично
rcall out_com
ret
stopS:
ldi temp,$EE ;подтверждение не получено
rcall out_com
ret
SetTime: ;установка текущих значений в МК
cli
rcall Sclock ;записали из компьютера BCD-значения
ldi ZL,Sek ;упакованные секунды
rcall HEX_time ;имеем hex-секунды в temp
mov count_sek,temp ;переписываем в счетчик
;далее распаковываем для индикации: часы-минуты
ldi ZL,Hour ;распакованные в память
ld temp,Z
mov data,temp
andi temp,0b00001111 ;младший часов
ldi ZL,DeH
st Z,temp
andi data, 0b11110000 ;старший часов
swap data ;старший в младшей тетраде
ldi ZL,DdH
st Z,data
ldi ZL,Min ;распакованные в память
ld temp,Z
mov data,temp
andi temp,0b00001111 ;младший минут
ldi ZL,DeM
st Z,temp
andi data,0b11110000 ;старший минут
swap data ;старший в младшей тетраде
ldi ZL,DdM
st Z,data
sei
ret
ReadTime: ;чтения часов из памяти в порядке ЧЧ: ММ ДД. мм. ГГ
cli
rcall ReadClk ;сначала читаем из часов
ldi ZH,1 ;старший RAM
ldi ZL,Hour
ld temp,Z
rcall out_com ;hour
ldi ZL,Min
ld temp,Z;
rcall out_com ;min
ldi ZL,Sek
ld temp,Z;
rcall out_com ;sek
ldi ZL,Date
ld temp,Z+;
rcall out_com ;data
ld temp,Z+;
rcall out_com ;month
ld temp,Z;
rcall out_com ;year
sei
ret
Как видите, довольно длинно получилось, но ничего не поделаешь. Теперь мы находимся в следующей ситуации: часы установлены и идут сами по себе, в памяти МК имеются значения времени, которые туда записали при установке, есть еще регистр count_sek, в котором отдельно хранятся значения секунд в нормальном (а не BCD) цифровом формате. Осталось заставить МК отсчитывать время — сам по себе контроллер никогда не «узнает», который сейчас час.
Для этого мы и припасли прерывание от часов, которое происходит раз в секунду. В принципе мы могли бы каждое это прерывание читать значения времени из часов процедурой ReadClk, но это неудобно, т. к. процедура длинная и будет тормозить индикацию. Даже в ПК так не делали — там время отсчитывается BIOS при включенном компьютере самостоятельно. И нет никакой нужды этим заниматься, если мы можем считать время в МК: синхронизацию значений мы при включении питания или при установке часов делаем, а синхронизация хода часов обеспечена тем, что прерывания управляются от RTC. А считать секунды, минуты и часы совсем нетрудно и много времени не займет. Календарь же нам вести в МК не требуется, мы его правильный отсчет получим при чтении из устройства за счет того, что предварительно обновляем значения в памяти процедурой ReadClk(см. процедуру ReadTime в листинге 16.15).
Итак, вычеркнем опять из начального запуска процедуру инициализации Timer 1 (всю секцию Set Timer 1, вернув вместо нее ldi temp, (1<и out TIMSK, tempдля инициализации только Timer 0, см. первоначальный текст в Приложении 5 ), уберем из текста обработчик прерывания TIM1_COMPAи вместо ссылки rjmp TIM1_COMPAв секции прерываний опять поставим команду reti.
Вместо этого в секции прерываний для внешнего прерывания INTO (во второй строке, сразу после rjmp RESET) заменим retiна rjmp EXT_INTO, а в начальную загрузку впишем инициализацию внешнего прерывания INTO:
;====== внешнее прерывание INTO
ldi temp,(1< ;прерывание. INTO по спаду
out MCUCR,temp
ldi temp,(1< ;разрешение. INTO
out GICR,temp
ldi temp,$FF ;на всякий случай сбросить все флаги прерываний
out GIFR,temp
Теперь, если часы работают, у нас каждую секунду будет происходить прерывание INTO. В нем мы сначала займемся счетом времени, а потом записью во внешнюю flash каждые три часа. Для этого нам придется организовать довольно громоздкую процедуру сравнения времени с заданным. В нашем измерителе мы будем писать с т. н. метеорологическим интервалом (каждые три часа, начиная с 0 часов).
Читать дальшеИнтервал:
Закладка: