Forum: Mikrocontroller und Digitale Elektronik Kurze Hilfe in ASM


von Holger P. (Gast)


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.
1
; ***********************************************************************
2
; * Zeichen abspeichern                                                 *
3
; ***********************************************************************
4
    ldi   xl,low(RS232Buffer-1)         ; X Pointer laden
5
    ldi   xh,high(RS232Buffer-1)        
6
    
7
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
8
    inc   Dummy1                        ; Zeiger um eins weiterschieben
9
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
10
    brne  SOK                           ; Noch keine 20 Byte 
11
    ldi   Dummy1,1                      ; 68 Byte überschritten wieder bei 1 anfangen  
12
SOK:
13
    sts   RS232Zeiger,Dummy1
14
ZeigerStellen:
15
    adiw  xl:xh,1                       ; Zeiger erhöhen
16
    dec   Dummy1
17
    brne  ZeigerStellen
18
    st    x,EZeichen
19
    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?

von spess53 (Gast)


Lesenswert?

Hi

 -> st    x+,EZeichen

MfG Spess

von Dussel (Gast)


Lesenswert?

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

von Mathias F. (minglifu)


Lesenswert?

Servus,

nein er meint das was er sagt:

x+

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

von spess53 (Gast)


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

von Klaus2m5 (Gast)


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:
1
.ORG 0x100  ;oder direkt nach den Reset Vektoren
2
RS232Buffer .BYTE 68
3
RS232EndofBuffer:
4
;init während reset
5
  ldi   temp,low(RS232Buffer)
6
  sts   RS232Zeiger,temp
7
8
; ***********************************************************************
9
; * Zeichen abspeichern                                                 *
10
; ***********************************************************************
11
    ldi   xh,high(RS232Buffer)          ; X Pointer laden
12
    lds   xl,RS232Zeiger        
13
    cpi   xl,low(RS232EndofBuffer)      ; Auf Speichergrenze von 68 Byte testen 
14
    brlo  SOK                           ; Noch keine 68 Byte 
15
    ldi   xl,low(RS232Buffer)           ; 68 Byte überschritten wieder bei 0 anfangen  
16
SOK:
17
    st    x+,EZeichen
18
    sts   RS232Zeiger,xl
19
    rjmp  EndeInRs232

von Klaus2m5 (Gast)


Lesenswert?

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

