www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Kurze Hilfe in ASM


Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In meinem BootLoader speichere ich die Zeichen ab die ich über die RS232 
bekomme. Da geht auch recht gut. Nun habe ich mir mein Programm noch mal 
angeschaut und bin der Meinung das ich das Abspeichern umständlich 
mache.
; ***********************************************************************
; * Zeichen abspeichern                                                 *
; ***********************************************************************
    ldi   xl,low(RS232Buffer-1)         ; X Pointer laden
    ldi   xh,high(RS232Buffer-1)        
    
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
    inc   Dummy1                        ; Zeiger um eins weiterschieben
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
    brne  SOK                           ; Noch keine 20 Byte 
    ldi   Dummy1,1                      ; 68 Byte überschritten wieder bei 1 anfangen  
SOK:
    sts   RS232Zeiger,Dummy1
ZeigerStellen:
    adiw  xl:xh,1                       ; Zeiger erhöhen
    dec   Dummy1
    brne  ZeigerStellen
    st    x,EZeichen
    rjmp  EndeInRs232

Umständlich finde ich es den Zeiger mit adiw  xl:xh,1 in einer Schleife 
hoch zu zählen. In Dummy1 steht der Wert um wieviel der Zeiger erhöht 
werden muss.

Ich komme einfach nicht darauf. Könnte mir jemand auf die Sprünge 
helfen?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

 -> st    x+,EZeichen

MfG Spess

Autor: Dussel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meinst du
clr rxx   ;Beliebiges Register von r16-r32
add xl,Dummy
adc xh,rxx

