Forum: Mikrocontroller und Digitale Elektronik EEPROM Uart LCD


von Kulli (Gast)


Angehängte Dateien:

Lesenswert?

Hallo
habe Probleme mit dem EEPROM und wahrscheinlich dem Uart.
Ich möchte die vom Uart geschickten Zeichen im EEPROM speichern. Dies 
geschieht im Uart Interrupt Receive.
Die im EEPROM abgespeicherten Zeichen möchte ich dann lesen und (als 
Kontrolle für den korrekten Empfang) wieder auf einem Display ausgeben 
(Passiert ebenfalls noch im Uart Interrupt Receive).


Wie sich zeigt funktioniert es nicht korrekt.
Schicke ich z.B. vom PC die Zeichen :
12345678901234567890
so werden auf dem LCD nur die Zeichen 123970 angezeigt.


Die Funktionen zum EEPROM schreiben und Lesen haben ich dem Tutorium 
entnommen.
Woran kann es liegen. Hängt es vielleicht damit zusammen, dass einfach 
nicht alle Zeichen vom Mikrocontroller empfangen bzw. verarbeitet werden 
können. Oder ist mein LCD zu langsam? Ich verwende das LCD204B LED von 
Reichelt.
Wie müsste ich mein Programm umändern?

Quelltext ist angehängt
ATMega32, 11MHz

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Denke daran, Daß das EEPROM 4ms Zeit für das Speichern von 1 Byte 
benötigt. Wahrscheinlich ist Deine Baudrate zu hoch. Wartest Du in der 
Schreibroutine auf das Ende des eventuell gerade laufenden 
Schreibzyklusses?

von Kulli (Gast)


Lesenswert?

hi
ja ich warte auf auf das Ende des Schreibzyklusses

EEPROM_write:
    sbic    EECR, EEWE                  ; prüfe ob der letzte 
Schreibvorgang beendet ist
    rjmp    EEPROM_write                ; wenn nein, nochmal prüfen

von Kulli (Gast)


Lesenswert?

Kann keiner helfen?

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Wie hoch ist die Baudrate des UARTs?

von Kulli (Gast)


Lesenswert?

Baud=9600

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Macht knapp ein Byte pro Millisekunde - das schaffst Du nicht im EEPROM 
wegzuspeichern!

von Kulli (Gast)


Lesenswert?

Das heißt was? Was muss ich machen und wo?

von Kulli (Gast)


Lesenswert?

Kann mir jemandhelfen?

von Wasweissich (Gast)


Lesenswert?

Das heisst Du musst das Schreiben in das EEPROM aus der 
RX-Interrupt-Routine herausnehmen. Am besten schreibst Du die Daten 
erstmal in eine (Ring-)buffer.
Grundsätzlich ist es sehr gut zu überlegen ob solche langen 
Programmteile im Interrupt stehen sollten. Eher nicht.

Dann schreibst Du die Daten im Hauptprogramm. Während Du auf den 
Abschluss des Schreibvorganges wartest, kann der RX-Int dann weiterhin 
zuschlagen.
Verstanden?

von fubu1000 (Gast)


Lesenswert?

Hallo,
vorausgesetzt, du hast ein selbstgeschriebenes Programm am PC, welches 
Zeichen ausgibt!
Machst es in einem billig Protokoll:
z.B. wenn TX vom Pc senden will schickt es ein ACK, z.B. 0xAA.
Wenn der uC gerade nix zu tun hat schickt er ein, z.B. 0xBB zurück.
Dann kommen die Daten, die du im, ich hoffe ich irre mich jetzt nicht,
UDR-Register empfängst. Nach Ende des Empfangs sendest du z.B. ein 0xCC 
an den PC, damit das Proggi aufm PC wartet.
Dann kommt die LCD Ausgabe, oder sonstwas und dann sendest du z.B. ein 
0xDD an den PC, damit dein Proggi weiss er kann neues Zeichen senden.

Falls du z.B. Hyperterminal benutzt und weisst wieviel Daten kommen 
werden, würde ich diese im RAM speichern, ausserdem Variable hochzählen, 
wenn max. errreicht, aufm LCD Zeichen ausgeben.


