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





ПРИЛОЖЕНИЕ 3
Тексты программ
Далее приведены полные тексты некоторых программ, разбираемых в соответствующих главах книги. Ссылка на главу приводится в комментариях в начале каждого текста.
Демонстрационная программа обмена данными с flash-памятью 45DB011В по интерфейсу SPI
Листинг П3.1 содержит код программы обмена данными с flash-памятью 45DB011В по интерфейсу SPI.
;Проверка аппаратного SPI с памятью 45DB011B
;см. главу 11
.include "m8535def.inc"
; кварц 4 МГц
; =================== Константы ==========================
.equ _CS = РВО
.equ MOSI = РВ5
.equ MISO = PB6
.equ SCK = PB7 /разряды порта В, используемые интерфейсом SPI ;
================== Переменные =========================
.def temp = R16 .def count = R17
.def count_time = rl8 ;счетчик для таймера .def AddrL = r24 ;адрес страницы
.def AddrH = r25
; ================== Прерывания ==============
SPI Transfer Complete Handler USART_RXC ; USART RX Complete Handler USART_UDRE
; UDR Empty Handler USART_TXC ; USART TX Complete Handler ADC ; ADC Conversion
Complete Handler EE_RDY ; EEPROM Ready Handler ANA_COMP ; Analog Comparator
Handler TWSI ; Two-wire Serial Interface Handler EXT_INT2 ; IRQ2 Handler
rjmp,TIM0_COMP ; TimerO Compare Handler SPM RDY ; Store Program Memory Ready
Handler
rjmp RESET ; Reset Handler rjmp INT_0 ; IRQO Handler reti ;EXT_INT1 ; IRQ1 Handler reti
;rjmp TIM2_COMP ; Timer2 Compare Handler reti ;TIM2_OVF ; Timer2 Overflow Handler
reti ;TIM1_CAPT ; Timerl Capture Handler reti ;TIMl_COMPA ; Timerl Compare A Handler
reti ;TIMl_COMPB ; Timerl Compare В Handler reti ;TIMl_OVF ; Timerl Overflow Handler
rjmp TIM0_OVF ; TimerO Overflow Handler reti reti reti reti reti reti reti reti reti reti reti
out_com: /посылка байта из temp no UART
sbis UCSRA,UDRE ;ждем готовности буфера передатчика
rjmp ' out_com out UDR,temp
ret
;======== Обработчик внешнего прерывания 0 ==========
INT_0:
/первым делом запрещаем прерывания от кнопки
clr temp
out GICR,temp ;на всякий случай очищаем регистр флагов прерываний
ldi temp,$FF
out GIFR,temp ;GIFR очищается записью единиц
ldi temp,ObOOOOOlOO ;запуск TimerO входная частота 1:256
out TCCRO,temp
ldi count_time,61 ;интервал 1 с rcall write rcall read
reti
TlMOjDVF: ;TimerO Overflow 61 Гц
dec count_time ;в каждом прерывании уменьшаем на 1 breq int_timer ;если ноль, то разрешение прерывания reti /иначе выход из прерывания int_timer:
ldi temp, 1«INT0 ;разр. INTO out GICR,temp ;GIMSK тоже пашет ;на всякий случай очищаем регистр флагов прерываний ldi temp,$FF
out GIFR,temp ;GIFR очищается записью единиц clr temp; остановка TimerO out TCCRO,temp reti
;============ Обмен no SPI =============
WR_spi:
out SPDR,temp ; Начать передачу
wait_spi:
sbis SPSR,SPIF ; SPI - готов?
rjmp wait_spi
in temp,SPDR ; Чтение данных
ret
;======= Операции между буфером и страницей памяти ====
;на входе в temp — код операции
page_oper:
cbi PORTB,_CS ;CS = 0
rcall WR_spi ;передача кода операции
ldi AddrH, high(Address) ;старший адреса страницы
ldi AddrL, low.(Address) ;младший адреса страницы
lsr AddrL ;влево на 1 бит
rol AddrH ;влево через перенос
mov temp,AddrH
rcall WR_spi ;вывод через SPI mov temp,AddrL
rcall WR_spi ;вывод через SPI rcall WR_spi ;любой байт sbi PORTB,_CS ;CS = 1
ret
;====== Ожидание завершения страничной операции ====
wait_end_page_operation:
cbi PORTB,_CS ;CS = 0
ldi temp,0x57
rcall WR_spi ;передача кода операции
read_status: ldi
rcall
sbrs
rjmp sbi
temp, OxFF
WR_spi ;чтение регистра статуса через SPI temp, 7
read_status /ожидание готовности PORTB, CS ;CS = 1
ret
RESET: ;начало работы ldi temp,'.
out
temp,low(RAMEND) ;загрузка указателя стека SPL,temp
ldi
out
temp,high(RAMEND) /загрузка указателя стека SPH,temp

