Code:
.NOLIST
.INCLUDE "D:\m32def.inc"
.LIST
; Programmbeschreibung: Serielle Schnittstellenübertragung
; Das Programm sendet eine bestimmte Anzahl von Bytes über RS232.
; Sobald an RX (Port D Pin1) etwas (ein Byte) empfangen wird
; (zB durch ein Tastendruck am PC), wird eine Interruptroutine gestartet,
; die aus dem Datenspeicher (Beginn: Adresse $62) ein Byte nach dem anderen sendet.
; Wobei das erste Byte (in $60) die Anzahl der Bytes, die zu senden sind, angibt.
; Steht zB in $60 'C8' werden die nachfolgenden 200 Bytes gesendet.
; Maximal 1500 Messwerte ($5DC)
; Datenübertragung: Baudrate 4800, keine Parität, 8 Datenbits + 1 Stopbit
; ist URSEL in UCSRC '0' wird für I/O UBRRH verwendet. Bei '1' UCSRC.
; Hier können Anzahl der Daten- und Stopbits gesetzt werden
;-----Konstanten-----
.equ fck = 4000000
.equ baudrate = 4800
.equ baudconst = (fck / (baudrate * 16)) - 1
.equ rs_recv = 0 ; 1 = Byte empfangen ; 0 = kein Byte empfangen
.equ adresse_anzahl = $60 ; Adresse an der die Anzahl der Werte steht
.equ adresse_anzahl_high = $61
.equ startadresse_werte = $62 ; Adresse für der Start der Werte
;-----Variablen-----
.def byte_send = R16 ; Register für zu sendente Bytes
.def counter_send_low = R17 ; Register für die Anzahl der zu sendenten Bytes <256 Werte
.def counter_send_high = R18; Register für die Anzahl der zu sendenten Bytes >256 Werte
.def w = R19 ; Arbeitsregister
.def wi = R20 ; Interrupt-Arbeitsregister
.def rs_buf = R21 ; Buffer für empfangenes Byte
.def a_flag = R22 ; Flagregister
;----- Interrupt-Adressen -----
.cseg
.org $0000
rjmp main
.org $01A ; RS232 Empfangsinterrupt
rjmp rs232_recv ; RS232 Behandlungsroutine wenn etwas empfangen wird
; im UCSRA Register liegt RXC auf "1"
;----- I/O-Port Initialisierung -----
hdw_init:
ldi w, 0b11111111
out PORTD, w ; alle Pins am Port D auf 1 setzen
ldi w, 0b11111110
out DDRD, w ; Datenrichtung am Port D festlegen: 1 = Ausgang; 0 = Eingang
; Pin 1 am Port D Empfangen (= 0) RX
; Pin 2 am Port D Senden (= 1) TX
; Port B zB für LED-Anzeige
ldi w, 0b11111111
out PORTB, w ; alle Pins am Port B auf 1 setzen
ldi w, 0b11111111
out DDRB, w ; Datenrichtung am Port B = Ausgang
;----- Test für Daten senden -----
; Datenspeicher mit Werten füllen
test:
ldi w, 0b00000011 ; insgesamt werden 3 werte geschickt
sts $60, w
ldi w, 0b00000001
sts $61, w
ldi w, 0b11110000 ; 1.wert der an excel geschickt wird
sts $62, w
ldi w, 0b00000001 ; 2.wert der an excel geschickt wird
sts $63, w
ldi w, 0b11111110 ; 3.wert der an excel geschickt wird
sts $64, w
;----- UART Initialisierung -----
uart_init:
ldi w, baudconst
out UBRRL, w ; UBRR = USART Baud Rate Register
ldi w, 0
out UBRRH, w
ldi w, 0b00011000
out UCSRB, w ; RXEN und TXEN setzen
sbi UCSRB, RXCIE ; RS232 Interrupt freigeben
sei ; gibt alle Interrups frei
ret
;----- Routine für empfangene Bytes -----
rs_rec_up:
cbr a_flag, 1 << rs_recv; durch '1<<' wird eine '1' n-mal nach links geschoben
; für rs_recv = 0: 0b00000001
; für rs_recv = 1: 0b00000010
; rs_recv ist eine Konstante ("0")
; --> das erste Bit in a_flag wird somit gelöscht
mov w, rs_buf ; empfangenes Byte in w
out PORTB, w ; an Port B ausgeben (LED Anzeige)
rcall rs_send
ret
;----- Routine zum Senden von Bytes -----
rs_send:
rcall count_bytes ; übernimmt die Anzahl der zu übertragenen Werte
clr R27
ldi R26, startadresse_werte ; Low-Byte des Zeigeregisters X mit der Adresse $62 beschreiben
send_loop:
rcall read_bytes ; liest die Werte ein
udre_loop:
sbis UCSRA, UDRE ; überprüft, ob UDRE im Register UCSRA gesetzt ist, wenn ja (UDRE=1) überspringen
; UDRE = 1 Sender frei, UDRE = 0 Sender besetzt
rjmp udre_loop ; solange Sender frei
out UDR, byte_send ; Wert senden
dec counter_send_low ; erniedrigt den low-Zähler um 1
brne send_loop ; solange bis Zähler = 0
dec counter_send_high ; erniedrigt den high-Zähler um 1 (= 16bit Zähler)
brne send_loop ; solange bis Zähler = 0
ret ; wenn Zähler = 0 alle Werte gesendet
count_bytes:
clr R27 ; High-Byte des Zeigeregisters X löschen
ldi R26, adresse_anzahl ; Low-Byte des Zeigeregisters X mit der Adresse $60 beschreiben
ld counter_send_low, x+ ; läd in counter_send_high die Anzahl der zu sendenten Bytes für >256 Messwerte
ld counter_send_high, x ; läd in counter_send_low die Anzahl der zu sendenten Bytes für <256 Messwerte
ret
read_bytes:
ld byte_send, x+ ; läd in byte_send das zu sendente Byte und erhöht den Zeiger x um 1
ret
;----- Interruptroutine zum Empfangen von Bytes -----
rs232_recv:
in wi, SREG ; CPU-Status
push wi ; wi in Stackpointer
in wi, UDR ; Byte vom Empfänger laden
mov rs_buf, wi ; zwischenspeichern
sbr a_flag, 1<<rs_recv ; durch '1<<' wird eine '1' n-mal nach links geschoben
; für rs_recv = 0: 0b00000001
; für rs_recv = 1: 0b00000010
; rs_recv ist eine Konstante ("0")
; --> das erste Bit in a_flag wird somit gesetzt
pop wi ; Stackpointer zurück in wi
out SREG, wi ; zurück zur CPU
reti ; Return from Interrupt
;----- Hauptprogramm -----
main:
ldi w, HIGH(RAMEND) ; RAMEND: Speicherende des Chips
out SPH, w ; in Stackpointer schreiben
ldi w, LOW(RAMEND) ; RAMEND: Speicheranfang des Chips
out SPL, w ; in Stackpointer schreiben
clr a_flag ; "0" = nichts wurde empfangen
rcall hdw_init ; Hardware Initialisierung
ldi w, 0b01010101
out PORTB, w ; wenn jede 2. LED leuchtet = empfangsbereit
;----- Endlosschleife -----
; wartet auf ein Empfangsinterrupt
endlos:
sbrc a_flag, rs_recv ; wenn was empfangen wurde, dann rs_rec_up, ansonsten überspringen
rcall rs_rec_up
rjmp endlos ; Dauerschleife
die hardware muss eigentlich stimmen. kontakte alle überprüft (mehrmals). laufen lass ich das ganze mit dem internen quarz (1mhz mit 64ms)
Lesezeichen