Forum: Mikrocontroller und Digitale Elektronik Probleme mit UART Mega8


von Alexander Arndt (Gast)


Lesenswert?

Hallo,

kann mir jemand mit folgenden Problem helfen :

Ich bin dabei, einen Converter für ein serielles LCD zu bauen, damit
über den UART Txd ein Display mit einfachen Printbefehlen steuern
kann.

Aber :

Ich möchte gerne auswerten, wenn ein String übertragen wurde, also
CHR(10) bzw. (13) gesendet wird.

Ich arbeitet mit dem UDR-Register, welches o.g. "ASCII-Zahlen)
überträgt.

Wenn ich aber den Interupt auslöse onRXD und sage
if udr = 10 then "string-Ende"

reagiert er garnicht, auch nicht bei UDR = 13, nämling dann soll der
"fertige" String übergeben werden und zur Anzeige kommen.

Vielleicht kann mir jemand helfen...?

Gruss
Alex

von Karl heinz B. (heinzi)


Lesenswert?

Du musst schon Dein Program herzeigen, damit wir Dir
sagen koennen was daran nicht stimmt.

von Hannes L. (hannes)


Lesenswert?

Alle empfangenen Zeichen in einen Ringbuffer im SRAM ablegen. Dabei
immer die letzten beiden Zeichen auf 10 und 13 prüfen. Der Ringbuffer
sollte so groß sein, dass er den maximal möglichen String fassen kann.

Der Einfachheit halber kann man das zuletzt empfangene Zeichen auch in
einem weiteren Register halten, so wird das Prüfen des letzten und des
aktuellen Bytes (mit CPI) bequemer (da ohne Zugriff auf den Buffer).

Ein ähnliches System habe ich auch im Hinterkopf, allerdings ist mir
der Mega8 dazu etwas zu groß (Overkill), der Tiny2313 hat mir aber
etwas zuwenig SRAM (für Ringbuffer) für ein 8x24-LCD.

...

von A. Arndt (Gast)


Lesenswert?

Hallo,

ich nutze BASCOM und verstehe nicht, warum if udr = 13 then ... nicht
anschlägt..

Ich poste nochmal das Listing, am WE...

Gruss

von Hannes L. (hannes)


Lesenswert?

Ich verstehe BASCOM nicht, nur Assembler...

...

von Marko (Gast)


Lesenswert?

du verwendes inkey vermute ich als Eingabesequenz

Das gibt dir den ASC vom eingegangenen Wert an.

Ist kein Zeichen im Puffer gibts 0 zurück.

Der Print gibt die nachfolgenden Zeichen auf der UART aus + CR + LF,
es sei denn du brungst nach dem Print und Zeichenfolge ein ; Semikilon,
dann bringt er das nicht.

kuck mal ob du Semikolon al Abschluss von deinem Print hast, wenn ja,
dann raus damit

von A. Arndt (Gast)


Lesenswert?

Hallo,

@ Marko

Ich nutze diese Geschichte mit Interrupt, wenn ein Zeichen auf Uart
empfangen wurde...

OnRXD

und dann

im Interupt

"Sting1" = "String1" + chr(udr)

Also packe immer ein Zeichen dazu

und dann möchte ich, wenn udr = 10 then "String2" = "String1"

also vollständigen String übergeben und dann

lcd "String2"

Gruss
A. Arndt

von Hannes L. (hannes)


Lesenswert?

> ich nutze BASCOM und verstehe nicht, warum if udr = 13 then ...
> nicht anschlägt..

<Spekulation>

Das I/O-Register "udr" behält seinen Wert nicht bis in alle
Ewigkeit.
Wenn man in ASM (also Maschinensprache) darauf zugreift, dann ist der
Inhalt anschließend weg.
In ASM muss man auch udr in ein Register einlesen (in temp,udr) und
dann das Register überprüfen oder in den String (SRAM-Bereich)
kopieren.

Vielleicht sollte man (auch in Basic) mit einer Hilfsvariablen
arbeiten. Also (QBASIC-Syntax):

temp=udr
if temp=10 then
 string2=string1
 string1=""
else
 string1=string1+temp
endif

Allerdings würde das Stringkopieren für eine ISR zu lange dauern, in
ASM setze ich mir für sowas in einem reservierten Register ein Bit als
Flag (Variable vom Typ Boolean, davon bis zu 8 Stück für verschiedene
Zwecke in einem gemeinsamen Register), worauf das Hauptprogramm den
etwas aufwendigeren Job (hier das Kopieren des Strings, Löschen des
Empfangsstrings und die anschließende Ausgabe an das LCD) übernimmt.

ISRs müssen nämlich so kurz wie möglich sein, sonst besteht die Gefahr,
dass Interrupts verschluckt werden.

In der ISR würde dann stehen (QBASIC-Syntax):

temp=udr
if temp=10 then
  flags=flags or 1
else
  string1=string1+temp
endif

In der Mainloop wird dann zyklisch "flags" abgefragt:

do
  'andere Mainloop-Jobs...
  if flags and 1 then
    flags=flags and (255-1)  'Flag löschen
    string2=string1          'String kopieren
    string1=""               'RX-String löschen
    lcd string2              'String an LCD
  endif
loop

</Spekulation>

Wie gesagt, QBASIC-Syntax (außer "lcd"), BASCOM kenne ich nicht
weiter, AVRs programmiere ich in ASM, das bietet viel mehr Freiheiten
und Übersichtlichkeit (ASM ist eindeutig...).

