Занимательная микроэлектроника — страница 113 из 117

  ;умножаем старший на старший

add temp2,r0  ;4-й разряд нам тут не требуется, но он в r01

ret


bin2BCD16:  ;преобразование 16-разрядного hex в упакованный BCD


;input: hex value low=AregL hex value high = AregH

;output: BCD value digits 1 and 0 ResL

;BCD value digits 2 and 3(=0) ResH

ldi tempi,16  ;Init loop counter

 clr ResH

           clr ResL

           clr ZH  ;clear ZH (not needed for AT90Sxx0x)

bBCDx_1: lsl AregL  ;shift input value

rol AregH  ;through all bytes

rol ResL;

            rol ResH

            dec temp1  ;decrement loop counter

brne bBCDx_2  ;if counter not zero

ret  ;return

bBCDx_2:ldi r30,AtBCD2+1  ;Z points to result MSB + 1

bBCDx_3:

            ld temp, — Z  ;get (Z) with pre-decrement

subi temp, — $03  ;add 0x03

sbrc temp,3  ;if bit 3 not clear

st Z, temp  ;store back

ld temp, Z  ;get (Z)

subi temp, — $30  ;add 0x30

sbrc temp, 7  ;if bit 7 not clear

st Z,temp  ;store back

cpi ZL,AtBCDO  ;done all three?

brne bBCDx_3  ;loop again if not

rjmp bBCDx_1


bin2bcd8:  ;преобразование 8-разрядного hex в неупакованный BCD

;вход hex= temp, выход BCD temp1 — старш.; temp — младш.

;эта процедура работает только для исходного меньше 100

clr tempi  ;clear result MSD

bBCD8_1: subi temp,10  ;input = input — 10

 brcs bBCD8_2  ;abort if carry set

inc temp1  ;inc MSD

rjmp bBCD8_1  ;loop again

bBCD8_2:subi temp, — 10  ;compensate extra subtraction

ret


RESET:  ;точка запуска программы после включения

ldi temp,low(RAMEND)  ;загрузка указателя стека

 out SPL,temp

            ldi temp,high(RAMEND)  ;загрузка указателя стека

out SPH,temp

            ldi temp,1<

            out ACSR,temp  ;выкл. аналог, компаратор на всякий


;установка портов вход-выход

ldi temp,0b00111111  ;разряды

out DDRB,temp

            ldi temp,0b01111111  ;сегменты

out DDRC,temp

            ldi temp,0b10000000  ;знак "минус"

out DDRD,temp


;установка АЦП

ldi temp, 1<

            ;start ADC 1/32 такт = 128 кГц  ;interrupt enable

out ADCSRA,temp


;установка таймера

  ldi temp,0b00000010

             out TCCR0,temp

             ;Timer0 on div 1:8 управление разрядами 2000 Гц


;прерывания

