Init_usart:
ldi temp,(1<<TXEN | 1<<RXEN)
out UCSRB,temp ;разрешение передачи по каналу USART (в регистр
;TXEN и RXEN записываем 1)
sbi UCSRB, RXCIE ;разрешаем прерывание «прием завершен», ;теперь как только в UDR придет байт произойдет ;прерывание и мыперейдем на обраьотчик RECEIVE
clr temp
out UBRRH,temp
ldi temp,0x05
out UBRRL,temp ;задается скорость передачи 38400 бод
ldi temp, ((1<<URSEL)|(3<<UCSZ0))
out UCSRC,temp ; 1 стоп бит - 0 в USBS,
;контроль четности отсутсвует UPM1,UPM0 = 0
;USZ=3(USZ0-0,USZ1-1,USZ2-1) - посылается 8 бит за 1 раз
ret
;*******************************************************************
BUTTON1_ON:
ldi button,BUTTON_1_ON ;нажата первая кнопка
ldi zl,low(text*2) ;загрузка начального адреса передаваемого текста
;(память программ имеет 2х байтовую структуру, а ;в zl вноситься побайтно, отсюда *2
ldi zh,high(text*2)
rjmp USART_TRANSMIT
BUTTON2_ON:
ldi button,BUTTON_2_ON;нажата вторая кнопка
ldi zl,low(text1*2)
ldi zh,high(text1*2)
rjmp USART_TRANSMIT
;*******************************************************************
;передача байта по USART
USART_TRANSMIT:
cbi UCSRB,RXCIE ;запрещаем прием данных (сбрасываем в 0 флаг ;разрешения прерывания «прием завершен»)
clr flag
ldi count,29
sbi UCSRB,UDRIE ;разрешаем прием данных, установив флаг разрешения ;прерывания «регистр данных пуст», теперь каждый раз, ;когда байт будет передан будет происходить ;прерывание, обработчиком которого является функция ;TRANSMIT
rjmp loop
TRANSMIT:
lpm
out UDR,r0 ;передача данных по USART
mov temp,r0
inc zl
cpi button,BUTTON_2_ON
breq BUTTON2_END
BUTTON1_END:
dec count
breq END_POSL
rjmp END_TR
BUTTON2_END:
cpi temp,0x0D
breq END_POSL
END_TR:
reti
END_POSL:
ldi flag,0x01
rjmp END_TR
;*******************************************************************
RECEIVE:
in temp, UDR ; считываем данные, переданные по USART ;(байт содержаться в регистре UDR)
out PORTB,temp ; выводим полученное значение на светодиоды
reti
; определили константы в памяти программы
text: .db 'I',' ','L','O','V','E',' ','T','H','I','S',' ','W','O','N','D','E','F','U','L','L',' ','W','O','R','L','D',0x0A,0x0D
text1:.db 'S','O','M','B','O','D','Y',' ','P','L','E','A','S','E',' ','K','I','L','L',' ','M','E',0x0A,0x0D
.eseg
Пример2.
Как уже говорилось, выше в этом примере при передаче и приеме регистры RXC, UDRE проверяются вручную.
Теперь в основном цикле main проверяется не только нажаты ли кнопки, но и установлен ли флаг RXC «прием завершен». Если RXC=1, то вызывается функция RECEIVE, из UDR считывается байт данных и выводиться на светодиоды.
main:
….
sbic UCSRA,RXC
rcall RECEIVE
rjmp main
RECEIVE:
In temp, udr
out PORTB,temp ; выводим полученное значение на светодиоды)
ret
В обработчике события нажатия каждой кнопки в регистр button записываем ее номер, в регистр z вносим начальный адрес соответствующей данной кнопке последовательности символов. Полсе чего переходим на метку USART_TRANSMIT, где разрешаем прерывания таймера, обнуляем его счетчик, записываем в регистр count число символов первой последовательности и переходим к циклу loop ожидания прерывания таймера. В данной программе используется таймер, чтобы задать скорость передачи данных.
USART_TRANSMIT:
clr flag
ldi count,29
clr temp
out TCNT1H,temp
out TCNT1L,temp
ldi temp,(1<<OCIE1A)
out TIMSK,temp ;устанавливает 7 бит, чтобы разрешить прерывания
rjmp loop
Функция TRANSMIT является обработчиком прерывания таймера. Она начинается с цикла ожидания установления флага UDRE.
TRANSMIT:
sbis UCSRA,UDRE
rjmp TRANSMIT
После выхода из цикла происходит передача байта.
lpm
out UDR,r0 ;передача данных по USART
Снова обнуляем счетчик таймера,
clr temp
out TCNT1H,temp
out TCNT1L,temp
переданный байт записываем в регистр temp.
mov temp,r0
Увеличиваем адрес, по которому считывается байт из памяти программы, на 1.
inc zl
В зависимости от того какая кнопка нажата переходим на разные метки.
Определение конца передачи последовательности реализуется абсолютно так же, как в примере 1.
Теперь, перед выходом из цикла loop, мы должны запретить прерывания таймера и только после этого вернуться в основной цикл main.
ldi temp,(0<<OCIE1A) ;запрещаем прерывания таймера
out TIMSK,temp.
Полный код:
.include "m8515def.inc"
.dseg
.def temp = r16
.def flag = r17
.def count = r18
.def button = r19 ;хранит номер надатой кнопки
.equ BUTTON1 = 0x00
.equ BUTTON2 = 0x01
.equ BUTTON_1_ON = 0x01
.equ BUTTON_2_ON = 0x02
.cseg
.org 0x0000
rjmp INIT
.org 0x0004
rjmp TRANSMIT
INIT:
ldi temp,low(RAMEND) ;инициализация стека
out SPL,temp
ldi temp,high(RAMEND)
out SPH,temp
sei ;разрешение прерываний
ser temp
out DDRB,temp ;портВ - светодиоды, в DDRB 1111111 - порт на вывод
clr temp
out DDRA,temp ;портА - на ввод, кнопки
ser temp
out PINA,temp
out PORTA,temp
rcall INIT_USART ;инициализация USART
rcall INIT_TIMER
MAIN:
sbic UCSRA,RXC ; если флаг RXC=0, то пропускаем следующую команду
rcall RECEIVE ; если RXC=1, то считываем из регистра UDR байт, ;полученный по USART
sbis PINA,BUTTON1 ;если нулевой разряд установлен (кнопка не нажата), то ;пропускаем следующую команду
rcall BUTTON1_UP
sbis PINA,BUTTON2
rcall BUTTON2_UP
rjmp MAIN
BUTTON1_UP:
sbic PINA,BUTTON1
rjmp BUTTON1_ON
rjmp BUTTON1_UP
BUTTON2_UP:
sbic PINA,BUTTON2
rjmp BUTTON2_ON
rjmp BUTTON2_UP
;*********************************************************************
LOOP:
cpi flag,0x01
breq END_LOOP
sbis PINA,BUTTON1
rjmp END_LOOP
sbis PINA,BUTTON2
rcall END_LOOP
rjmp LOOP
END_LOOP:
ldi temp,(0<<OCIE1A)
out TIMSK,temp
ret
;********************************************************************* INIT_TIMER:
ldi temp,(1<<CS12) ;частота таймера = 1/256 частоты процессора
out TCCR1B,temp ;таймер начал работу, но прерывания запрещены
ldi temp,0x00 ;таймер считает до совпадения со значением
out OCR1AH,temp ; занесенным в эти регистры
ldi temp,0x03
out OCR1AL,temp
ldi temp,0x80 ;включаем компаратор для таймера
out ACSR,temp
ret
;*********************************************************************