Gruss fubu.

von Kulli (Gast)


Lesenswert?

Hallo
danke für die Antworten.
Die Variante von fubu fällt jedoch aus, da die Daten später nicht vom PC 
gesendet werden und ich auch nicht entscheiden kann ein bestimmtes 
Zeichen bei  Bereitschaft ect zu senden.

Zu der Sache mit dem Ring-Buffer:
Gibt es hierfür evt. schon eine fertige Routine? Da es sich hierbei nur 
um ein Teilstück in einem größerem Projekt handelt, würde es mich 
freuen, wenn mir jemand dabei behilflich sein kann.
Wie würde das mit dem Ring-Buffer denn in etwa in Assembler aussehen?
Muss ich da den rol-Befehl nutzen?

von Stephan H. (stephan-)


Lesenswert?

stelle Dir den Ringbuffer wie die Rotation des Akkus über Carry vor.
Nur nicht mit Bits sondern mit Bytes.
Und das was sonst ins Carry geht, geht dann eben in den EEPROM.

von Kulli (Gast)


Lesenswert?

Hi
habe jetzt schon studenlang im Netz nach Assembler-Routinen für 
Ring-Buffern gesucht. Leider ohne Erfolg.
Es wäre nett wenn mir jemand evt. kleinere Code-Snipsel zukommen lassen 
kann. Da ich absolut nicht weiss wie man das mit den Ring-Buffern 
realisieren kann. Bin auch noch nicht soooo bewandert in Assembler.

von Karl H. (kbuchegg)


Lesenswert?

Kulli wrote:
> Hi
> habe jetzt schon studenlang im Netz nach Assembler-Routinen für
> Ring-Buffern gesucht. Leider ohne Erfolg.

Dann: selber schreiben. Dabei lernst du sowieso mehr, als wenn
du nur fertige Routinen abkupferst.

> Es wäre nett wenn mir jemand evt. kleinere Code-Snipsel zukommen lassen
> kann. Da ich absolut nicht weiss wie man das mit den Ring-Buffern
> realisieren kann.

Hast du schon tausende male benutzt.
Wenn du grade an was arbeitest und jemand kommt zu dir ins Zimmer
und will dir was mitteilen, dann schreibst du das erst mal auf
und siehst es dir erst dann genau an, wenn Zeit dazu ist.

Ein Ringbuffer ist nichts anderes als eine Speicherfläche
in der die Daten erst mal landen. Rungbuffer heist er deswegen,
weil er logisch zu einem Ring zusammengeklebt wird. Ist man
am Ende der Speicherfläche angelangt, dann beginnt man ganz
einfach wieder vorne zu schreiben. So wie auf einem Papierstreifen
den man zu einem Ring zusammenklebt und einfach drauflosschreibt
und dabei das was vorher dort stand einfach überschreibt.

Du musst dir 2 Dinge in Variablen merken:
Wo darf das nächste Zeichen geschrieben werden
Von wo ist das letzte Zeichen gelesen worden

  Das sei deine Speicherfläche

    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+

und jetzt das ganze mit den Schreib/Lesezeigern

    +---+---+---+---+---+---+---+---+
    |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
     ^^
     ||
     |+----------------+
     |                 |
   Lesen            Schreiben

Wenn jetzt ein Text zwischengespeichert werden muss, dann wandert
der erst mal in den Ringbuffer. Zb. der Text "abc"

    +---+---+---+---+---+---+---+---+
    | a | b | c |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+
     ^             ^
     |             |
     |             +---+
     |                 |
   Lesen            Schreiben

Jetzt nehmen wir mal an, dein µC hat keine Zeit den Text zu bearbeitn
aber in der Zwischenzeit kommt ein neuer Text herein: 1 2

Diese Zeichen wandern ebenfalls in den Ringbuffer

    +---+---+---+---+---+---+---+---+
    | a | b | c | 1 | 2 |   |   |   |
    +---+---+---+---+---+---+---+---+
     ^                    ^
     |                    |
     |                 +--+
     |                 |
   Lesen            Schreiben

