www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Länge von UART-String begrenzt, BASCOM, Atmega8


Autor: Martin Zippel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schönen guten Abend!
Ich hänge jetzt schon seit mehreren Stunden an diesem Problem und weiß 
mir keinen Rat mehr. Darum versuch ich mein Glück hier.
Ich habe einen Atmega8 als Master, der über die UART mit einem zweiten 
Atmega8 verbunden ist.
Am Slave hängt ein LCD, dass den über die UART gesendeten Text anzeigen 
soll.

Hier der BASCOM-Code für den Master:
------------------------------------------------------------------------ 
---
$regfile "m8def.dat"
$crystal = 1000000
Config Com1 = 4800 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

Config Portd = &b111111100                     'UART-Port

Declare Sub Anzeigen(byval Text As String)     'als Parameter der Text, der versendet werden soll

Do
Call Anzeigen( "hallo")                                         'Unterprorgamm aufrufen, den Text in Anführungszeichen per UARt verschicken
Waitms 100                                     'kurz warten
Loop

Sub Anzeigen(byval Text As String)
Portd.5 = 1                                    'richtigen "Slave" aussuchen
Portd.6 = 0
Portd.7 = 0
Print Text                                     'an Unterprorgamm übergebenen Text über UART senden
End Sub
------------------------------------------------------------------------ 
---

Hier der Slave-Code:

------------------------------------------------------------------------ 
---
$regfile "m8def.dat"
$crystal = 1000000
Config Com1 = 4800 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Echo Off                                   'empfangene Zeichen werden nicht zurückgeschickt

Config Portd = &b000111100
Portd = 0

Config Lcdbus = 4
Config Lcdpin = Pin , Rs = Portb.5 , E = Portb.4 , Db4 = Portb.3 , Db5 = Portb.2 , Db6 = Portb.1 , Db7 = Portb.0

Config Lcd = 40 * 2                         'LC-Display konfigurieren
Waitms 100                                  'auf Initialisierung des LCD warten

'Deflcdchar 0 , 8 , 2 , 8 , 2 , 2 , 32 , 4 , 8               'erstes Zeichen wird definiert
'Deflcdchar 1 , 32 , 8 , 20 , 2 , 1 , 32 , 32 , 32           'zweites Zeichen wird definiert

Cls                                         'cls ist wichtig und MUSS nach den Definitionen kommen!

Declare Sub Anzeigen(byval Text As String)  'Text auf LCD anzeigen
Declare Sub Anzeigen2(byval Length As Byte) 'Länge des empfangenen Textes anzeigen
Dim Uart As String * 10
Dim Lange As Byte

Do
If Pind.5 = 1 Then                          'nur wenn der master mit diesem slave reden will
Input Uart                                  'Was über die uart kommt wird in der Variablen uart gespeichert
Lange = Len(uart)                           'Länge des erhaltenen Textes abfragen
Call Anzeigen2(lange)                       'Länge ausgeben
Call Anzeigen(uart)                         'Text ausgeben
End If
Waitms 1000                                 'kurz warten
Loop

Sub Anzeigen2(byval Length As Byte)
Locate 2 , 1
Lcd Length
End Sub

Sub Anzeigen(byval Text As String)
Locate 1 , 1
Lcd Text
End Sub
------------------------------------------------------------------------ 
---

Es soll noch andere Slaves geben, im Moment sind aber nur diese zwei 
Freunde miteinander verbunden.
Die Übertragung klappt (fast) problemlos, wenn man nur 5 Zeichen 
eingibt:
Das erste Zeichen auf dem LCD ist ein schwarzer Balken, dann kommt hall 
(ohne o).
Sobald man aber die Stringlänge von UART auf etwas über 5 festlegt
sobald aber der Text länger wird, wird nichts mehr angezeigt.
Die Länge des gesendeten Textes wird als (tatsächliche Zeichen + 3) 
ausgegeben. Beim hallo also 8.
Ich vermute einfach mal, dass das erste zusätzliche Zeichen das 
Startbit, das vorletzte CR und das letzte der Zeilensprung ist.
Der Balken ganz vorn stört mich eigentlich gar nicht, mein Problem ist, 
dass eben bei einem Text länger als 5 in der oberen Zeile nichts steht 
und in der zweiten Zeile dann eben.

Und während ich das hier schreibe, kappt mittlerweile nicht mal mehr das 
richtig: wenn "hallo" gesendet werden soll, kommt nur noch 
Balken-h-Balken-ha

