proc_F0: ;F0 запись flash разрешить
rcall EnableFlash
rjmp Gcykle
proc_F1: ;F1 запись flash запретить
rcall DisFlash
rjmp Gcykle
…
EnableFlash:
cli
;сначала проверяем бит «конец памяти»
sbrc Flag,2
rjmp exit_FE
;проверяем байт разрешения, если нет, пишем его в память
ldi ZH,1 ;старший RAM
ldi ZL,FEnRAM
ld temp,Z
cpi temp,$FF
breq exit_FA
ldi temp,$FF
st Z,temp
clr ZH ;старший EEPR
ldi ZL,FEnEE
rcall WriteEEP
ldi temp,$AA ;все Ok
rcall out_com
sei
ret
exi t_FA:
ldi temp,$FA ;ответ в комп. — уже разрешен
rcall out_com
sei
ret
exit_FE:
ldi temp,$FE ;ответ в комп. — конец памяти
rcall out_com
sei
ret
DisFlash:
cli
clr temp
ldi ZH,1 ;старший RAM
ldi ZL,FEnRAM
st Z,temp
clr ZH ;старший EEPR
ldi ZL,FEnEE
rcall WriteEEP
ldi temp,$AA ;ответ в комп. — все Ok
rcall out_com
sei
ret
Мы используем запрещение прерываний, потому что процедуры достаточно долгие и запросто можно «испортить» temp по ходу дела, а здесь это уже недопустимо. Кроме того, они включают запись в EEPROM, во время которой прерывания надо все равно запрещать. Из этих процедур мы также видим, зачем нам понадобился отдельный флаг «конец памяти» — если он установлен, то разрешить запись будет нельзя. Это можно будет сделать только одновременно со сбросом адреса, что необратимо, и данные после этого уже прочесть будет нельзя. Потому мы сначала займемся их чтением (листинг 16.9).
proc_F2: ;F2 читать flash
rcall ReadFullFlash
rjmp Gcykle
…
ReadFullFlash:
cli
mov YH,AddrH ;сохраняем текущий адрес в Y
mov YL,AddrL
clr AddrL ;чтение начнем с начала памяти
clr AddrH
loopRF:
cp AddrL, YL ;не дошли ли до текущего
срс AddrH, YH
breq end_RF ;если дошли, то конец чтения
rcall ReadFlash ;собственно чтение
mov temp,DATA ;данные из DATA в temp
rcall out_com ;передаем наружу
adiw AddrL,1 ;следующий адрес
rjmp loopRF
end_RF:
mov AddrH,YH ;восстанавливаем текущий адрес
mov AddrL,YL
sei
ret
Процедура эта будет долгой, если записан сколько-нибудь существенный кусок в памяти (для передачи 32 кбайт со скоростью 9600 потребуется порядка полминуты, да еще и чтение по I2С), и на все это время прерывания будут запрещены. Для нашего измерителя это выльется только в исчезновение на это время индикации, но могут быть ситуации, когда следует предотвратить выключение контроллера на такое время — например, чтобы не потерять данные, когда настанет момент очередной записи. В дальнейшем мы учтем этот момент (хотя это, как вы увидите, сильно усложнит программу). А пока
proc_F8: ;F8 clear address
rcall ClearAddr
rjmp Gcykle
…
ClearAddr:
cbr Flag,4 ;обнуляем бит конец памяти
clr AddrH ;обнуляем адрес
clr AddrL
clr ZH ;и записываем его в EEPROM
ldi ZL,EaddrL
mov temp,AddrL ;можно и просто clr temp
rcall WriteEEP
inc ZL
mov temp,AddrH
rcall WriteEEP
ldi temp,$AA ;ответ в комп. все Ok
rcall out_com
sei
ret
Теперь у нас есть измеритель температуры и давления, записывающий данные во внешнюю память, откуда они могут быть прочитаны в любой момент. В