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:
------------------------------------------------------------------------
---
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:
------------------------------------------------------------------------
---
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...!
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.
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.
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:
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.
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...
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;
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?
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.
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?!
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.
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
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).
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 ;-)