freddy0815
08.02.2005, 14:00
hallo,
hab ein programm geschrieben, das 3 werte über rs232 an excel schickt, sobald man von excel aus zb auf nen knopf drückt. wenn ich das prog auf nem atmega32 im starterkit laufen lasse, funktioniert alles perfekt.
jetzt habe ich ne platine mit nem smd atmega32. über isp hab ich den programmiert. wenn ich jetzt über rs232 in excel die werte einlesen will, dann gibt er zwar 3 werte aus, wie er auch soll, aber leider nicht die richtigen. statt 54 gibt er zb 248 aus. die werte stehen im daten register.
hier mal der quellcode
.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)
kann das am internen quarz liegen?
steh grad ratlos rum...
danke mal
freddy0815
hab ein programm geschrieben, das 3 werte über rs232 an excel schickt, sobald man von excel aus zb auf nen knopf drückt. wenn ich das prog auf nem atmega32 im starterkit laufen lasse, funktioniert alles perfekt.
jetzt habe ich ne platine mit nem smd atmega32. über isp hab ich den programmiert. wenn ich jetzt über rs232 in excel die werte einlesen will, dann gibt er zwar 3 werte aus, wie er auch soll, aber leider nicht die richtigen. statt 54 gibt er zb 248 aus. die werte stehen im daten register.
hier mal der quellcode
.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)
kann das am internen quarz liegen?
steh grad ratlos rum...
danke mal
freddy0815