;======= Инициализация UART, 9600 при 4 МГц ====
. ldi temp,26 out UBRRL, temp ldi temp, (1«RXEN) | (1«TXEN) out UCSRB,temp
ldi temp, (1«URSEL) | (3«UCSZ0) ;UCSZ0=1 UCSZ1=1 8бит out UCSRC,temp ;======
Инициализация SPI mode 3, мастер =======
ldi temp, OxFF
out PORTB,temp ;PB7..0 - высокие.
ldi temp, (1«SCK) + (l«MOSI) + (1«_CS) + (1«PB4 )
out DDRB,temp ;SCK,MOSI,_CS, SS - выходы
;DORD=0 - старший бит первым, SPRln SPRO = 0 - скорость Fck/4
ldi temp, (1«SPE) + (1«MSTR) + (l«CPOL) + (1«CPHA)
out SPCR,temp ;=== инициализация прерываний ======
ldi temp, (1«ISC01) /прер. INTO по спаду
out MCUCR,temp
ldi temp,l«INT0 ;разр. INTO
out GICR,temp ;очищаем регистр флагов прерываний
ldi temp,$FF
out GIFR,temp ;GIFR очищается записью единиц ldi temp, (l«TOIE0) ;разр. прерывания TimerO out TIMSK,temp ldi temp, OxFF
out TIFR, temp ;сбросить флаги прерываний таймеров sei ;разрешаем прерывания .equ Address = 100 ;для примера будем писать в страницу номер 100

Cykle:
rjmp Cykle
; Запись 256 байт в АТ45
write:
cbi PORTB,_CS ;CS = 0
ldi temp,0x84
rcall WR_spi ;код операции — запись в буфер
ldi count,3 buff_addr_write:
ldi temp,0 / Начальный адрес в буфере =0 rcall WR_spi dec count
brne buff_addr_write ;данные:
ldi count,0 ;count=0
wr_buf:
mov temp,count ;заполняем последовательными числами от 0 rcall WR_spi ;вывод через SPI inc count
brne wr_buf ;буфер заполнен, когда count опять 0 sbi PORTB,_CS ;CS = 1 ldi temp,0x83
rcall page_oper ;запись из буфера в память с предварительным стиранием rcall
wait_end_page_operation ;страничная операция завершена ~20 мс
ret
; Чтение из AT4 5
read:
ldi temp,0x53
rcall page_oper /запись из страницы памяти в буфер
rcall wait_end_page_operation /страничная операция завершена ~250 мкс cbi PORTB,_CS ;CS'=0 ldi temp,0x54
rcall WR_spi /передача кода операции чтения буфера ldi count,3 buff_addr_read: ldi temp,0 /начальный адрес в буфере = 0 rcall WR_spi dec count
brne buff_addr_read
rcall WR_spi /передача незначащего байта ldi count,0 /0 = 256 rd_buf: rcall WR_spi /чтение через SPI
rcall out_com /посыпаем через UART dec count
brne rd_buf ; прочли 256 байт, когда count опять О sbi PORTB,_CS ;CS = 1 ret

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

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

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

Листинг П3.2
файл 12С.ргд
Процедуры чтения и записи по интерфейсу I2C
+ порт D
equ pSCL = 4 equ pSDA = 5
def def def def def
DATA
ClkA
cnt AddrL AddrH
= rl7
= rl8 = r23 = r24 = r25
/адреса EEPROM
WriteFlash: ;на
cbi cbi ldi
loopl20f: push rcall ldi rcall brcs mov rcall brcs mov rcall brcs pop rcall brcs rcall brcs ret
запись EEPROM
;B AddrL,AddrH — адрес, данные в DATA
выходе если бит с = 1 в регистре флагов, то ошибка
PORTD,pSDA
PORTD,pSCL
cnt,120 ;120 попыток прописать
;addr device=0,r/w=0
;С=1 ERROR ;set HI address
DATA start DATA, OxAO write rt_writef DATA, AddrH write
rt_writef DATA write rt_f
stop rt f
rt_writef ;C=1 ERROR DATA,AddrL ;set LO address write
;C=1 ERROR set data to DATA
;C-1 ERROR
;C=1 ERROR
; чтение,EEPROM
ReadFlash: ;в AddrL,AddrH — адрес, данные в DATA
/если бит с = 1 в регистре флагов, то ошибка
cbi PORTD,pSDA
cbi PORTD,pSCL
rt
ldi cnt, loop_read_f: rcall ldi rcall brcs mov rcall brcs mov rcall brcs rcall ldi rcall brcs clt rcall rcall brcs ret _f: dec brne ret
120
start
DATA, OxAO ;addr device=0,r/w=0 write rt f ;C=1 ERROR
DATA,AddrH ;set HI address write rt f ;C=1 ERROR
DATA,AddrL ;set LO address write rt f ;C=1 ERROR
start DATA, OxAl ;addr device=0,r/w=l write rt f ;C=1 ERROR
no put ACK read stop rt f ;C=1 ERROR
cnt loop read_f
rt_writef:
pop DATA
rt_f:
brcc Ok_wr_f
dec cnt brne loopl20f
Ok_wr_f: ret
; запись RTC
write_i2c: ;в ClkA — адрес, данные в DATA