von Holger P. (Gast)


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 :-(

von spess53 (Gast)


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

von Holger P. (Gast)


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?

von Holger P. (Gast)


Lesenswert?

So wäre das:
1
; ***********************************************************************
2
; * Zeichen abspeichern                                                 *
3
; ***********************************************************************
4
    ldi   xl,low(RS232Buffer-1)         ; X Pointer laden
5
    ldi   xh,high(RS232Buffer-1)        ;
6
    
7
    clr   Dummy2
8
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
9
    inc   Dummy1                        ; Zeiger um eins weiterschieben
10
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
11
    brne  SOK                           ; Noch keine 68 Byte 
12
    ldi   Dummy1,1                      ; 68 Byte überschritten wieder bei 1 anfangen  
13
SOK:
14
    sts   RS232Zeiger,Dummy1
15
    add   xl,Dummy1
16
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
17
    st    x,EZeichen
18
    rjmp  EndeInRs232

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

von Klaus2m5 (Gast)


Lesenswert?

Nein! - aber Deine Aufgabenstellung ist erfüllt.

von spess53 (Gast)


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

von spess53 (Gast)


Lesenswert?

Hi

ülich -> üblich

MfG Spess

von Holger P. (Gast)


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.

von spess53 (Gast)


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

von Holger P. (Gast)


Lesenswert?

Du meinst so
1
; ***********************************************************************
2
; * Zeichen abspeichern                                                 *
3
; ***********************************************************************
4
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
5
    ldi   xh,high(RS232Buffer)          ;
6
    
7
    clr   Dummy2
8
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
9
10
    add   xl,Dummy1
11
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
12
    st    x,EZeichen
13
14
    inc   Dummy1                        ; Zeiger um eins weiterschieben
15
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
16
    brne  SOK                           ; Noch keine 68 Byte gespeichert 
17
    ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
18
SOK:
19
    sts   RS232Zeiger,Dummy1
20
    rjmp  EndeInRs232

von spess53 (Gast)


Lesenswert?

Hi

>Du meinst so

Ja.

MfG Spess

von Holger P. (Gast)


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?

von spess53 (Gast)


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

von Klaus 2. (klaus2m5)


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.

von Holger P. (Gast)


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.

von Holger P. (Gast)


Lesenswert?

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

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

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

Leeren tu ich den Buffer so
1
; ***********************************************************************
2
; * Löscht den Buffer für die RS232                                     *
3
; * In Dummy1 steht der wert der in den Speicher geschrieben wird       *
4
; ***********************************************************************
5
Clear_RS232_Buffer:
6
;RS232 Buffer Zeiger auf wert von Dummy1
7
    sts RS232Zeiger,Dummy1 
8
  
9
;RS232 Buffer speicher löschen SRAM
10
    ldi xl,low(RS232Buffer); Z Pointer laden
11
    ldi xh,high(RS232Buffer)
12
    ldi Zaehler,68    
13
BClear:
14
    st  x+,Dummy1
15
    dec Zaehler
16
    brne BClear
17
ret

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

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

von spess53 (Gast)


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

von Holger P. (Gast)


Lesenswert?

spess53 schrieb:
> Wozu braucht man dafür 38400Bd?

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

von spess53 (Gast)


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

von Klaus 2. (klaus2m5)


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.

von Holger P. (Gast)


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.

von Holger P. (Gast)


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
1
; ***********************************************************************
2
; * Zeichen von der RS232 empfangen und auswerten;                      *
3
; ***********************************************************************
4
InRS232:
5
    push  Dummy3
6
    push  Dummy2
7
    push  Dummy1
8
9
    lds   EZeichen,udr0      ; Empfangenes Zeichen holen Interrupt löschen
10
    cpi   EZeichen,13        ; Wurde  Enter=13 gesendet?
11
    breq  Enter              ; Enter Zeichen in RS232 Buffer nicht Speichern
12
; ***********************************************************************
13
; * Zeichen abspeichern                                                 *
14
***********************************************************************
15
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
16
    ldi   xh,high(RS232Buffer)          ;
17
    
18
    clr   Dummy2
19
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
20
21
    add   xl,Dummy1
22
    adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
23
    st    x,EZeichen
24
25
    inc   Dummy1                        ; Zeiger um eins weiterschieben
26
    cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
27
    brne  SOK                           ; Noch keine 68 Byte gespeichert 
28
    ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
29
SOK:
30
    sts   RS232Zeiger,Dummy1
31
    rjmp  EndeInRs232
32
33
Enter:

von Klaus 2. (klaus2m5)


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.

von Holger P. (Gast)


Lesenswert?

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

von Klaus 2. (klaus2m5)


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

von Holger P. (Gast)


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?

von spess53 (Gast)


Lesenswert?

Hi

>ja diesen benutze ich

Und wo ist die Sicherung von SREG?

MfG Spess

von Holger P. (Gast)


Lesenswert?

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

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

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

von spess53 (Gast)


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

von Holger P. (Gast)


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?

von Holger P. (Gast)


Lesenswert?

Aber recht hast Du. Wer weiß schon wo die Spielerei noch hinführt.
1
; ***********************************************************************
2
; * Zeichen von der RS232 empfangen und auswerten;                      *
3
; ***********************************************************************
4
InRS232:
5
    in    sreg_save,sreg
6
    push  Dummy3
7
    push  Dummy2
8
    push  Dummy1
9
10
..
11
..
12
..
13
..
14
..
15
16
EndeInRs232:
17
    pop   Dummy1
18
    pop   Dummy2
19
    pop   Dummy3
20
    out   sreg, sreg_save      ; SREG wieder herstellen
21
reti

von spess53 (Gast)


Lesenswert?

Hi

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

MfG Spess

von Holger P. (Gast)


Lesenswert?

1
.INCLUDE "m88def.inc"
2
3
.def Dummy1     = r16
4
.def Dummy2     = r17
5
.def Dummy3     = r18
6
.def EZeichen   = r20
7
.def Zaehler    = r21
8
.def sreg_save  = r22
9
10
.equ F_CPU = 8000000                            ; Systemtakt in Hz
11
.equ BAUD  = 38400                              ; Baudrate
12
13
14
; Berechnungen
15
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
16
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
17
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
18
 
19
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
20
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
21
.endif 
22
23
24
.org 0x000     ; kommt ganz an den Anfang des Speichers
25
  rjmp RESET ; Interruptvektoren überspringen und zum Hauptprogramm
26
27
reti           ; $001 External Interrupt Request 0
28
reti           ; $002 External Interrupt Request 1
29
reti           ; $003 Pin Change Interrupt Request 0
30
reti           ; $004 Pin Change Interrupt Request 0
31
reti           ; $005 Pin Change Interrupt Request 1
32
reti           ; $006 Watchdog Time-out Interrupt
33
reti           ; $007 Timer/Counter2 Compare Match A
34
reti           ; $008 Timer/Counter2 Compare Match A
35
reti           ; $009 Timer/Counter2 Overflow
36
reti           ; $00A Timer/Counter1 Capture Event
37
reti           ; $00B Timer/Counter1 Compare Match A
38
reti           ; $00C Timer/Counter1 Compare Match B
39
reti           ; $00D Timer/Counter1 Overflow
40
reti           ; $00E TimerCounter0 Compare Match A
41
reti           ; $00F TimerCounter0 Compare Match B
42
reti           ; $010 Timer/Couner0 Overflow
43
reti           ; $011 SPI Serial Transfer Complete
44
rjmp InRS232   ; $012 USART Rx Complete
45
reti           ; $013 USART, Data Register Empty
46
reti           ; $014 USART Tx Complete
47
reti           ; $015 ADC Conversion Complete
48
reti           ; $016 EEPROM Ready
49
reti           ; $017 Analog Comparator
50
reti           ; $018 Two-wire Serial Interface
51
reti           ; $019 Store Program Memory Read
52
53
RESET:         ; Hier beginnt das Hauptprogramm 
54
55
56
; Stackpointer initialisieren
57
ldi Dummy1, high(RAMEND) 
58
out SPH,Dummy1           
59
ldi Dummy1, low(RAMEND)
60
out SPL,Dummy1
61
62
; ***********************************************************************
63
; * Port instaliesieren                                                 *
64
; *   Ports alle auf Ausgang bis auf PD0=Eingang RXD                    *
65
; *   Alle Interrups aus                                                *
66
; ***********************************************************************
67
ldi  Dummy1, 0b11111111
68
out DDRC,Dummy1 ; Port-C Ausgang
69
out DDRB,Dummy1 ; Port-B Ausgang
70
ldi  Dummy1, 0b11111110
71
out DDRD,Dummy1 ; Port-D Ausgang PD0=Eingang RXD
72
73
sbi PortB,0                       ; Setzt PortB Bit 0 (LED aus)
74
75
; ***********************************************************************
76
; * Baudrate einstellen                                                 *
77
; ***********************************************************************
78
ldi Dummy1, HIGH(UBRR_VAL)
79
sts UBRR0H, Dummy1
80
ldi Dummy1, LOW(UBRR_VAL)
81
sts UBRR0L, Dummy1
82
83
; ***********************************************************************
84
; * RS232 Frame-Format: 8 Bit                                           *
85
; *********************************************************************** 
86
ldi Dummy1, (1<<RXEN0)|(1<<RXCIE0)|(1<<TXEN0) ; TX aktivieren, RX aktivieren, Interrupt bei Empfang RX aktivieren 
87
sts UCSR0B, Dummy1
88
ldi Dummy1, (1<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00) ; 8 Bit Daten kein Paraty, 1 Stopbit
89
sts UCSR0C, Dummy1 
90
91
; ***********************************************************************
92
; * RS232 Buffer löschen                                                *
93
; ***********************************************************************
94
    ldi   Dummy1,0       
95
    rcall Clear_RS232_Buffer
96
97
; ***********************************************************************
98
; * Alle Interrups an                                                   *
99
; *********************************************************************** 
100
sei
101
102
Loop:
103
sbi  PortD,6      ; Setzt PortD Bit 7 (LED Grün)
104
rcall Delay500ms ; 500ms Warten
105
cbi  PortD,6      ; Setzt PortD Bit 7 (LED Rot)
106
rcall Delay500ms ; 500ms Warten
107
rjmp Loop
108
109
110
; ***********************************************************************
111
; * Zeichen von der RS232 empfangen und auswerten;                      *
112
; ***********************************************************************
113
InRS232:
114
    in    sreg_save,sreg
115
    push  Dummy3
116
    push  Dummy2
117
    push  Dummy1
118
119
    lds   EZeichen,udr0      ; Empfangenes Zeichen holen Interrupt löschen
120
    cpi   EZeichen,13        ; Wurde  Enter=13 gesendet?
121
    breq  Enter              ; Enter Zeichen in RS232 Buffer nicht Speichern
122
123
; ***********************************************************************
124
; * Zeichen abspeichern                                                 *
125
; ***********************************************************************
126
    ldi   xl,low(RS232Buffer)           ; X Pointer laden
127
    ldi   xh,high(RS232Buffer)          ;
128
    
129
    clr   Dummy2
130
    lds   Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher holen
131
132
  add   xl,Dummy1
133
  adc   xh,Dummy2                     ; Zeiger auf neuen Speicherplatz
134
  st    x,EZeichen
135
136
  inc   Dummy1                        ; Zeiger um eins weiterschieben
137
  cpi   Dummy1,69                     ; Auf Speichergrenze von 68 Byte testen 
138
   brne  SOK                           ; Noch keine 68 Byte gespeichert 
139
   ldi   Dummy1,0                      ; 68 Byte überschritten wieder bei 1 anfangen  
140
SOK:
141
    sts   RS232Zeiger,Dummy1
142
    rjmp  EndeInRs232
143
144
Enter:
145
; ***********************************************************************
146
; * Enter wurde gesender                                                *
147
; * Wurde Enter gedrückt und der Buffer ist leer so abbruch mit NAK     *
148
; ***********************************************************************
149
    lds   Dummy1,RS232Zeiger  ; den RS232-Zeiger aus dem Speicher holen    
150
    tst   Dummy1              ; Testet auf 0
151
    brne  V1
152
    ldi   Dummy1,0x15         ; Eingabe mit NAK bestätigen
153
    rcall sercharout
154
    rjmp  EndeRS232
155
156
157
V1:   
158
; ***********************************************************************
159
; * Enter wurde gesender                                                *
160
; * Vergleichen mit Befehlen                                            *
161
; ***********************************************************************
162
  RS232StrComp LEDGAN ; prüfen auf LED gelb an
163
  brne  V2
164
165
  cbi   PortB,0              ; Setzt PortD Bit 5 (LED gelb an)
166
  ldi   Dummy1,0x6         ; Eingabe mit ACK bestätigen
167
  rcall sercharout
168
  rjmp  EndeRS232
169
  
170
V2:
171
  RS232StrComp LEDGAUS     ; prüfen auf LED gelb aus
172
  brne  EndeRS232
173
174
  sbi   PortB,0              ; Setzt PortD Bit 5 (LED gelb aus)
175
  ldi   Dummy1,0x6         ; Eingabe mit ACK bestätigen
176
  rcall sercharout
177
178
179
EndeRS232:
180
  ldi   Dummy1,0       
181
  rcall Clear_RS232_Buffer
182
183
EndeInRs232:
184
  pop   Dummy1
185
  pop   Dummy2
186
  pop   Dummy3
187
  out   sreg, sreg_save      ; SREG wieder herstellen
188
reti  
189
190
191
; ***********************************************************************
192
; * Ausgabe eines Zeichen welches in R16 steht                          * 
193
; ***********************************************************************
194
sercharout:
195
    lds      Dummy2,UCSR0A   ; Warten bis UDR für das nächste
196
    sbrs    Dummy2,UDRE0    ; Byte bereit ist         
197
    rjmp    sercharout           
198
199
    sts     UDR0, Dummy1    ; Zeichen ausgeben
200
ret
201
202
203
; ***********************************************************************
204
; * RS232Buffer mit Z Pointer vergleichen                               *
205
; ***********************************************************************
206
KV:    ldi   xl,low(RS232Buffer)   ; X Pointer laden
207
       ldi   xh,high(RS232Buffer)  ;
208
209
       push Dummy1
210
       push Dummy2
211
XXX:   lpm  Dummy1,Z+               ; nächstes Byte aus dem Flash laden
212
       tst  Dummy1                  ; = Null? 
213
       breq Kende                   ; Vergleich fertig und somit OK 
214
KVW:   ld   Dummy2,X+               ; Zeichen aus SRAM holen
215
       cp   Dummy1,Dummy2
216
       brne  Kende
217
       rjmp  XXX
218
Kende: pop Dummy2
219
       pop Dummy1
220
       ret
221
222
223
; ***********************************************************************
224
; * Löscht den Buffer für die RS232                                     *
225
; * In Dummy1 steht der wert der in den Speicher geschrieben wird       *
226
; ***********************************************************************
227
Clear_RS232_Buffer:
228
;RS232 Buffer Zeiger auf wert von Dummy1
229
    sts RS232Zeiger,Dummy1 
230
  
231
;RS232 Buffer speicher löschen SRAM
232
    ldi xl,low(RS232Buffer); Z Pointer laden
233
    ldi xh,high(RS232Buffer)
234
    ldi Zaehler,68    
235
BClear:
236
    st  x+,Dummy1
237
    dec Zaehler
238
    brne BClear
239
ret
240
241
242
243
; ***********************************************************************
244
; *   RS232StrComp                                                      * 
245
; *   prüfen @0 mit RS232Buffer                                         *
246
; ***********************************************************************
247
.macro RS232StrComp
248
    ldi   zl,low(@0*2);    ; Z Pointer laden
249
    ldi   zh,high(@0*2)    ;  
250
    rcall KV
251
.endmacro
252
253
254
LEDGAN:        .db "LED gelb an"
255
LEDGAUS:       .db "LED gelb aus"
256
257
.dseg
258
RS232Zeiger: .Byte 1
259
RS232Buffer: .Byte 68

von spess53 (Gast)


Lesenswert?

Hi

Nachdem ich deine Interrupt_Routine gesehen habe, wundert mich 
eigentlich nichts mehr.
1
    .cseg
2
Loop:
3
    cpi   EZeichen,13        ; Wurde  Enter=13 gesendet?
4
    brne loop
5
6
    ldi   Dummy1,0x15         ; Eingabe mit NAK bestätigen
7
    rcall sercharout
8
9
; Deine Verarbeitung
10
11
    clr Dummy1
12
    sts RS232Buffer,Dummy1        ; 1.Zeichen Null
13
    sts RS232Zeiger,Dummy1        ; Pointer auf Null
14
rjmp Loop
15
16
;------------------------------------------------------------------
17
InRS232:
18
    in sreg_save,sreg
19
    push Dummy2
20
    push Dummy1
21
    push YL
22
    push YH
23
24
    lds EZeichen,udr0      ; Empfangenes Zeichen holen Interrupt löschen
25
    cpi EZeichen,13        ; Wurde  Enter=13 gesendet?
26
    breq Enter              ; Enter Zeichen in RS232 Buffer nicht Speichern
27
28
    ldi YL,low(RS232Buffer)           ; Y Pointer laden
29
    ldi YH,high(RS232Buffer)          ;
30
    clr Dummy2
31
    lds Dummy1,RS232Zeiger            ; den RS232-Zeiger aus dem Speicher 
32
    add YL,Dummy1
33
    adc YH,Dummy2                     ; Zeiger auf neuen Speicherplatz
34
    st Y,EZeichen        ; Zeichen speichern
35
    std Y+1,Dummy2       ; nächtes Zeichen Null
36
    inc Dummy1
37
    sts RS232Zeiger,Dummy1
38
enter:
39
    pop YH
40
    pop YL
41
    pop Dummy1
42
    pop Dummy2
43
    out sreg, sreg_save      ; SREG wieder herstellen
44
reti

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

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

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

MfG Spess

von Holger P. (Gast)


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?

von spess53 (Gast)


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:
1
RS232Buffer: .Byte 64
2
3
    .cseg
4
  .... 
5
  inc   Dummy1
6
  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?

von Holger P. (Gast)


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

von Sascha W. (sascha-w)


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

von Holger P. (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.