Hm, ich hab bis jetzt schon so einiges ausprobiert und bin mittlerweile 
gänzlich verwirrt.
- Ich hab vermutet, dass die Zeit des LCD-Slaves nicht reicht, um die 
UART zu lesen. Aber die beiden sollten ja miteinander reden, also der 
eine auf den anderen warten.
- ich habe längere und kürzere Strings verschickt
- Stringlänge vom Slave verkürzt, verlängert...
- diese Abfrage nach der gesendeten Textlänge eingeführt
- Außerdem hatte ich die Idee, dass der Text zwar richtig ankommt, aber 
nicht richtig angezeigt wird, zB durch zwei Zeilenumbrüche (oder wie 
auch immer). Aber das Beschneiden des Strings mit Mid(uart, 2,2) hat 
auch nichts gebracht.

Tja, wenn jemand einen Tipp hat, würde ich mich sehr freuen...!

Autor: Martin Zippel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dazu hat keiner eine Idee?

Autor: Rainer Unsinn (r-u)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Teste Deine beiden Teile separat mit PC und Hyperterminal (oder einem 
anderen Terminalprogramm). Dann siehst Du, ob Dein Sender richtig sendet 
("Hallo" auf dem Bildschirm) und Du kannst Zeichen eintippen und gucken, 
ob sie auf dem Display richtig ankommen.