ldi temp,(1<  ;разр. прер. Timer 0

  out TIMSK,temp

             ldi temp,255  ;сбросить все прерывательные флаги

out TIFR,temp

             out GIFR,temp


;начальная установка переменных

  ldi r29,1  ;YH=1, пишем в RAM, начиная с 01:00

clr count

             clr countCyk

             clr cRazr

             clr Flag

             sbr Flag,0x01  ; сначала измеряем температуру


;обнуление рабочих ячеек

clr temp

             ldi r28,Tram  ;Tempr

st Y+,temp

             st Y,temp

             ldi r2 8,Pram  ;Prs

st Y+,temp

             st Y,temp


;запись коэффициентов

ldi r28,tZH  ;начальный адрес

;Z Tempr=471

    ldi temp,High(471)  ;ст.

st Y+,temp

             ldi temp,Low(471)  ;мл.

st Y+,temp


;К Tempr=1020

ldi temp,High(1020)  ;ст.

st Y+,temp

            ldi temp,Low(1020)  ;мл.

st Y+,temp


;Z prs=12

ldi temp,High(12)  ;ст. на самом деле = 0

st Y+,temp

            ldi temp,Low(12)  ;мл.

st Y+,temp


;К prs=916

ldi temp,High(916)  ;ст.

st Y+,temp

            ldi temp,Low(916)  ;мл.

st Y,temp

sei  ;разрешаем прерывания

G_cykle:  ;основной цикл

  rjmp G_cykle


Процедуры обмена по интерфейсу I2С

Протокол обмена I2С и пример его использования описан в главе 16. Процедуры составлены для передачи со скоростью около 100 кГц при тактовой частоте контроллера 4 МГц. При другой частоте контроллера или иной скорости передачи число циклов в процедуре delay, равное 6, следует пропорционально изменить. Например, для частоты кварца, равной 16 МГц и скорости передачи, пониженной до 30 кГц, команду ldi cnt,6 следует заменить на команду ldi cnt,75 (приблизительно). Ошибка в ±50 % в скорости передачи обычно роли не играет. При наличии сбоев увеличивайте число циклов до тех пор, пока связь не установится.

Программа содержит процедуры для двух конкретных устройств: энергонезависимой памяти с интерфейсом I2С (типа АТ24) и часов реального времени (RTC) с таким же интерфейсом (например, DS1307). Процедуры Write-Flash/ReadFlash предназначены для обмена с памятью, процедуры write_i2c/read_i2c для обмена с часами. Примеры их использования см. в главе 16. Для других устройств легко построить собственную процедуру по аналогии, если использовать универсальные процедуры формирования протокола (start, write, read и stop), находящиеся в данном тексте. Исключите ненужные процедуры перед компиляцией программы, чтобы не загромождать память МК.

Текст листинга П5.3 целесообразно скопировать в отдельный файл, и назвать его, например, i2c.prg. Готовый файл i2c.prg также доступен в архиве по адресу http://revich.lib.ru/AVR/ctp.zip, где еще содержится программа для измерителя температуры и давления, обсуждаемая в главе 16. При необходимости использовать эти процедуры в другом устройстве следует отредактировать начальные строки, которые задают выводы МК, задействованные в процессе обмена. В данном случае это биты порта D номер 4 (SCL) и 6 (SDA). Кроме этого, конечно, следует изменить регистры для переменных, если это требуется (и при необходимости число циклов, если частота тактового генератора другая). Файл подключается к вашей программе с помощью директивы. include "i2c.prg"после таблицы векторов прерываний (см. главу 16).

Листинг П5.3

;файл I2С.рrg

;Процедуры чтения и записи по интерфейсу I2C

;+----------- порт D ---------+

.equ pSCL = 4

.equ pSDA = 6

;-------------------------------

.def DATA = r17

.def ClkA = r18

.def cnt = r23

.def AddrL = r24  ;адреса EEPROM

.def AddrH = r25

;---------------- запись EEPROM ------------

WriteFlash:  ;в AddrL,AddrH — адрес, данные в DATA

                  ;на выходе если бит с = 1 в регистре флагов, то ошибка

cbi PORTD,pSDA

         cbi PORTD,pSCL

         ldi cnt,120  ;120 попыток прописать

loop120f:

         push DATA

         rcall start

         ldi DATA,0xA0  ;addr device=0,r/w=0

rcall write

         brcs rt_writef  ;C=1 ERROR

mov DATA,AddrH  ;set HI address

rcall write

         brcs rt_writef  ;C=1 ERROR

mov DATA,AddrL  ;set LO address

rcall write

         brcs rt_writef  ;C=1 ERROR

pop DATA  ;set data to DATA

rcall write

         brcs rt_f  ;C=1 ERROR

rcall stop

         brcs rt_f  ;C=1 ERROR

 ret


;--------------- чтение EEPROM -------------

ReadFlash:  ;в AddrL,AddrH — адрес, данные в DATA

                  ;если бит с = 1 в регистре флагов, то ошибка

cbi PORTD,pSDA

         cbi PORTD,pSCL

ldi cnt,120

loop_read_f:

         rcall start

         ldi DATA,0xA0  ;addr device=0,r/w=0

rcall write

         brcs rt__f  ;C=1 ERROR

mov DATA,AddrH  ;set HI address

rcall write

         brcs rt__f  ;C=1 ERROR

mov DATA,AddrL  ;set LO address rcall write

brcs rt__f  ;C=1 ERROR

rcall start

ldi DATA,0xA1  ;addr device=0,r/w=1

rcall write

         brcs rt__f  ;C=1 ERROR

clt;  ;no put ACK

rcall read

         rcall stop

         brcs rt__f  ;G=1 ERROR

ret

rt__f:

         dec cnt

         brne loop_read_f

         ret


rt_writef:

         pop DATA

rt_f:

         brcc Ok_wr_f

         dec cnt

         brne loop120f

Ok_wr_f:

         ret


;------------ запись RTC ------------

write_i2c:  ;b ClkA — адрес, данные в DATA

                  ;если бит с = 1 в регистре флагов, то ошибка

cbi PORTD,pSDA

         cbi PORTD,pSCL

         ldi cnt,120  ;120 попыток прописать

lоор120:

         push DATA

         rcall start

         ldi DATA,0bi1010000  ;addr device,r/w=0

rcall write

         brcs rt_write  ;C=1 ERROR

mov DATA,ClkA