Dein µC hat jetzt endlich Zeit und beginnt sich das erste Zeichen aus
dem Ringbuffer zu holen: a

    +---+---+---+---+---+---+---+---+
    | a | b | c | 1 | 2 |   |   |   |
    +---+---+---+---+---+---+---+---+
          ^               ^
          |               |
     +----+            +--+
     |                 |
   Lesen            Schreiben


Er holt sich das nächste Zeichen: b

    +---+---+---+---+---+---+---+---+
    | a | b | c | 1 | 2 |   |   |   |
    +---+---+---+---+---+---+---+---+
              ^           ^
              |           |
     +--------+        +--+
     |                 |
   Lesen            Schreiben

und dann ist er erst mal beschäftigt. In der Zwischenzeit trifft
weiterer Text ein: defg
Auch der wird erst mal im Ringbuffer abgelegt

    +---+---+---+---+---+---+---+---+
    | g | b | c | 1 | 2 | d | e | f |
    +---+---+---+---+---+---+---+---+
      ^       ^
      +----------------+
     +--------+        |
     |                 |
   Lesen            Schreiben

Beachte: nach f ist die Speicherfläche zu Ende, also wird das noch
eingetroffene g ganz am Anfang geschrieben. Ist ja auch kein
Problem, das a das vorher dort stand wurde schon verarbeitet.

Dein µC hat jetzt wieder Zeit und widmet sich den nächsten
Zeichen aus dem Ringbuffer: c

    +---+---+---+---+---+---+---+---+
    | g | b | c | 1 | 2 | d | e | f |
    +---+---+---+---+---+---+---+---+
      ^           ^
      +----------------+
     +------------+    |
     |                 |
   Lesen            Schreiben

und noch eins: 1

    +---+---+---+---+---+---+---+---+
    | g | b | c | 1 | 2 | d | e | f |
    +---+---+---+---+---+---+---+---+
      ^               ^
      +----------------+
     +----------------+|
     |                 |
   Lesen            Schreiben


Aber jetzt dauerts wieder in der Bearbeitung. In der Zwischenzeit
kommt das nächste über die Schnittstelle: A

    +---+---+---+---+---+---+---+---+
    | g | A | c | 1 | 2 | d | e | f |
    +---+---+---+---+---+---+---+---+
          ^           ^
          +------------+
     +----------------+|
     |                 |
   Lesen            Schreiben

usw. usw. Aufpassen muss man eigentlich nur, wenn der Ringbuffer
dann tatsächlich voll wird. Wenn in der jetzigen Situation 3 Zeichen
eintrudeln, dann gibt es ein Problem.


Viel Spass bei der Implementierung!

von Stephan H. (stephan-)


Lesenswert?

Karl Heinz,
du bist eine Sonne.....

von Karl H. (kbuchegg)


Lesenswert?

Stephan Henning wrote:
> Karl Heinz,
> du bist eine Sonne.....

Wenn möglich erkläre ich ihm lieber das Prinzip und lasse
ihn selbst an einer Implementierung arbeiten. Das ist zwar
für mich mehr Aufwand aber wenn ers dann durchzieht hat er
mehr davon als wenn ich ihm eine fertige Routine präsentiere.
Erfahrungsgemäß wird die nämlich einfach so übernommen ohne
zu verstehen was da eigentlich abgeht und wie's funktioniert.
Bei Problemen steht er dann da und weiß erst recht nicht wo
hinten und vorne ist.

Viele Algorithmen in der Programmierung sind eigentlich
unglaublich einfach. Wir benutzen sie jeden Tag im
täglichen Leben ohne uns dessen bewusst zu sein.

(Und ausserdem hasse ich nichts mehr als Leute die sich
stolz im Bekanntenkreis mit ihren Programmierkünsten
präsentieren und in Wirklichkeit keinen blassen Schimmer
davon haben, was sie da eigentlich gemacht haben. Mit
'Malen nach Zahlen' kann man mich nicht wirklich beeindrucken)

von ... .. (docean) Benutzerseite


Lesenswert?

Wau nette Erklärung zum Ringbuffer...

hier mal eine feritge UART Lib...
http://homepage.hispeed.ch/peterfleury/avr-software.html#libs
(und LCD Lib)

von Kulli (Gast)


Lesenswert?

