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


von Martin Zippel (Gast)


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:
------------------------------------------------------------------------ 
---
1
$regfile "m8def.dat"
2
$crystal = 1000000
3
Config Com1 = 4800 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
4
5
Config Portd = &b111111100                     'UART-Port
6
7
Declare Sub Anzeigen(byval Text As String)     'als Parameter der Text, der versendet werden soll
8
9
Do
10
Call Anzeigen( "hallo")                                         'Unterprorgamm aufrufen, den Text in Anführungszeichen per UARt verschicken
11
Waitms 100                                     'kurz warten
12
Loop
13
14
Sub Anzeigen(byval Text As String)
15
Portd.5 = 1                                    'richtigen "Slave" aussuchen
16
Portd.6 = 0
17
Portd.7 = 0
18
Print Text                                     'an Unterprorgamm übergebenen Text über UART senden
19
End Sub
------------------------------------------------------------------------ 
---

Hier der Slave-Code:

------------------------------------------------------------------------ 
---
1
$regfile "m8def.dat"
2
$crystal = 1000000
3
Config Com1 = 4800 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
4
Echo Off                                   'empfangene Zeichen werden nicht zurückgeschickt
5
6
Config Portd = &b000111100
7
Portd = 0
8
9
Config Lcdbus = 4
10
Config Lcdpin = Pin , Rs = Portb.5 , E = Portb.4 , Db4 = Portb.3 , Db5 = Portb.2 , Db6 = Portb.1 , Db7 = Portb.0
11
12
Config Lcd = 40 * 2                         'LC-Display konfigurieren
13
Waitms 100                                  'auf Initialisierung des LCD warten
14
15
'Deflcdchar 0 , 8 , 2 , 8 , 2 , 2 , 32 , 4 , 8               'erstes Zeichen wird definiert
16
'Deflcdchar 1 , 32 , 8 , 20 , 2 , 1 , 32 , 32 , 32           'zweites Zeichen wird definiert
17
18
Cls                                         'cls ist wichtig und MUSS nach den Definitionen kommen!
19
20
Declare Sub Anzeigen(byval Text As String)  'Text auf LCD anzeigen
21
Declare Sub Anzeigen2(byval Length As Byte) 'Länge des empfangenen Textes anzeigen
22
Dim Uart As String * 10
23
Dim Lange As Byte
24
25
Do
26
If Pind.5 = 1 Then                          'nur wenn der master mit diesem slave reden will
27
Input Uart                                  'Was über die uart kommt wird in der Variablen uart gespeichert
28
Lange = Len(uart)                           'Länge des erhaltenen Textes abfragen
29
Call Anzeigen2(lange)                       'Länge ausgeben
30
Call Anzeigen(uart)                         'Text ausgeben
31
End If
32
Waitms 1000                                 'kurz warten
33
Loop
34
35
Sub Anzeigen2(byval Length As Byte)
36
Locate 2 , 1
37
Lcd Length
38
End Sub
39
40
Sub Anzeigen(byval Text As String)
41
Locate 1 , 1
42
Lcd Text
43
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...!

von Martin Zippel (Gast)


Lesenswert?

Dazu hat keiner eine Idee?

von Rainer U. (r-u)


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.

von Joachim R. (bastelbaer)


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.

von Martin Zippel (Gast)


Angehängte Dateien:

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:
1
Call Anzeigen( "hallo" + "hallo")
Das bringt auch nichts.

Ich hänge nochmal den Quellcode vom Master an:
1
$regfile "m8def.dat"
2
3
$crystal = 1000000
4
uart einstellen
5
Config Com1 = 4800 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
6
7
Config Portd = &B111111100                                  'UART-Port
8
9
Declare Sub Anzeigen(byval Text As String)                  'als Parameter der Text, der versendet werden soll
10
11
Do
12
Call Anzeigen( "hallo")                                     'Unterprorgamm aufrufen, den Text in Anführungszeichen per UARt verschicken
13
Waitms 100                                                  'kurz warten
14
Loop
15
16
Sub Anzeigen(byval Text As String)
17
Portd.5 = 1                                                 'richtigen "Slave" aussuchen
18
Portd.6 = 0
19
Portd.7 = 0
20
Print Text                                                  'an Unterprorgamm übergebenen Text über UART senden
21
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.

von Martin Zippel (Gast)


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...

von Rainer U. (r-u)


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;

von Joachim R. (bastelbaer)


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?

von Martin Zippel (Gast)


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.

von Martin Zippel (Gast)


Angehängte Dateien:

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?!

von Joachim R. (bastelbaer)


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.

von Peter R. (peterfido)


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

von Martin Zippel (Gast)


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).

von Martin Zippel (Gast)


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 ;-)

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.