Aber ganz so einfach wird das auch nicht, denn die LCD-Ausgabe ist
relativ langsam, da das LCD nach jedem Byte beschäftigt ist und die
Ausgaberoutine entweder mit Wartezeiten arbeitet oder das Busy-Flag des
LCDs abfragt (und auch nur wartet).
Dies ist ein Grund, weshalb ich inzwischen meine LCD-Ausgaben über
Ringbuffer laufen lasse und die Zeichenausgabe vom Ringbuffer zum LCD
über Timer (und Jobflag) synchronisiere. Somit wird das nächste Zeichen
immer erst ausgegeben, wenn der nächste "Termin" ran ist. Dazwischen
wird nicht gewartet, sondern die Mainloop durchlaufen und "geschaut,
was es sonst noch so zu tun gibt", also alle Jobflags und ggf.
Tastenflags der Entprellung abgefragt.

...

von Marko (Gast)


Lesenswert?

schon klar, so oder so,
der chr 10 /13 muss aber gesendet werden und den Int auslösen.
Den Int löst jedes Zeichen ausser chr(0) aus.

ich denk aber auf der print-seite haste den semikolon drinne.

von Alexander Arndt (Gast)


Lesenswert?

Hallo,

hier endlich mein Code :


$crystal = 12000000                                         '
frequency used
$baud = 9600
                                               ' baud rate
Config Portb.1 = Output

Config Portd.5 = Output
Config Portc.1 = Output

Config Lcdpin = Pin , Db4 = Portb.5 , Db5 = Portb.4 , Db6 = Portb.3 ,
Db7 = Portd.6 , E = Portd.7 , Rs = Portb.0
Config Lcd = 20 * 4

Config Timer1 = Pwm , Pwm = 8 , Prescale = 1 , Compare A Pwm = Clear Up
, Compare B Pwm = Clear Down

Dim Lcd_contrast As Byte
Dim Backlight As Byte
Enable Interrupts

Dim Inco As String * 16
Dim Incom As String * 16
On Urxc Onrxd
Enable Interrupts
Enable Urxc

Lcd_contrast = 190
Backlight = 60


Pwm1a = Lcd_contrast
Pwm1b = Backlight

Initlcd
Cursor Off
Cls


Locate 1 , 1
Lcd " Serielles LCD V1.0"


Linestart:
If Inco <> "" Then Goto Show
Print "gesend. Char :" ; Incom
Wait 1
Goto Linestart
Show:
Locate 4 , 1
Lcd "                    "
Locate 4 , 1
Lcd " Data:" ; Inco

Print Incom
Wait 2
Incom = ""
Goto Linestart


End

Onrxd:
Incom = Incom + Chr(udr)
If Udr = 13 Then Inco = Incom


Return

********************** E N D E **************************

Ich möchte doch nur, wenn eine String vollständig ist, also die Sendung
von ASCII 10 + 13 das der "gesammelte" Sting incom zu inco vollständig
übergeben wird....

H I L F E

Gruss
A. Arndt

von Alexander Arndt (Gast)


Lesenswert?

Hallo nochmal,

warum ist eigentlich die Quarzfrequenz für den Uart-Betrieb so von
Bedeutung ?

Gruss
Alexander

von Hegy (Gast)


Lesenswert?

Kussu mal ins Datasheet. Da steht eine Abbildung drin, woraus sich die
U(S)ART die Taktfrequenz (Schieberegister) aus dem Quarz holt. Diese
Frequenz wird noch geteilt und dann mittels des UBRRx weiter geteilt.
Letztenendes ergibt das dann eben 9600 Hertz z.B.

von Hannes L. (hannes)


Lesenswert?

UART taktet mit dem 16-fachen der Baudrate.

Nun nimm mal übliche Baudraten mal 16 und nimm davon das kleinste
gemeinsame Vielfache. Nun multipliziere das mit Ganzzahlen und schau
dir die Werte mal an, besonders die, die in der Nähe der Max-Werte der
AVRs liegen. Und dann vergleiche deine Ergebnisse mal mit den Tabellen
für Baudraten in den AVR-Datenblättern im Kapitel U(S)ART.

Dann bedenke, dass alles eine gewisse Toleranz hat. Auch die Baudrate
des PCs. Ein kleiner Baudratenfehler (z.B. wegen eines Standardquarzes
aus deinem Sortiment) kann ohne Weiteres mit dem PC funktionieren,
falls der PC auch in die gleiche Richtung abweicht. Weicht er in die
andere Richtung ab, dann wird es knapp, dann kann es passieren, dass
die Abtastpunkte des Empfängers im Laufe der 10...12 Bits nicht mehr
das Bit treffen, sondern davor oder danach. Uns schon gibt's Müll.

Mit Quarzen, die ein Vielfaches von 1,8432MHz haben, bleibt man aber
mit Sicherheit in der Toleranzgrenze.

Es würde deinem Shop sicher nicht schaden, wenn du die Rubrik
"Baudratenquarze für Mikrocontroller" eröffnest und die Reihe:
  1,8432MHz,
  3,6864MHz,
  7,3728MHz,
 14,7456MHz,
 18,4320MHz
beschaffst und anbietest.

Plane mich aber bitte nicht mehr ein, ich habe mich bereits bei CSD
eingedeckt, weil Reichelt sie nicht hatte. ;-)

Dein BASCOM-Programm ist mir zu kryptisch (ich kann kein BASCOM), sei
mir nicht böse, wenn ich mich damit nicht befasse.
Leider habe ich kein LCD 4X20, also kann ich auch kein entsprechendes
Programm in ASM schreiben. Eine Version für 4x27 (Pollin) nützt dir ja
nix, das hat ja 2 Controller und ist daher nicht kompatibel. Auch die
Version für 8x24 nützt nix, sie hat ja den Controller MS50530.

...

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.