hi
habs jetzt mal versucht selber zu schreiben.
Könnt ihr es kontrollieren? Bin mir nicht sicher wie man die Position 
des letzten Bytes abfragen kann.

so siehts aus:

.dseg
.equ  L_FIFO  =  128
FIFO_Data:  .byte  L_FIFO


init_FIFO:
    ldi XL,low(FIFO_Data)         ; read
    ldi XH,high(FIFO_Data)
    ldi YL,low(FIFO_Data)         ; write
    ldi YH,high(FIFO_Data)
ret


write_fifo:

    push temp1                ; temp auf dem Stack sichern
    in temp1, sreg            ; SREG sichern
    push temp1
    push temp2

    in temp1, UDR             ; UART Daten lesen
    st Y+, temp1

    ld temp2, Y
    cpi temp2, L_FIFO         ; Ende des Ringpuffers erreicht?
    brne no_reset_pointerY
    ldi YL,low(FIFO_Data)
    ldi YH,high(FIFO_Data)

  no_reset_pointerY:
   pop temp2
   pop temp1
   out sreg, temp1            ; SREG wiederherstellen
   pop temp1                 ; temp wiederherstellen

ret


read_fifo:
  push temp2
  ld r16, X+

  ld temp2, X
  cpi temp2, L_FIFO      ; Ende des Ringpuffers erreicht?
  brne no_reset_pointerX
  ldi XL,low(FIFO_Data)
  ldi XH,high(FIFO_Data)

  no_reset_pointerX:
  pop temp2
ret

von Spess53 (Gast)


Lesenswert?

Hi


>    ld temp2, Y ?????????????

Wenn schon, dann 'mov temp2,XL'.

Wenn man eine 2er-Potenz als Puffergrösse und eine günstige Stelle im 
RAM für den Puffer wählt kann man die Prüfung des Pufferendes durch eine 
AND-Operation ersetzen:

   .dseg
   .org $0000

Puffer:   .db 128


   .cseg

.....
   clr XL             ; Pointer initialisieren
   clr XH

.....

   ld temp2,X+
   andi XL,0b01111111 ; XL wird bei 128 wieder 0

MfG Spess

von Kulli (Gast)


Lesenswert?

Bei mir fängt der RAM erst ab $0060 an. Wie kann ich nun auf das Ende 
des Pufferendes Überprüfen?

von TheMason (Gast)


Lesenswert?

@karl heinz

echt schön beschrieben :-)
wunnerbar !

von Hannes L. (hannes)


Lesenswert?

Kulli wrote:
> Bei mir fängt der RAM erst ab $0060 an. Wie kann ich nun auf das Ende
> des Pufferendes Überprüfen?

Im Falle des Y-Pointers:

.def buffersize=32

.dseg
.org sram_start
buffer:  .byte 32

.cseg

;...

 st y+,tmp
 cpi yl,buffer+buffersize
 brne weg_hier
 ldi yl,low(buffer)
 ldi xh,high(buffer)
weg_hier:

...

von Kulli (Gast)


Angehängte Dateien:

Lesenswert?

Hallo danke an alle, nun funktioniert es.
Auch nochmal von mir ein Dank an Karl-Heinz.

Hat ja lange genug gedauert. Aber im Endeffekt ist es wirklich nicht 
schwer. Wie gesagt, das kommt wenn man nicht viel Ahnung in Assembler 
hat. Kann man das Ganze eigentlich auch mit nur einem Pointer 
realisieren?


@Karl-Heinz
Ich hatte im Netz ja nur nach Ring-Buffern geschaut, um überhaupt 
irgendetwas zu dem Prinzip zu finden. Selbst wenn ich fertige Routinen 
nutze, versuche ich schon diese nachzuvollziehen.

>Und ausserdem hasse ich nichts mehr als Leute die sich stolz im >Bekanntenkreis 
mit ihren Programmierkünsten präsentieren und in Wirklichkeit >keinen blassen 
Schimmer davon haben, was sie da eigentlich gemacht haben.

-->Das wird bei mir noch dauern. Bis ich das Projekt endlich fertig 
habe, kanns noch ne Weile dauern ;-)

Also nochmal vielen Dank

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.