Autor: Joachim R. (bastelbaer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Martin,
folgendes von meiner Seite dazu.
Ich vermute mal, dass du beim Einlesen deshalb Probleme bekommst, weil 
im Datenpuffer noch ein Zeichen steckt. Du sendest Daten die von deinem 
Atmel auch empfangen werden. Nach dem Print wird ein CR/LF gesendet. 
Also ist in deinem Puffer als letztes Zeichen ein LF drin. Startest du 
jetzt die Input-Routine liest die das LF und den folgenden Text ein. Das 
könnte der Balken am Anfang sein.
Ich würde dir folgenden Vorschlag zum probieren machen.
SENDER:
Sub Anzeigen(byval Text As String)
  Portd.5 = 1        'richtigen "Slave" aussuchen
  Portd.6 = 0
  Portd.7 = 0
  Waitms 10 ' kann man anpassen
  Print Text        'an Unterprorgamm übergebenen Text über UART senden
End Sub


EMPFÄNGER:
Dim Char as Byte
' damit hast du ne interruptgesteuertes Einlesen im Hintergrund
Config Serialin = Buffered , Size = 10 ' 10Byte Puffer für Serielle
Enable Interrupts                            ' Timer und seriell


Do
  ' immer mal wieder den Puffer leeren
  Do
    char = Inkey() ' einlesen bis nix mehr da ist, Puffer leeren
  Loop Until char = 0


  If Pind.5 = 1 Then ' Ist was für mich
    ' jetzt sollte die Waitms vom Sender ablaufen
    Input Uart....

    ' ich würde aber ein zeichenweises einlesen bevorzugen, da du damit
    ' auch Timeouts abfangen kannst, z.B.
    Uart=""
    Waitfor_ok=0
    While Waitfor_ok = 0
      If Ischarwaiting() = 1 Then ' wenn was da ist
        Char = Waitkey()    ' einlesen
        Select Case char     ' und auswerten
        Case 13           ' ignorieren
        Case 10            ' LF empfangen, Zeile da
          Waitfor_ok=1  ' wenn ja, beenden (1=ok)
        Case Else ' normales Zeichen zu String dabeimachen
          Uart = Uart + Chr(char)
          ' hier z.B. Timeout=MaxWartezeit
        End Select
        ' hier könnten z.B. Timeoutroutinen stehen
        ' If Timeout=0 Then Waitfor_ok=2 (2=timeout)
      End If
    Wend
    Lange = Len(uart)
    Call Anzeigen2(lange)                       'Länge ausgeben
    Call Anzeigen(uart)                         'Text ausgeben
  End If
Loop

Mit dem zeichenweisen Einlesen kannst du auch die Adressierung über die 
Pins ersetzen indem du z.B. mit 9 Datenbits arbeitest und das 9.Bit den 
Start der Datenübertragung anzeigt und gleichzeitig die Slaveadresse 
ist. Geht natürlich auch etwas einfacher mit dem 8.Datenbit solange du 
nur Text versendest. Also bei 8 Bit ne Abfrage a la:
Do
  If Ischarwaiting() = 1 Then ' wenn was da ist
    Char = Waitkey()    ' einlesen
    If Char.7=1 Then    ' ist erstes Byte und Adresse
      Reset Char.7   ' Kennungsbit löschen
      If Char=Slaveadresse Then ' und sehen obs die Adresse ist
        uart=""  ' und weiter gehts
        waitfor_ok=0.......


oder alles in eine Interruptroutine auslagern, das ist das allerbeste.
Puh, jetzt hab ich hoffentlich alle Varianten drin.

Autor: Martin Zippel (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Schönen guten Morgen!

Also auf die Idee, das am Terminal zu testen, hätt ich auch selbst mal 
kommen können. Zumal auch das Kabel zum PC schon am Master steckt...
Da hab ich wohl einfach schon zu lang gesessen, um drauf zu kommen.
Wie dem auch sei, wenn ich den schwarzen Freund auf dem Programmierbrett 
lasse und per avrterm abfrage, passiert (ähnlich wie gestern) folgendes:
Wenn der String 5 Zeichen lang ist, geht's, dann kommt im Terminal ein 
Viereck, das Wort und wieder zwei Vierecke.
Sieht also so aus wie Startbit, String, CR und LF
Das hab ich mal als Bild angehängt. Am Anfang kommen komische Zeichen 
ich nehme mal an, das  liegt daran, dass ich das "UART-Kabel" erst 
einstecke, wenn der schon läuft (& sendet) und somit erstmal Unfug 
ankommt.
Sobald der String länger als 5 Buchstaben ist, kommen nur noch diese 
Vierecke.
Ich habe auch versucht, zwei Strings zu schicken:
Call Anzeigen( "hallo" + "hallo")
Das bringt auch nichts.

Ich hänge nochmal den Quellcode vom Master an:
$regfile "m8def.dat"

$crystal = 1000000
uart einstellen
Config Com1 = 4800 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

Config Portd = &B111111100                                  'UART-Port

Declare Sub Anzeigen(byval Text As String)                  'als Parameter der Text, der versendet werden soll

Do
Call Anzeigen( "hallo")                                     'Unterprorgamm aufrufen, den Text in Anführungszeichen per UARt verschicken
Waitms 100                                                  'kurz warten
Loop

Sub Anzeigen(byval Text As String)
Portd.5 = 1                                                 'richtigen "Slave" aussuchen
Portd.6 = 0
Portd.7 = 0
Print Text                                                  'an Unterprorgamm übergebenen Text über UART senden
End Sub

@ Joachim: ich danke dir für deinen langen Beitrag.
Das mit der "Lange" hatte ich übrigens nur zum Testen drin, um zu sehen, 
was der slave als Stringlänge empfängt.
Ich denke, ich habe deinen Code so weit verstanden, allerdings ist mir 
nicht ganz klar, woher die case 10 & case 13 kommen?
Ist die 10 der Code für LF und die 13 für CR?
Also ist das generell der Code, weil ich kann nirgends sehen, dass du 
die definiert hast.

Autor: Martin Zippel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich noch vergessen habe:
Ich hatte auch darüber nachgedacht, das ganze zeichenweise zu 
verschicken, allerdings glaubte ich nicht, das "5er"-Problem so lösen zu 
können. Und, naja, die UART einfach mit "input" auszulesen ist schon 
ganz schön bequem...

Autor: Rainer Unsinn (r-u)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Kauderwelsch am Anfang kommt vom Einstecken oder was Anderes. Du 
siehst hello, dann zwei Vierecke (CR, LF oder 13 und 10 dezimal oder 0d 
0a hexadezimal) Wenn Du das nicht willst, ergänze Deine Zeile um ein 
Semikolon:

Print Text;

Autor: Joachim R. (bastelbaer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Martin,
10 ist der ASCII-Wert für LF und 13 der Wert für CR. Wenn also ein CR 
über die Schnittstelle kommt, dann wird das Zeichen ignoriert, erst wenn 
LF kommt wird davon ausgegangen, dass die Daten komplett sind.

Wie gesagt, ich würde, wenn du mit deiner PIN-Version weiterarbeiten 
willst, permanent den seriellen Puffer auslesen und dadurch löschen. 
Dann, wenn PIN gesetzt wird, evtl. noch ein extra Puffer leeren und dann 
an's Einlesen gehen. Du kannst ja auch bei Empfang des LF prüfen ob dein 
String die entsprechende Länge hat und die Daten ggf. verwerfen.
Oder halt mit Startbyte/bit, Längenangabe und z.B. CRC am Schluss. Das 
macht die Sache sicher, kostet aber etwas Code.

Was hast du denn eigentlich genau vor?

Autor: Martin Zippel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Seit meinem letzten Post hat sich nichts getan, ich hab nämlich 
geschlafen.
Ich hab eine alte Digitalkamera auseiandergenommen und den Auslöser an 
zwei Relais gehängt (man muss da zwei Kontakte hintereinander schalten).
Ein Atmega steuert also, wann wie wo ein Foto gemacht wird.
Naja, dann habe ich noch einen Schrittmotor über einen Motortreiber an 
einem Atmega8 und eben einen Atmega für das Display.
Der Zweck ist, dass die Kamera zeitgesteuert Fotos macht und sich dann 
dreht.
Dann kann man zum Beispiel jede Stunde automatisch ein Panoramabild 
machen lassen oder so etwas.
Naja, wahrscheinlich hätte ein Atmega128 genug Pins, um alle Aufgaben 
allein zu lösen, aber ich wollte an dem Ding vor allem was lernen.
Gerade so ein Master-Slave-System hat mich schon länger interessiert.
Um den richtigen Slave zu finden würden auch zwei Leitungen reichen, da 
es ja nur 3 Slaves gibt. Aber für den Fall, dass da später mal was 
drankommt, hab ich 3 Leitungen genommen.
Außerdem hab ich die 8er genommen, weil...ich davon genug habe.
Am Motorenslave sind schon die Leitungen vorbereitet, um einen 
Endlageschalter abzufragen (der hier: 
http://www.reichelt.de/?ACTION=3;ARTICLE=73929;PROVID=2402)
Die Aufgabe dieses Slaves soll dann sein, die vom Master verschickte 
Anzahl an Schritten nach links oder rechts zu drehen. Wenn er 360° 
erreicht hat, soll er das merken und sich automatisch um einen 
entsprechenden Winkel zurückdrehen. Das soll vermeiden, dass sich das 
Kabel um den ganzen Aufbau wickelt.
Also wenn der Meister ruft: dreh dich um 40° nach links, der Slave aber 
schon bei 330° steht, dreht automatisch um 310° nach rechts.

Aber zuvor möchte ich, dass die Sache mit der UART wirklich läuft.
Am Display kann ich das wohl noch am ehesten testen, wenn der Motor 
nicht macht, was er soll such ich mich ja dumm&dusslig.
Das Display habe ich hauptsächlich zu Kontrolle vorgesehen, damit ich 
zum Beispiel in Fällen wie eben diesem weiterkomme.
Wie gesagt, Hauptaufgabe des ganzen Aufbau ist es, dass dieses Bussystem 
funktioniert.
Schrittmotor ansteuern, LCD betreiben, Kamera schalten, jeweils für sich 
hab ich das alles schon mal gemacht.

Autor: Martin Zippel (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab vergessen, das Bild anzuhängen.

Dann werde ich das mit der bitweisen Übertragung mal probieren (müssen).
Allerdings, besteht das Problem ja (meiner Meiung nach) schon beim 
Master, da der PC ja auch nichts mehr erkennt, wenn der String länger 
als 5 Zeichen ist. Und dem Rechner kann ich ja nicht vorschreiben, ob er 
die Daten zeichenweise einlesen soll, oder?!

Autor: Joachim R. (bastelbaer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klar kannst du dem PC vorschreiben wie er einliest, nennt sich 
programmieren :-).
Aber Scherz beiseite. Dein Master sendet im Normalfall immer korrekt, 
auch bei dir. Das Problem ist, das der Slave Müll im Puffer stehen haben 
kann, gilt auch für den PC als Slave. Du musst also erst mal dafür 
sorgen, dass du erst Daten einliest wenn es nötig ist.

Als weitere Alternative schau mal unter
http://www.fakedomain.de/elektronik/servocam/index.htm
nach. Da hab ich das Ganze mit Interrupts gemacht. Die Routine läuft 
ohne Probleme egal wann oder wie die Daten gesendet werden. Du müsstest 
nur noch die Abfrage deines PINs in die Interruptroutine reinbauen. Was 
immer wichtig ist, wäre eine Bestätigung des Slaves, dass die Daten 
empfangen wurden. Dann kannst du im Fehlerfall die Daten erneut senden.

Autor: Peter R. (peterfido)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Stringlänge sollte noch mit angegeben werden.
Ich nutze selten bis gar nicht solche Deklarierten Subs sondern springe 
meist mit gosub. Hier mal der Kern des Senders.


dim sendetext as string*20 'maximal 20 Zeichen

do
sendetext="Hallo"
gosub textsenden
waitms 125
loop
end

textsenden:
print sendetext
return

Autor: Martin Zippel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich werd bekloppt...
Da hab ich nun so lange dran gesessen und das war die Lösung...
Ich nutze die Subprogramme sonst auch in der Art, wie du das gepostet 
hast. Nur hier habe ich das anders probiert, weil ich das mit dem Text 
als Parameter für wesentlich eleganter halte.
Aber so funktioniert es tadellos (mit dem Rechner als Slave zumindest).
Hm, back to the roots wär die Lösung gewesen.

Ich danke für eure Posts und werde mich jetzt an den Motorenslave machen 
(wenn der LCD-Slave auch mitmacht, aber da bin ich guter Dinge).

Autor: Martin Zippel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollt mich nochmal für die Hilfe bedanken.
Mittlerweile läuft auch der "Antreiber" vom Schrittmotor schon richtig 
gut, findet am Anfang seine Ausgangslage per Interrupt und läuft so 
viele Schritte in die richtige Richtung, wie es ihm sein Herr & Meister 
befiehlt.
Die drei scheinen sich prächtig zu verstehen ;-)

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.