Init_usart:
ldi temp,(1<<TXEN | 1<<RXEN)
out UCSRB,temp ;разрешение передачи по каналу USART (в ;разряды TXEN и RXEN записываем 1)
sbi UCSRB, RXCIE ;устанавливаем флаг разрешения прерывания по
;завершении приема, прерывание происходит,
;когда RXC устанавливается в 1
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
;**********************************************************************
;передача байта по USART
USART_TRANSMIT:
clr flag
sbi UCSRB,UDRIE ;устанавливаем флаг разрешения ;прерывания регистр данных пуст ;прерывание происходит когда передача ;предыдущего байта завершена; ;и устанавливается флаг UDRE
rjmp loop ;переход на цикл ожидания прерывания
;**********************************************************************
;обработчик прерывания регистр данных UDR пуст, UDRE=1
TRANSMIT:
ldi flag,0x01 ;устанвливаем флаг в 1
ldi temp, 0x65 ;передаем "A", 0x65- ASCII код этого символа
out UDR,temp ;передача данных по USART
reti
;**********************************************************************;обработчик прерывания «прием данных завершен», регистр RXC=1
RECEIVE:
In temp, udr ; считываем данные, переданные по usart ;микроконтроллеру(байт содержаться в ;регистре udr)
out PORTB,temp ; выводим полученное значение на ;светодиоды
reti
.eseg
В двух следующих примерах по нажатию кнопки 0 осуществляется вывод последовательности байт I love this wonderful world, по нажатию кнопки 1 – Hello, World. При этом для того, чтобы определить конец последовательности в первом случае вводиться счетчик, который увеличивается на 1при выводе каждого символа ,после чего его значение сравнивается с количеством символов в последовательности. Если значение счетчика меньше количества символов, то выводим следующий байт, иначе завершаем передачу данных. Также символ введенный с клавиатуры компьютера выводится на светодиоды.
Во втором случае передача байт завершается после того, как передаваемый байт совпал с последним байтом последовательности.
В примере 1 используется для организации обмена данными прерывания USART, в примере 2 – проверяется значение флагов вручную.
Последовательность символов с помощью директивы .db вносится в память программы.
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
Где text – это метка, по которой мы сможем обращаться к нашей последовательности в программе.
Два последних байта 0x0A и 0x0D – это коды соответствующие переносу строки и возврату каретки. Введены в последовательность, чтобы в окне Hyper Terminal фрза выводилась с начала новой строки.
Для чтения символов из памяти используется команда lpm(Load Program Memory). При ее выполнении байт, записанный в память программы, копируется в регистр r0. Адрес этого байта определяется шестнадцатиразрядным регистром z.
Для чиения символов нашей последовательности одного за другим следует сначала в регистр z записать адрес начала последовательности.
ldi zl,low(text*2)
ldi zh,high(text*2)
Умножение на 2необходимо, так как память программ имеет 2х байтовую структуру, а в zl значения вноситься побайтно.
Теперь чтобы передать байт по USART:
считываем символ из памяти командой
lpm
передаем по USART
out UDR,r0,
увеличиваем адрес в z на 1
inc zl
Пример 1.
Ожидание прерывания происходит в бесконечном цикле loop. Для выхода из него используется регистр flag. После завершения передачи всех байт в обработчике прерывания этот флаг устанавливается в 1. В цикле loop происходит сравнение flag с 1, если flag=1, то осуществляется выход из цикла loop и возвращение в main.
В цикле main проверяется нажаты ли кнопки. Переход на функции обработки нажатия кнопки происходит только после того, как кнопка была отпущена.
Так как в функции передачи последовательности байт USART_TRANSMIT мы должны знать какая кнопка нажата, чтобы для каждой из них реализовать свой принцип завершения последовательности, вводиться регистр button, который хранит номер нажатой кнопки.
В обработчике события каждой кнопки в регистр button записываем ее номер, в регистр z вносим начальный адрес соответствующей данной кнопке последовательности символов и переходим на метку USART_TRANSMIT
BUTTON1_ON:
ldi button,BUTTON_1_ON
ldi zl,low(text*2) ;загрузка начального адреса передаваемого текста
ldi zh,high(text*2)
rjmp USART_TRANSMIT
В USART_TRANSMIT разрешаем прерывание «регистр данных пуст» sbi UCSRB,UDRIE, запрещаем прерывание «прием завершен cbi UCSRB,RXCIE. В регистр count записываем число символов первой последовательности ldi count,29 и переходим на цикл ожидания прерывания rjmp loop.
Когда происходит прерывание, передаем байт данных. Переданный байт записываем в регистр temp. Увеличиваем адрес, по которому считывается байт из памяти программы, на 1. В зависимости от того какая кнопка нажата переходим на разные метки.
TRANSMIT:
lpm
out UDR,r0 ;передача данных по USART
mov temp,r0
inc zl
cpi button,BUTTON_2_ON
breq BUTTON2_END
Если нажата кнопка 0, то переходим на метку BUTTON1_END, уменьшаем на 1 значение счетчика переданных символов count. Если его значение не равно0, то переходим на метку END_TR и по команде reti возвращаемся в цикл ожидания прерывания «регистр данных пуст» loop. Если равно, то завершаем передачу, перейдя на метку END_POSL, где устанавливаем в 1 flag.
Теперь, когда по команде reti мы вернемся в цикл loop, из него произойдет переход в основной цикл main, так как flag = 1.
Если нажата кнопка 1 макета, то из USART_TRANSMIT осуществляется переход на метку BUTTON2_END. Сравниваем содержимое регистра temp с последним символом последовательности. Если равенство не выполняется, то возвращаемся в loop по reti, иначе переходим на метку END_POSL, устанавливаем в 1 flag. И теперь, когда по команде reti мы вернемся в цикл loop, из него произойдет переход в основной цикл main, так как flag = 1.
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
Во время цикла main может произойти прерывание «прием завершен». Тогда мы перейдем на обработчик прерывания RECEIVE, считаем полученный символ и выведем его ASCII код на светодиоды.
вывод последовательности символов по прерываниям от USART для Степана
.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 0x0009
rjmp RECEIVE
.org 0x000a
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
MAIN:
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 ;если flag=1, то выходим из цикла, вся ;последовательность символов уже передана
breq END_LOOP
sbis PINA,BUTTON1 ;если нулевой разряд установлен (кнопка не ;нажата), то пропускаем следующую команду
rjmp END_LOOP ;если установлен, то выходим из цикла
sbis PINA,BUTTON2
rjmp END_LOOP
rjmp LOOP
END_LOOP:
cbi UCSRB,UDRIE ;запрещаем прерывание «регистр данных пуст»
sbi UCSRB,RXCIE ;разрешаем прерывание «прием завершен», тперь ;снова можем принимать байты
ret ;возврат в цикл main
;*******************************************************************