Autor: Mathias Fendl (minglifu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Servus,

nein er meint das was er sagt:

x+

erhöht automatisch nach dieser ausführung den Zeiger um eine Position!
MfG
MingliFu

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>erhöht automatisch nach dieser ausführung den Zeiger um eine Position!

Hatte ich auch gedacht (nicht richtig gelesen). Das von Dussel (Gast) 
passt schon.

MfG Spess

Autor: Klaus2m5 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geschickter ist es, den Speicher von RS232Buffer so zu definieren, dass 
kein Überlauf im High-Byte stattfinden kann. Rs232Zeiger enthält dann 
direkt das Low-Byte der Adresse. In etwa so:
.ORG 0x100  ;oder direkt nach den Reset Vektoren
RS232Buffer .BYTE 68
RS232EndofBuffer:
;init während reset
  ldi   temp,low(RS232Buffer)
  sts   RS232Zeiger,temp

; ***********************************************************************
; * Zeichen abspeichern                                                 *
; ***********************************************************************
    ldi   xh,high(RS232Buffer)          ; X Pointer laden
    lds   xl,RS232Zeiger        
    cpi   xl,low(RS232EndofBuffer)      ; Auf Speichergrenze von 68 Byte testen 
    brlo  SOK                           ; Noch keine 68 Byte 
    ldi   xl,low(RS232Buffer)           ; 68 Byte überschritten wieder bei 0 anfangen  
SOK:
    st    x+,EZeichen
    sts   RS232Zeiger,xl
    rjmp  EndeInRs232

Autor: Klaus2m5 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups - fehlt noch .DSEG, .CSEG und der Hinweis mit den Reset Vektoren ist 
quatsch.

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also in RS232Zeiger habe ich die Anzahl der schon empfangenden Zeichen
und in RS232Buffer sind die Zeichen.

Bekomme ich nun ein Zeichen so speichere ich das in den 
RS232Buffer+RS232Zeiger.


Mein RS232Buffer liegt bei 0x0101
Mein RS232Zeiger liegt bei 0x0100

Kommt das erste Zeichen schreibe ich in RS232Zeiger die 1
Danach setze ich x auf RS232Buffer-1
Danach zähle ich Rs232Zeiger runter bis es null ist
bei jedem dec erhöhe ich x

Also: Erste Zeichen

RS232Zeiger=1
RS232Buffer=0x0100
Loop:
RS232Zeiger-1
RS232Buffer+1
RS232Zeiger=0 ZeichenSpeichern in RS232Buffer
RS232Zeiger nicht 0 gehe zu Loop

Somit kommt das Zeichen immer an die richtige stelle.

Nur wenn ich schon 50 Zeichen abgespeichert habe. So muss ich beim 
nächsten zeichen 51 mal die schleife durchlaufen das kostet doch Zeit.

Hier wollte ich eigentlich

adiw  xl:xh, RS232Zeiger machen. Was aber nicht geht :-(

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Hier wollte ich eigentlich
>adiw  xl:xh, RS232Zeiger machen. Was aber nicht geht :-(

Na dann mache es doch so:

Beitrag "Re: Kurze Hilfe in ASM"

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ahh mit add xl,Dummy1 erhöhe ich XL um den wert Dummy1. Sollte dabei ein 
Übertrag entstehen so wird dieses durch adc xh,rxx übernommen da rxx 0 
ist und das Carry gesetzt. Ergab es kein übertrag ist rxx 0 und kein 
Carry. Richtig?


clr   Dummy2
ldi   Dummy1,RS232Zeiger
ldi   xl,low(RS232Buffer)         ; X Pointer laden
ldi   xh,high(RS232Buffer)


so ist x=0x0100

Nehmen wir an Dummy1 (RS232Zeiger) wäre 0x44 so würde

add xl,Dummy1 =  0x44 sein
adc xh,Dummy2 =  0x01 da kein Übertrag entstanden ist

Richtig?

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So wäre das:
; ***********************************************************************
; * Zeichen abspeichern                                                 *
; ***********************************************************************
    ldi   xl,low(RS232Buffer-1)         ; X Pointer laden
    ldi   xh,high(RS232Buffer-1)        ;
    
    clr   Dummy2
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
    inc   Dummy1                        ; Zeiger um eins weiterschieben
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
    brne  SOK                           ; Noch keine 68 Byte 
    ldi   Dummy1,1                      ; 68 Byte überschritten wieder bei 1 anfangen  
SOK:
    sts   RS232Zeiger,Dummy1
    add   xl,Dummy1
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
    st    x,EZeichen
    rjmp  EndeInRs232

Die schnellste und kürzeste form den Ringspeicher zu füllen?

Autor: Klaus2m5 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein! - aber Deine Aufgabenstellung ist erfüllt.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Die schnellste und kürzeste form den Ringspeicher zu füllen?

>    ldi   xl,low(RS232Buffer-1)         ; X Pointer laden
>    ldi   xh,high(RS232Buffer-1)        ;
>    ...
>    ldi   Dummy1,1

Warum fängst du nicht, wie allgemein ülich, bei Null an?

MfG Spess

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

ülich -> üblich

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Warum fängst du nicht, wie allgemein ülich, bei Null an?

Weil ich doch mein Zeiger erhöhe und somit min. eine 1 darin steht. Um 
nun auf RS232Buffer zu kommen muss ich doch wegen dem add eins weniger 
haben.

Klaus2m5 schrieb:
> Nein! - aber Deine Aufgabenstellung ist erfüllt.

Wie könnte ich es noch besser machen.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Weil ich doch mein Zeiger erhöhe und somit min. eine 1 darin steht. Um
>nun auf RS232Buffer zu kommen muss ich doch wegen dem add eins weniger
>haben.

Dann erhöhe den Zeiger nach dem addieren.

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du meinst so
; ***********************************************************************
; * Zeichen abspeichern                                                 *
; ***********************************************************************
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
    ldi   xh,high(RS232Buffer)          ;
    
    clr   Dummy2
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen

    add   xl,Dummy1
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
    st    x,EZeichen

    inc   Dummy1                        ; Zeiger um eins weiterschieben
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
    brne  SOK                           ; Noch keine 68 Byte gespeichert 
    ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
SOK:
    sts   RS232Zeiger,Dummy1
    rjmp  EndeInRs232

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Du meinst so

Ja.

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Macht von der Geschwindigkeit und vom Speicherplatz aber nix aus.

Geht das ganze, ein empfangendes Zeichen in einen Ringbuffer zu 
schreiben noch kürzer bzw. noch schneller?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Mal andersherum gefragt: An welcher Stelle siehst du ein Problem. Der 
Code-Teil wird, bei 8 MHz, in ca. 2µs abgearbeitet. Bei 9600Bd dauert 
ein Zeichen ca. 1ms.

MfG Spess

Autor: Klaus 2m5 (klaus2m5)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Holger P. schrieb:
> Macht von der Geschwindigkeit und vom Speicherplatz aber nix aus.
>
> Geht das ganze, ein empfangendes Zeichen in einen Ringbuffer zu
> schreiben noch kürzer bzw. noch schneller?

Ja - aber für RS232 spielt das jetzt nicht wirklich eine Rolle, es sei 
denn, Du arbeitest mit sehr hohen Baudraten und niedriger AVR-Clock.

Den Ringpuffer zu füllen, ist allerdings noch nicht mal die halbe Miete. 
Du musst den Ringpuffer ja auch leeren und vor Überlauf schützen. Wenn 
es dann klemmt, kannst Du Dir immer noch Gedanken über Optimierungen 
machen.

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So wie ich das nun getestet habe, lief mein Code auch gut im BootLoader. 
Als ich aber diese Speicherung in meinem Hauptprogramm eingesetzt habe 
musste ich feststellen das wenn ich eine Zeichenkette aus dem PC 
versende z.B. "LED gelb an" dieser Satz nicht im Buffer stand.

Wenn ich aber "L" "E" "D" " " "g" "e" "l" "b" " " "a" "n" tippte ging 
das.

Alos hinter einander senden der Buchstaben geht. Als String nicht. Was 
mir sagte das meine Routine wohl zu langsam ist. Bei einer Baudrate von 
38400. Also schaute ich mir mein Code an und dachte das da was zu machen 
sei.

War es auch und ich habe mein fehler verstanden.

Jetzt frage ich mich ob es noch schneller geht.

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus 2m5 schrieb:
> Du musst den Ringpuffer ja auch leeren und vor Überlauf schützen.

mit dem
    inc   Dummy1                        ; Zeiger um eins weiterschieben
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
    brne  SOK                           ; Noch keine 68 Byte gespeichert 
    ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
SOK:
    sts   RS232Zeiger,Dummy1

Denke ich mir schütze ich den Buffer vor dem Überlauf.

Leeren tu ich den Buffer so
; ***********************************************************************
; * Löscht den Buffer für die RS232                                     *
; * In Dummy1 steht der wert der in den Speicher geschrieben wird       *
; ***********************************************************************
Clear_RS232_Buffer:
;RS232 Buffer Zeiger auf wert von Dummy1
    sts RS232Zeiger,Dummy1 
  
;RS232 Buffer speicher löschen SRAM
    ldi xl,low(RS232Buffer); Z Pointer laden
    ldi xh,high(RS232Buffer)
    ldi Zaehler,68    
BClear:
    st  x+,Dummy1
    dec Zaehler
    brne BClear
ret

Aufruf z.B.:
ldi   Dummy1,0
rcall Clear_RS232Buffer

Wenn ich das SRAM resetten möchte ( Ausgangszustand nach dem BootLoader 
z.B. )
ldi   Dummy1,0xff
rcall Clear_RS232Buffer

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

> Als String nicht. Was
>mir sagte das meine Routine wohl zu langsam ist. Bei einer Baudrate von
>38400. Also schaute ich mir mein Code an und dachte das da was zu machen
>sei.

Wozu braucht man dafür 38400Bd?

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Wozu braucht man dafür 38400Bd?

Ich möchte eine schnelle Kommunikation zwischen PC->µC und 38400 ist 
schneller als 19200 :-)

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ich möchte eine schnelle Kommunikation zwischen PC->µC und 38400 ist
>schneller als 19200 :-)

Und du meinst du merkst das. Benutzt du den RX-Complete-Interrupt? Wenn 
nicht, hängt es wahrscheinlich an einer ganz anderen Stelle.

MfG Spess

Autor: Klaus 2m5 (klaus2m5)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Holger P. schrieb:
> Denke ich mir schütze ich den Buffer vor dem Überlauf.
>
> Leeren tu ich den Buffer so

Das ist natürlich kein Ringpuffer. Ich frage mich allerdings, wozu Du 
beim Empfang bei mehr als 68 Bytes wieder auf den Anfang des Puffers 
schreibst? Das ist dann der Überlauf und vorher Empfangenes würde 
überschrieben.

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus 2m5 schrieb:
> Das ist dann der Überlauf und vorher Empfangenes würde
>
> überschrieben.

Jo genau und somit das gesendete ungültig.

Sendet der PC "LED gelb an"+chr(13) schreibe ich alles was kommt in 
diesen Buffer. Kommt Enter werte ich den Buffer aus und vergleiche auf 
hinterlegte befehle. Geht gut!. Kommt "LED gelb an und das sehr schnell 
auf los geht es los 123456789012345 alles klar" so steht im Buffer " und 
das sehr schnell auf los geht es los 123456789012345 alles klar" und der 
vergleich mit "LED gelb an" geht schief. Genauso alles andere was von 
"LED gelb an" abweicht.

So habe ich unter

.db "LED gelb an"
.db "LED rot an"
.db "LED gelb aus"
u.s.w.

meine Befehle gelegt und vergleiche wie getippt den Buffer mit den 
Wörtern nachdem ich ein ENTER bekommen habe welches ich nicht 
abspeicher.

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Benutzt du den RX-Complete-Interrupt?

reti           ; $011 SPI Serial Transfer Complete
rjmp InRS232   ; $012 USART Rx Complete
reti           ; $013 USART, Data Register Empty


ja diesen benutze ich
; ***********************************************************************
; * Zeichen von der RS232 empfangen und auswerten;                      *
; ***********************************************************************
InRS232:
    push  Dummy3
    push  Dummy2
    push  Dummy1

    lds   EZeichen,udr0      ; Empfangenes Zeichen holen Interrupt löschen
    cpi   EZeichen,13        ; Wurde  Enter=13 gesendet?
    breq  Enter              ; Enter Zeichen in RS232 Buffer nicht Speichern
; ***********************************************************************
; * Zeichen abspeichern                                                 *
***********************************************************************
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
    ldi   xh,high(RS232Buffer)          ;
    
    clr   Dummy2
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen

    add   xl,Dummy1
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
    st    x,EZeichen

    inc   Dummy1                        ; Zeiger um eins weiterschieben
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
    brne  SOK                           ; Noch keine 68 Byte gespeichert 
    ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
SOK:
    sts   RS232Zeiger,Dummy1
    rjmp  EndeInRs232

Enter:

Autor: Klaus 2m5 (klaus2m5)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Holger P. schrieb:
> Jo genau und somit das gesendete ungültig.

O.K. - ungewöhnlich, aber kann man so machen. Hat mich nur dazu 
verleitet, zu glauben, dass es sich um einen Ringpuffer handelt.

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nenn man das nicht RingBuffer. So würde sich ja wieder eine neue Frage 
stellen. Was ist ein RingBuffer

Autor: Klaus 2m5 (klaus2m5)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Holger P. schrieb:
> Nenn man das nicht RingBuffer. So würde sich ja wieder eine neue Frage
> stellen. Was ist ein RingBuffer

http://www.mikrocontroller.net/articles/FIFO

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nungut so benutzte ich das falsche Wort. Sorry bin halt noch Anfänger.

Aber zurück zu meiner Frage:

Schneller geht das abspeichern nicht oder? Das ist jetzt schon Optimal 
so?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>ja diesen benutze ich

Und wo ist die Sicherung von SREG?

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe ich in dem Interupt nicht für notwendig empfunden. Ist es das? Bei 
Ja warum?

Mein Hauptprogramm macht doch nix:
Loop:
sbi  PortD,6      ; Setzt PortD Bit 7 (LED Grün)
rcall Delay500ms ; 500ms Warten
cbi  PortD,6      ; Setzt PortD Bit 7 (LED Rot)
rcall Delay500ms ; 500ms Warten
rjmp Loop

Und in Delay500ms benutze ich nur Dummy1 und Dummy2. An Interrups 
benutze ich nur den rjmp InRS232   ; $012 USART Rx Complete

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Habe ich in dem Interupt nicht für notwendig empfunden. Ist es das? Bei
>Ja warum?

Das ist eine der wichtigsten Sachen. Stell dir mal vor, das der 
Interrupt zwischen den beiden Befehlen ausgelöst wird:

cpi r16,5
breq blabla

Und jetzt überlege, was passiert wenn der Interrupt das Z-Flag (befindet 
sich in SREG) ändert.

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leuchtet mir ein das es knallt. Aber ich mache doch nix in meinem Loop

ODER kann ein ; $012 USART Rx Complete auch ausgelöst werden wenn ich in 
der Routine bin?

Das würde eventuell erklären warum ich Zeichen verliere wenn ich sie an 
einem Stück aussende. So müsste ich den Interrupt ausschalten wenn ich 
in der abarbeitung des Interrupt's bin.

Aber das SReg zu sichern in diesem fall will mir noch nicht einleuchten.

Klar vorsorge tragen damit bei einer erweiterung keine Probleme kommen 
können. Aber so zum spielen?

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aber recht hast Du. Wer weiß schon wo die Spielerei noch hinführt.
; ***********************************************************************
; * Zeichen von der RS232 empfangen und auswerten;                      *
; ***********************************************************************
InRS232:
    in    sreg_save,sreg
    push  Dummy3
    push  Dummy2
    push  Dummy1

..
..
..
..
..

EndeInRs232:
    pop   Dummy1
    pop   Dummy2
    pop   Dummy3
    out   sreg, sreg_save      ; SREG wieder herstellen
reti

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Zeig mal dein komplettes Programm. Es ist total nervig die Informationen 
scheibchen weise zu bekommen.

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
.INCLUDE "m88def.inc"

.def Dummy1     = r16
.def Dummy2     = r17
.def Dummy3     = r18
.def EZeichen   = r20
.def Zaehler    = r21
.def sreg_save  = r22

.equ F_CPU = 8000000                            ; Systemtakt in Hz
.equ BAUD  = 38400                              ; Baudrate


; Berechnungen
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
 
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
.endif 


.org 0x000     ; kommt ganz an den Anfang des Speichers
  rjmp RESET ; Interruptvektoren überspringen und zum Hauptprogramm

reti           ; $001 External Interrupt Request 0
reti           ; $002 External Interrupt Request 1
reti           ; $003 Pin Change Interrupt Request 0
reti           ; $004 Pin Change Interrupt Request 0
reti           ; $005 Pin Change Interrupt Request 1
reti           ; $006 Watchdog Time-out Interrupt
reti           ; $007 Timer/Counter2 Compare Match A
reti           ; $008 Timer/Counter2 Compare Match A
reti           ; $009 Timer/Counter2 Overflow
reti           ; $00A Timer/Counter1 Capture Event
reti           ; $00B Timer/Counter1 Compare Match A
reti           ; $00C Timer/Counter1 Compare Match B
reti           ; $00D Timer/Counter1 Overflow
reti           ; $00E TimerCounter0 Compare Match A
reti           ; $00F TimerCounter0 Compare Match B
reti           ; $010 Timer/Couner0 Overflow
reti           ; $011 SPI Serial Transfer Complete
rjmp InRS232   ; $012 USART Rx Complete
reti           ; $013 USART, Data Register Empty
reti           ; $014 USART Tx Complete
reti           ; $015 ADC Conversion Complete
reti           ; $016 EEPROM Ready
reti           ; $017 Analog Comparator
reti           ; $018 Two-wire Serial Interface
reti           ; $019 Store Program Memory Read

RESET:         ; Hier beginnt das Hauptprogramm 


; Stackpointer initialisieren
ldi Dummy1, high(RAMEND) 
out SPH,Dummy1           
ldi Dummy1, low(RAMEND)
out SPL,Dummy1

; ***********************************************************************
; * Port instaliesieren                                                 *
; *   Ports alle auf Ausgang bis auf PD0=Eingang RXD                    *
; *   Alle Interrups aus                                                *
; ***********************************************************************
ldi  Dummy1, 0b11111111
out DDRC,Dummy1 ; Port-C Ausgang
out DDRB,Dummy1 ; Port-B Ausgang
ldi  Dummy1, 0b11111110
out DDRD,Dummy1 ; Port-D Ausgang PD0=Eingang RXD

sbi PortB,0                       ; Setzt PortB Bit 0 (LED aus)

; ***********************************************************************
; * Baudrate einstellen                                                 *
; ***********************************************************************
ldi Dummy1, HIGH(UBRR_VAL)
sts UBRR0H, Dummy1
ldi Dummy1, LOW(UBRR_VAL)
sts UBRR0L, Dummy1

; ***********************************************************************
; * RS232 Frame-Format: 8 Bit                                           *
; *********************************************************************** 
ldi Dummy1, (1<<RXEN0)|(1<<RXCIE0)|(1<<TXEN0) ; TX aktivieren, RX aktivieren, Interrupt bei Empfang RX aktivieren 
sts UCSR0B, Dummy1
ldi Dummy1, (1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00) ; 8 Bit Daten kein Paraty, 1 Stopbit
sts UCSR0C, Dummy1 

; ***********************************************************************
; * RS232 Buffer löschen                                                *
; ***********************************************************************
    ldi   Dummy1,0       
    rcall Clear_RS232_Buffer

; ***********************************************************************
; * Alle Interrups an                                                   *
; *********************************************************************** 
sei

Loop:
sbi  PortD,6      ; Setzt PortD Bit 7 (LED Grün)
rcall Delay500ms ; 500ms Warten
cbi  PortD,6      ; Setzt PortD Bit 7 (LED Rot)
rcall Delay500ms ; 500ms Warten
rjmp Loop


; ***********************************************************************
; * Zeichen von der RS232 empfangen und auswerten;                      *
; ***********************************************************************
InRS232:
    in    sreg_save,sreg
    push  Dummy3
    push  Dummy2
    push  Dummy1

    lds   EZeichen,udr0      ; Empfangenes Zeichen holen Interrupt löschen
    cpi   EZeichen,13        ; Wurde  Enter=13 gesendet?
    breq  Enter              ; Enter Zeichen in RS232 Buffer nicht Speichern

; ***********************************************************************
; * Zeichen abspeichern                                                 *
; ***********************************************************************
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
    ldi   xh,high(RS232Buffer)          ;
    
    clr   Dummy2
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen

  add   xl,Dummy1
  adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
  st    x,EZeichen

  inc   Dummy1                        ; Zeiger um eins weiterschieben
  cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
   brne  SOK                           ; Noch keine 68 Byte gespeichert 
   ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
SOK:
    sts   RS232Zeiger,Dummy1
    rjmp  EndeInRs232

Enter:
; ***********************************************************************
; * Enter wurde gesender                                                *
; * Wurde Enter gedrückt und der Buffer ist leer so abbruch mit NAK     *
; ***********************************************************************
    lds   Dummy1,RS232Zeiger  ; den RS232-Zeiger aus dem Speicher holen    
    tst   Dummy1              ; Testet auf 0
    brne  V1
    ldi   Dummy1,0x15         ; Eingabe mit NAK bestätigen
    rcall sercharout
    rjmp  EndeRS232


V1:   
; ***********************************************************************
; * Enter wurde gesender                                                *
; * Vergleichen mit Befehlen                                            *
; ***********************************************************************
  RS232StrComp LEDGAN ; prüfen auf LED gelb an
  brne  V2

  cbi   PortB,0              ; Setzt PortD Bit 5 (LED gelb an)
  ldi   Dummy1,0x6         ; Eingabe mit ACK bestätigen
  rcall sercharout
  rjmp  EndeRS232
  
V2:
  RS232StrComp LEDGAUS     ; prüfen auf LED gelb aus
  brne  EndeRS232

  sbi   PortB,0              ; Setzt PortD Bit 5 (LED gelb aus)
  ldi   Dummy1,0x6         ; Eingabe mit ACK bestätigen
  rcall sercharout


EndeRS232:
  ldi   Dummy1,0       
  rcall Clear_RS232_Buffer

EndeInRs232:
  pop   Dummy1
  pop   Dummy2
  pop   Dummy3
  out   sreg, sreg_save      ; SREG wieder herstellen
reti  


; ***********************************************************************
; * Ausgabe eines Zeichen welches in R16 steht                          * 
; ***********************************************************************
sercharout:
    lds      Dummy2,UCSR0A   ; Warten bis UDR für das nächste
    sbrs    Dummy2,UDRE0    ; Byte bereit ist         
    rjmp    sercharout           

    sts     UDR0, Dummy1    ; Zeichen ausgeben
ret


; ***********************************************************************
; * RS232Buffer mit Z Pointer vergleichen                               *
; ***********************************************************************
KV:    ldi   xl,low(RS232Buffer)   ; X Pointer laden
       ldi   xh,high(RS232Buffer)  ;

       push Dummy1
       push Dummy2
XXX:   lpm  Dummy1,Z+               ; nächstes Byte aus dem Flash laden
       tst  Dummy1                  ; = Null? 
       breq Kende                   ; Vergleich fertig und somit OK 
KVW:   ld   Dummy2,X+               ; Zeichen aus SRAM holen
       cp   Dummy1,Dummy2
       brne  Kende
       rjmp  XXX
Kende: pop Dummy2
       pop Dummy1
       ret


; ***********************************************************************
; * Löscht den Buffer für die RS232                                     *
; * In Dummy1 steht der wert der in den Speicher geschrieben wird       *
; ***********************************************************************
Clear_RS232_Buffer:
;RS232 Buffer Zeiger auf wert von Dummy1
    sts RS232Zeiger,Dummy1 
  
;RS232 Buffer speicher löschen SRAM
    ldi xl,low(RS232Buffer); Z Pointer laden
    ldi xh,high(RS232Buffer)
    ldi Zaehler,68    
BClear:
    st  x+,Dummy1
    dec Zaehler
    brne BClear
ret



; ***********************************************************************
; *   RS232StrComp                                                      * 
; *   prüfen @0 mit RS232Buffer                                         *
; ***********************************************************************
.macro RS232StrComp
    ldi   zl,low(@0*2);    ; Z Pointer laden
    ldi   zh,high(@0*2)    ;  
    rcall KV
.endmacro


LEDGAN:        .db "LED gelb an"
LEDGAUS:       .db "LED gelb aus"

.dseg
RS232Zeiger: .Byte 1
RS232Buffer: .Byte 68

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Nachdem ich deine Interrupt_Routine gesehen habe, wundert mich 
eigentlich nichts mehr.
    .cseg
Loop:
    cpi   EZeichen,13        ; Wurde  Enter=13 gesendet?
    brne loop

    ldi   Dummy1,0x15         ; Eingabe mit NAK bestätigen
    rcall sercharout

; Deine Verarbeitung

    clr Dummy1
    sts RS232Buffer,Dummy1        ; 1.Zeichen Null
    sts RS232Zeiger,Dummy1        ; Pointer auf Null
rjmp Loop

;------------------------------------------------------------------
InRS232:
    in sreg_save,sreg
    push Dummy2
    push Dummy1
    push YL
    push YH

    lds EZeichen,udr0      ; Empfangenes Zeichen holen Interrupt löschen
    cpi EZeichen,13        ; Wurde  Enter=13 gesendet?
    breq Enter              ; Enter Zeichen in RS232 Buffer nicht Speichern

    ldi YL,low(RS232Buffer)           ; Y Pointer laden
    ldi YH,high(RS232Buffer)          ;
    clr Dummy2
    lds Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher 
    add YL,Dummy1
    adc YH,Dummy2                     ; Zeiger auf neuen Speicherplatz
    st Y,EZeichen        ; Zeichen speichern
    std Y+1,Dummy2       ; nächtes Zeichen Null
    inc Dummy1
    sts RS232Zeiger,Dummy1
enter:
    pop YH
    pop YL
    pop Dummy1
    pop Dummy2
    out sreg, sreg_save      ; SREG wieder herstellen
reti  

Mehr brauchst du in der Interruptroutine nicht. Den Rest machst du in 
deiner Schleife.

MfG Spess

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Noch etwas vergessen: Die 8 MHz kommen doch hoffentlich von einen Quarz. 
Sonst brauchen wir hier gar nicht weitermachen.

MfG Spess

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein ich benutze noch die Internen 8Mhz.

Zu dem was du mir geschrieben hast.

Das ganze Auswerten ausserhalb des Interrupts zu machen denke ich ist 
keine gute Idee.

Wenn ich es im Interrupt mache sind weitere Interrups erst mal gesperrt 
und mir kann nix dazwischen hauen. Würde sonst ein Zeichen gesendet in 
der Zei ich den Buffer durchsuche könnte es ja sein das schon wieder was 
andere drin steht.

In deinem Beispiel schaust du auch nicht ob ich mehr als 69 Zeichen im 
Buffer habe. Wobei mir klar ist das dieses keine fertige lösung sein 
soll sondern nur ein aufzeigen wie ich es auslagere.

Also besten Dank.


Warum ich Zeichen verliere wenn ich es im PC auf ein schlag versende 
verstehe ich noch nicht. Sende ich zeichen für Zeichen aus einer 
Schleife aus dem PC geht alles

Also ein ComPort1.WriteStr(Dummy); geht nicht
Wobei ein

    For I:=1 to Length(Dummy) do
    begin
         ComPort1.WriteStr(Dummy[I]);
    end;

Super geht.

Mein Progrämmelchen läuft klasse ohne Problem geht alles 100%


Danke

P.S. Nun ist aber schluss mit der Spielerei, suche jetzt mal ein 
richtiges Projekt.

UART habe ich glaube ich verstanden.
SPI habe ich glaube ich verstanden.
ADC habe ich glaube ich verstanden.
SRam, EEPROM und Flash habe ich glaube ich verstanden.
I/O natürlich auch.

Was noch fehlt ist PWM und I2C. PWM weiß nicht ob das so interessant ist 
i2C fehlen mir noch geräte die ich damit steuern könnte.

Hast du eine Idee?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Nein ich benutze noch die Internen 8Mhz.

Du liebst Glücksspiele. Damit bekommst du keine dauerhaft stabile 
Verbindung.

>In deinem Beispiel schaust du auch nicht ob ich mehr als 69 Zeichen im
>Buffer habe.

Wie kommst du eigentlich auf die 68? Mit 2er-Potenzen geht manches 
leichter:
RS232Buffer: .Byte 64

    .cseg
  .... 
  inc   Dummy1
  andi Dummy1,0b11000000  ; kann nicht größer 63 werden
Wie groß können eigentlich am Stück gesendet Strings werden?

>Also ein ComPort1.WriteStr(Dummy); geht nicht
>Wobei ein

>    For I:=1 to Length(Dummy) do
>    begin
>         ComPort1.WriteStr(Dummy[I]);

MfG Spess
>    end;

Sieht nach Delphi aus. Welch Komponente benutzt du?

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja aber wenn es 68 Byte sind soll es wieder bei 0 anfangen. Die 68 Byte 
habe ich von meinem BootLoader übernommen. 2Byte für die Pageadresse 
64Byte für die Daten und 2Byte für den CRC.

Ja es ist Delphi habe ich bei einem Bekannten bei dem ich eine Art 
Praktikum mache. Dort habe ich es auf einem PC, leider nicht daheim. Es 
ist die Version Delphi 4. Die Komponente ist die TComPort component ver. 
2.01 von Dejan Crnila

Autor: Sascha Weber (sascha-w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Holger P. schrieb:
> Warum ich Zeichen verliere wenn ich es im PC auf ein schlag versende
> verstehe ich noch nicht. Sende ich zeichen für Zeichen aus einer
> Schleife aus dem PC geht alles

wenn du die Zeichen einzeln sendest, dann kann sich der AVR bei jedem 
Zeichen anhand des Startbits synconisieren und die Abweichung die durch 
die Ungenauigkeit des interen Oszillators entsteht ist auf die 10Bit 
vernachlässigbar. Sendest du aber eine größere Anzahl nacheinander, so 
werden die Bits alle mit der syncronisation des 1.Startbits eingelesen 
und die Abweichung wird bei jedem Byte größer bis Fehler kommen. Du 
solltest in deiner ISR die Fehlerbits (OVR,FE) auswerten.

> Das ganze Auswerten ausserhalb des Interrupts zu machen denke ich ist
> keine gute Idee.

> Wenn ich es im Interrupt mache sind weitere Interrups erst mal gesperrt
> und mir kann nix dazwischen hauen. Würde sonst ein Zeichen gesendet in
> der Zei ich den Buffer durchsuche könnte es ja sein das schon wieder was
> andere drin steht.
eher umgekeht - wenn du die eingehenden Zeichen nicht aus dem UDR 
ausliest und abspeicherst gehen sie verloren! Der AVR kann nur eine 
Byte puffern.

Sascha

Autor: Holger P. (holg_i)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sascha Weber schrieb:
> eher umgekeht - wenn du die eingehenden Zeichen nicht aus dem UDR
>
> ausliest und abspeicherst gehen sie verloren! Der AVR kann nur eine
>
> Byte puffern.
>
>
>
> Sascha

Ich habe ja ein Buffer und fülle diesen. Kommt der Abschluss so werte 
ich den Buffer in dieser Routine gleich aus. Damit mir der Buffer nicht 
versaut wird.


Aber das mit den Zeichen einzeln und auf einmal versenden leutet mir 
ein. Werde es mal mit einem Externen Clock versuchen. Danke.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.