;если бит с = 1 в регистре флагов, то ошибка
cbi PORTD, pSDA
cbi PORTD,pSCL
ldi cnt,120 ;120 попыток прописать
1оор120:
push DATA
rcall start
ldi DATA, 0Ы1010000 ;addr device, r/w=0
rcall write
brcs rt write ;C=1 ERROR
mov DATA,ClkA ;set HI address
rcall write
brcs rt write ;C=1 ERROR
pop DATA ;set data to DATA
rcall write
brcs rt_ ;C=1 ERROR
rcall stop
brcs rt_ ;C=1 ERROR
ret
; чтение RTC
read_i2c: ;ClkA — адрес, данные в DATA
;если бит с = 1 в регистре флагов, то ошибка
cbi PORTD,pSDA
cbi PORTD,pSCL
ldi cnt,120
rcall ldi rcall brcs mov rcall brcs rcall ldi rcall brcs clt rcall rcall brcs ret
dec
brne
ret
loop_read_:
start
DATA,ObllOlOOOO ;addr device,r/w=0 write
rt ;C=1 ERROR
DATA,ClkA ;set HI address write
rt ;C=1 ERROR
start
DATA, 0Ы1010001 ;addr device, r/w=l write
rt ;C=1 ERROR
stop rt
no put ACK read
;C=1 ERROR
cnt loop read
rt
rt_write:
pop DATA
rt_:
brcc Ok_wr_ dec cnt brne loopl20 Ok_wr_: ret
write: ;запись байта из DATA
push push ldi
x42:
rol brcs sbi rjmp
sei:
cbi del_wr: cbi rcall sbi rcall dec brne cbi rcall cbi rcall clc sbic sec sbi rcall pop pop
ret
DATA cnt
cnt,8 ;счетчик бит
DATA
sei DDRD,pSDA
del_wr
DDRD,pSDA
DDRD,pSCL
delay DDRD,pSCL
delay cnt
x42 /следующий бит
DDRD,pSDA ; освободить pSDA для АСК
delay DDRD,pSCL
delay
PIND,pSDA /читаем в бит С состояние АСК ;АСК не пришел DDRD,pSCL
delay cnt DATA
read: ;чтение в DATA, бит t=l -> ответить АСК, t=0 не отвечать АСК
ldi DATA, 1
read:
sbi DDRD,pSCL ;SCL=0
cbi DDRD, pSDA ;SDA=1
rcall delay
cbi DDRD, pSCL ;SCL=1
rcall delay
clc
sbic PIND,pSDA ;читать SDA в бит С
sec
rol DATA
brcc loop read
;отсылаем АСК ()
sbi DDRD,pSCL ;SCL=0
rcall delay
brts seO
cbi DDRD, pSDA ;не отвечать АСК (t) , SDA=
rjmp rd_
sbi DDRD, pSDA ;отвечать АСК (t) , SDA=0
clc
rcall delay
cbi DDRD,pSCL ;SCL=1
rcall delay
t:
cbi DDRD, pSDA
cbi DDRD, pSCL
rcall delay
sbis PINC,pSDA
rjmp start
sbis PINC,pSCL
rjmp start
sbi DDRD, pSDA ;0=SDA
rcall delay
sbi DDRD,pSCL ;0=SCL
rcall delay
i: sbi DDRD, pSDA
sbi DDRD, pSCL
rcall delay
cbi DDRD, pSCL ;1=SCL
rcall delay
cbi DDRD, pSDA ;1=SDA
rcall delay
clc
sbic PIND,pSDA
ret
sbic PIND,pSCL
ret
sec
ret
delay: ;~5 мкс (кварц 4 МГц)
push cnt
ldi cnt, 6
cyk_delay: dec cnt
brne cyk_delay
pop cnt
ret



     
 

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