- •Содержание
- •Техническое задание
- •Введение
- •Структурная схема системы и пояснения к ней
- •Выбор элементной базы
- •Описание работы принципиальной схемы
- •Описание работы программного обеспечения (с блок-схемами алгоритмов)
- •Принципиальная схема и спецификация
- •Список литературы
- •Интерфейс rs232. Протокол modbus ascii
- •Заключение
- •Листинг программы
Листинг программы
.INCLUDE "C:\Program Files\Atmel\AVR Tools\AvrAssembler\Appnotes\2313def.inc"
.DSEG
.ORG 0x60
count: .byte 1
.CSEG
.ORG 0x0000
rjmp Reset
rjmp INT0_interrupt
rjmp INT1_interrupt
rjmp T1CAPT_interrupt
rjmp T1COMP_interrupt
rjmp T1OVF_interrupt
rjmp T0OVF_interrupt
rjmp UART_RX_interrupt
rjmp UART_UDRE_interrupt
rjmp UART_TX_interrupt
rjmp ANCOMP_interrupt
Reset:
;Настройка (инициализация) указателя стека
ldi r16, 0x7F
out SPL, r16
;ЗАПОМИНАЕМ ПОСТОЯННЫЕ ВЕЛИЧИНЫ В РЕГИСТРАХ ДЛЯ УДОБСТВА
ldi r17, 0x3A ; ':'
ldi r18, 0x0D ; CR
ldi r19, 0x0A ; LF
ldi r20, 0x30 ; 00110000 '0'
ldi r21, 0x31 ; 00110001 '1'
clr r1 ; count
ldi r16, 0x60
mov r0, r16 ; adress
clr r16
ldi r16, 0x30 ;смещение для преобраз в/из ascii
mov r5, r16
clr r16
;Настройка последовательного порта (UART)
;Настройка линии PD1, pd3,pd4,pd5 на вывод
ldi r16, 0x3A
out DDRD, r16
;Задание наибольшей скорости передачи данных
ldi r16, 0x00
out UBRR, r16
;Разрешение приемника и передатчика UART
;Разрешение прерываний по окончанию приема байта данных
ldi r16, 0x98 ;10011000
out UCR, r16
;Настройка порта B на вывод
ldi r16, 0xff
out DDRB, r16
;Глобальное разрешение прерываний
sei
ldi zh, high(string*2)
ldi zl, low(string*2)
adiw zl, 0x05
Main:
;Цикл основной программы
ldi r16, 0x03
mov r1, r16
ldi r16, 0x08
mov r12, r16
clr r16
loop1:
;Выбираем из памяти программ символ строки
lpm
rcall from_ascii
rcall to_indicator
;Посылаем символ нафиг. и он идет.
cpi R1, 0x03
brne lab1
rjmp lab_s
lab1: cpi R1, 0x02
brne lab2
ldi r16, 0x10
mov r12, r16
rjmp lab_s
lab2: cpi R1, 0x01
ldi r16, 0x20
mov r12, r16
rjmp lab_s
lab_s: out PORTD, r12
out PORTB, r0
nop
nop
nop
nop
nop
nop
nop
adiw zl, 0x01
dec r1
brne loop1
;Конец цикла вывода
wdr
rjmp Main
string: .db 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
error: .db 0x3A, 0x30, 0x31, 0x31, 0x30, 0x39, 0x39, 0x39, 0x39, 0x33, 0x0D, 0x0A
ind: .db 0xFC, 0x50, 0xDA, 0xF2, 0x55, 0xB6, 0xBE, 0xE0, 0xFE, 0xF5
;Обработчики прерываний
INT0_interrupt:
reti
INT1_interrupt:
reti
T1CAPT_interrupt:
reti
T1COMP_interrupt:
reti
T1OVF_interrupt:
reti
T0OVF_interrupt:
reti
UART_RX_interrupt:
;Обработка прерываний по приему байта данных
in R16, UDR
wdr
cpi R1, 0x00
brne l1
CPSE R16, R17 ;if count=0, udr=':'
rjmp ln
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l1: cpi R1, 0x01
brne l2
CPSE R16, R20 ;if count=1, udr='0'
rjmp ln
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l2: cpi R1, 0x02
brne l3
CPSE R16, R21 ;if count=2, udr='1'
rjmp ln
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l3: cpi R1, 0x03
brne l4
CPSE R16, R21 ;if count=3, udr='1'
rjmp ln
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l4: cpi R1, 0x04
brne l5
CPSE R16, R20 ;if count=4, udr='1'
rjmp ln
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l5: cpi R1, 0x05 ;data1
brne l6
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l6: cpi R1, 0x06 ;data2
brne l7
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l7: cpi R1, 0x07 ;data3
brne l8
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l8: cpi R1, 0x08 ;lrc1
brne l9
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
l9: cpi R1, 0x09 ;lrc2
brne lA
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
lA: cpi R1, 0x0A ;cr
brne lB
CPSE R16, R18 ;if count=0a, udr=cr
rjmp ln
st Z, R16
adiw zl, 0x01
inc R1
rjmp ll
lB: cpi R1, 0x0B ;lf
brne ln
CPSE R16, R19 ;if count=4, udr=lf
rjmp ln
st Z, R16
adiw zl, 0x01
clr R1
rjmp ll
ln: ;if not ':' -> error
rcall error_frame
ll: reti
UART_UDRE_interrupt:
reti
UART_TX_interrupt:
reti
ANCOMP_interrupt:
reti
;functions
error_frame:
;строка уже сформирована и лежит в памяти по адресу error
;Инициализация указателя на строку
ldi zh, high(error*2)
ldi zl, low(error*2)
;Начало цикла вывода строки
ldi r16, 12
mov r1, r16
clr r16
cycle:
;Выбираем из памяти программ символ строки
lpm
;Посылаем символ в последовательный порт
out UDR, r0
;Ждем (цикл wait), когда освободитмя регистр данных последовательного порта
wait:
nop
sbis USR, 5
rjmp wait
adiw zl, 0x01
dec r1
brne cycle
;Конец цикла вывода строки
ret
to_ascii:
; маска 0х0f и 0xf0 - разбиваем на 2 байта
; второй сдвигаем на 4 вправо
; к каждому прибавляем 0х30
;исходное - r0. результат - r10, r11
ldi r16, 0x30
mov r7, r16
ldi r16, 0x0f
mov r9, r16
ldi r16, 0xf0
mov r8, r16
mov r10, r0
mov r11, r0
and r10, r8
and r11, r9
lsr r10
lsr r10
lsr r10
lsr r10
add r10, r7
add r11, r7
ret
ret
from_ascii:
; отнимаем от каждого байта ascii 0х30
ldi r16, 0x30
sub r0, r16
clr r16
ret
to_indicator:
;преобразуем двоичный код числа для индикатора
;Инициализация указателя на строку
ldi zh, high(ind*2)
ldi zl, low(ind*2)
add zl, r0
lpm
ret
LRC:
; не считаются ':', cr, lf - итого остается 9 байт
ldi r16, 0x09
mov r2, r16
clr r16
clr r3
ldi xh, high(string*2)
ldi xl, low(string*2)
adiw xl, 0x01 ; ':' не считается
loop:
ld r1, X
adiw xl, 0x01
add r3, r1
dec r2
brne loop
mov r4, r3
neg r4
sub r3, r4
mov r4, r3
and r3, 0xf0
lsr r3
lsr r3
lsr r3
lsr r3
and r4, 0x0f
add r4, r5
add r3, r5
ld r1, X
cp r1, r3
brne label
adiw xl, 0x01
ld r1, X
cp r1, r4
brne label
rjmp m
label: rcall error_frame
m: RET
