PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Soft UART sendet, empfängt aber nicht



panier
01.01.2012, 12:03
Hallo zusammen,
und das Neue Jahr fängt nicht besser an, als das alte aufgehöhrt hat. :mad:
Ich hoffe Euer Start ist besser als meiner.

Problem: Mit dem RN-Minicontrol will ich am PC eingegebene Texte an das RN-Funk übergeben und gleichzeitig am PC den Empfang kontrollieren. Damit ist die RS232 für den PC erforderlich, das RN-Funk muss über eine Soft UART angesprochen werden (der Max ist beim RN-Runk entfernt).
Auf der anderen Seite der Funkstrecke sitzt ein RNmega128 mit Easyradio on Board, der allerdings 2 UARTs hat und damit an dem 2ten PC problemlos funktioniert.
Die Soft UART des RN-Minicontrol kann problemlos senden (es kommt alles am RN128 bzw. 2ten PC an), aber der Empfang ist mal da mal nicht, mal verstümmelt, mal genau 2 Zeichen (je nach Code Version und nicht klar reproduzierbar).
Getestet habe ich verschiedene Ports (auch PD3 mit INT1), in zig Kombinationen mit Buffer und ohne .....
Getestet habe ich auch eine Verbindung vom Funk (in) eine Kabelverbindung auf PD3 (--> Int1 Interrupt) was gar nicht funktioniert hat....
Ebenso hatte ich die Empfangsabfrage im Int1 --> da kam mal was ....

Könnt Ihr bitte mal drüber schauen --> ich bin mittlerweile betriebsblind


'################################################# #############
'
'Aufgabe:
' Lese alle Bytes vom Funk und gebe diese auf RS232 aus
' Lese alle Bytes vom PC via RS232 und gebe diese auf Funk aus
'
'
' Verkabelung:
' JP5 --> Pin 5 (PD4) mit dem Funkmodul TTL RS232 OUT verbunden
' --> Pin 4 (PB4) mit dem Funkmodul TTL RS232 IN verbunden
'
' RS232 --> PC Kabel
'
'################################################# #############
$regfile = "m168def.dat" 'Prozessor
$crystal = 16000000 'Quarzfrequenz
$hwstack = 32
$framesize = 32
$swstack = 32
$baud = 19200 'Für RS232, für Funk in Soft UART angegeben
On Int1 Int1_int 'Wenn PD3 den Status ändert. Für Soft UART benötigt?
Enable Int1
Config Int1 = Falling 'Auch Rising schon getestet
Enable Interrupts
Dim Funkempfang As Integer
Dim D As Integer
Dim X As Byte
Dim S As String * 1
Dim Sendetext As String * 30
Dim Empfangtext As String * 30
Config Serialout = Buffered , Size = 100
Config Serialin = Buffered , Size = 100
' ---------- Ende der Deklarationen -----------------------------------------
Print "Warte ich boote ..." ' Ausgabe am PC funktioniert gut
Open "comd.4:19200,8,n,1" For Output As #1 'jp5 Pin 5 linkester bzw. außen
Open "comb.4:19200,8,n,1" For Input As #2 'jp5 Pin 4 zweit linkester bzw. innen
D = 1
Funkempfang = 0
Wait 3
Print "Los geht's"
Do
Print " Schleife = " ; D 'Geht auf RS232 und PC
' ---------- RS232 abfragen und über Funk Ausgeben ------------------------
Sendetext = ""
While Ischarwaiting() <> 0 ' Wird vom RS232 gelesen
S = Inkey()
If S <> "0" Then
Sendetext = Sendetext + S
End If
Wend
If Len(sendetext) > 0 Then
Print "Sende jetzt: " ; Sendetext
Print #1 , Sendetext 'Geht gepuffert zum Funk
Print #1 , Len(sendetext)
End If
' ---------- bis hierhin funktioniert alles ------------------------
X = Inkey(#2)
While X <> 0
Print "Hurra X= " ;
Printbin X
Print
X = Inkey(#2)
If X = 0 Then
Print "Ende"
End If
Wend
D = D + 1
Wait 3
Loop
End

Int1_int:
Return


Zusatzfrage: Kann ich in das RN-Minicontrol einfach einen ATmega162 einbauen? Der hätte 2 UARTs.

Danke.

Gruß
Burkhard

PicNick
01.01.2012, 13:54
Du machst nach jedem Inkey(#2) zwei ziemlich lange "PRINT" Befehle. In der Zeit ist der Empfang nicht bereit.
Empfehlung: erst "inkey" bis X=0 , dabei die Daten sammeln, und erst dann "PRINT"

panier
01.01.2012, 17:57
Hallo Robert,
danke für die rasche Antwort.
Das war einer meiner Tests --> nur ein einziges Inkey --> damit bekomme ich genau ein Zeichen, das funktioiniert (das Kabel ist also auch ok).
Problem ist, dass da keine Schleife funktioniert, mit while X<>0 .... und permanent X=Inkey() bekomme ich genau 1 Zeichen.
Ischarwaiting() funktioniert bei Soft UART nicht (da meckert schon der Compiler).
Theoretisch könnte ich immer 1 Byte senden, das Echo zurück geben und dann das nächste senden, aber das Endgerät sendet mit hoher Geschwindigkeit und erwartet eine Antwort innerhalb von wenigen ms. Und was wenn ich 2 Meldungen kurz nacheinander erhalte?
--> Ratlosigkeit

Meine 2te Frage war, ob ich in das RN-Minicontrol einfach einen ATmega162 einbauen? Der hätte 2 UARTs.
Kannst Du da etwas sagen?

Gruß
Burkhard

PicNick
01.01.2012, 18:38
Also, wenn der 162 Pinkompatibel ist (?), kannst du ihn reintun.
versuche:


.......dein code etc
' ---------- bis hierhin funktioniert alles ------------------------
DIM instring as string * 8
DIM Inchar(8) as byte at instring overlay
DIM inidx as byte

inidx = 0
do
incr inidx
X = Inkey(#2)
inchar(inidx) = X
while X > 0

Print "<";Instring;">Len:";inidx


Kann ich jetzt nicht testen, sollte aber gehen

panier
01.01.2012, 20:45
Hallo Robert,
habe ich probiert (do ... while geändert in while .. wend) und keinen Erfolg gehabt.
Ob der ATmega162 pinkompatibel ist -->keine Ahnung, soweit ich gesehen habe ist er "Fuß-Anzahl-Kompatibel" :)
Gruß
Burkhard

PicNick
02.01.2012, 07:34
mmmhh.
Ich würde, um den Fehler einzukreisen, einmal mit $BAUD deutlich runtergehen, also 1200 oder so. Wenn der Fehler dann verschwindet, weiss man, wo man was tun muss.
Ich seh mir mal die Bascom-Soft-Uart an, was es da mit dem Int1 auf sich hat.

Mega162: dass die Anzahl der HAxen übereinstimmt, ist, wie man so sagt, "notwendig", aber nicht "hinreichend". Sagt auch nix, wenn sie gleich viel kosten oder im selben Laden gekauft sind *g*

MagicWSmoke
02.01.2012, 09:10
Getestet habe ich verschiedene Ports (auch PD3 mit INT1), in zig Kombinationen mit Buffer und ohne .....
Die Idee hinter ext. Int1 ist, dass man den Softuart-Empfang dort reinpackt um eine unmittelbare Reaktion auf eingehende Daten zu bekommen.
Eine leere Int1-ISR nutzt Dir nix. Nicht vergessen zum Abschluss der ISR das INTF1 zu löschen, ist in diesem Fall notwendig.
Nachteile einer solchen Konstruktion: Blockierung anderer ISR's während des Empfangs und andere ISR's können den Empfang behindern.

@PicNick

.......dein code etc
' ---------- bis hierhin funktioniert alles ------------------------
DIM instring as string * 8
DIM Inchar(8) as byte at instring overlay
DIM inidx as byte

inidx = 0
do
incr inidx
X = Inkey(#2)
inchar(inidx) = X
while X > 0

Print "<";Instring;">Len:";inidx
Das wird so nix, denn da müsste der PC dann senden, wenn der µC genau diese Stelle des Codes ausführt. Da wäre ein Waitkey() angebracht. Das hätte allerdings den Nachteil, dass der Code hängen bleibt, wenn nix von der Seriellen reinkommt.
Man könnte sich für Inkey() selber etwas stricken, so in etwa:

Dim Time_Out As Word
Time_Out = 10000
While PinB.4 = 1 And Time_Out > 0
Decr Time_Out
Wend
X = Inkey(#2)
' ...

PicNick
02.01.2012, 13:02
Du hast recht, wer nix weiss, soll nix reden.
Ich weiss nämlich nicht, was Bascom bei Soft-Uart "Inkey()" genau generiert.

MagicWSmoke
02.01.2012, 13:50
Du hast recht, wer nix weiss, soll nix reden.
Na, ich denke, Du weist schon, speziell bei Inkey() mag das jetzt nicht der Fall sein.

Ich weiss nämlich nicht, was Bascom bei Soft-Uart "Inkey()" genau generiert.
Muss zugeben, das wusste ich auch nicht genau, nur ergab sich aus der Hilfe:

If there is no character waiting, a zero will be returned.
dass Inkey() nicht-blockierend wirkt und lustig weitermacht, wenn nichts ansteht. Ob etwas ansteht, kann bei Soft-UART sowieso nur aktiv per Polling festgestellt werden (außer man verwendet Intx).

Daraus ergab sich, dass es im Pogrammablauf sehr unwahrscheinlich ist, dass das einzelne Inkey() gerade da kommt, wenn das Startbit vom PC kommt. Es gibt ein Beispiel dazu, "open.bas" im Samples-Ordner, da wird Inkey() in 'ner Do/Loop gepollt.

Aber um auch sagen zu können, was Inkey() tatsächlich macht, hab' ich's mir angesehen.
Wenn der Pin auf High liegt, liefert es eine 0 zurück, wenn er auf Low liegt, wird die Soft-UART Empfangsroutine ausgeführt.

Bei Deinem Code ist die Schleifenabbruchbedingung x = 0. Aus dem Gesagten ergibt sich, dass dies sehr wahrscheinlich gleich beim ersten Durchlauf zutrifft, die Schleife also sofort verlassen wird.

Waitkey() hingegen würde darauf warten, dass der Pegel Low geht, blockiert aber wenn nix über die Serielle kommt den weiteren Ablauf, deswegen mein Vorschlag mit dem Timeout.

PicNick
02.01.2012, 14:49
Das Bascom-Help hat mich über die Eigenheiten bzw. Unterschiede bei HW- und Softuart nicht befriedigt.
Bevor ich aber da mangels bessern Wissens nochmal "Lull" und "lall" erzähle, werd ich mir die diversen Soft-Uart Routinen disassemblieren und melde mich dann auf der Kampfstatt wieder *g*

MagicWSmoke
02.01.2012, 15:03
...werd ich mir die diversen Soft-Uart Routinen disassemblieren und melde mich dann auf der Kampfstatt wieder *g*
Alles klar. :D

PicNick
02.01.2012, 16:42
So, im Nachhinein betrachtet ohnehin klar:
Man muss/darf (wenn man INKEY() verwenden will) natürlich nur das speichern, was NICHT 0 ist. Als Endeerkennung einer Nachricht ist "0" wenig geeignet.
Wenn man z.b <CR> als Nachricht-Ende nimmt ( was Bascom-PRINT freiwillig tut, wenn man ihn nicht hindert), müsste die Receive-Schleife lauten:


DO
inchar= inkey(#2)
if inchar > 0
incr myidx
myarr(myidx) = inchar
end if
LOOP until inchar = 27

myarr(myidx) = 0 ' ev. ein String-ende aus dem <CR> machen


unter der Annahme, dass das Speichern nicht zu langsam ist. Müsst man ausrechnen, bis zu welcher baudrate es reicht.
Sonst ist wohl eher "INPUT #" oder GET # geeignet


Wen es interessiert, so sieht INKEY() von innen aus:


open comb.4:9600,8,n,1

L_0x00DE: ' delay 1/2 bit --------------------------
PUSH r24
PUSH r25
LDI r24,0x08
LDI r25,0x00
L_0x00E6:
SBIW r24,0x0001
BRNE L_0x00E6
POP r25
POP r24
RET

' inkey (#1) ---------------------------------
L_0x00F0:
SBIS 0x0016,4 ' check PortB.4
RJMP L_0x00F8 ' start
CLR r24 ' return 0
RET
L_0x00F8:
LDI r18,0x09 ' counter = 9 (8 + 1 )
L_0x00FA: ' loop until PortB.4 = 0
SBIC 0x0016,4 '
RJMP L_0x00FA
RCALL L_0x00DE ' delay 1/2 bit
L_0x0100:
RCALL L_0x00DE ' delay 1/2 bit
RCALL L_0x00DE ' delay 1/2 bit
CLC ' clear carry
SBIC 0x0016,4 ' PortB.4 = ?
SEC ' = 1---> set Carry
DEC r18 ' decr counter
BREQ L_0x0114 ' counter= 0 --> exit
ROR r24 ' shift carry into r24:r25
ROR r25
RJMP L_0x0100 ' next bit
L_0x0114:
RET ' R24 = inbyte (that's it)


Der Unterschied von Waitkey ist minimal


' waitkey (#1) ---------------------------------
L_0x00F0:
SBIS 0x0016,4 ' wait PortB.4 = 0
RJMP L_0x00F6 ' start
RJMP L_0x00F0 ' cont'd wait Das ist der einzige Unterschied

MagicWSmoke
02.01.2012, 17:07
unter der Annahme, dass das Speichern nicht zu langsam ist. Müsst man ausrechnen, bis zu welcher baudrate es reicht.
9600 Baud = 9600 Bit/Sek, bei 16 MHz sind dann 1667 Takte pro Bit, da kann er viel speichern. Auch bei 76800 Baud, welche bei 16 MHz nur 0.2% Fehler hätten, wären's noch 208 Takte, sollte auch noch locker reichen. Voraussetzung ist, dass keine Interrupts unterbrechen.

' inkey (#1) ---------------------------------
L_0x00F0:
SBIS 0x0016,4 ' check PortB.4
RJMP L_0x00F8
CLR r24 ' return 0
RET

Der Unterschied von Waitkey ist minimal

' waitkey (#1) ---------------------------------
L_0x00F0:
SBIS 0x0016,4 ' wait PortB.4 = 0
RJMP L_0x00F6 ' start
RJMP L_0x00F0 ' cont'd wait

Das ist der einzige Unterschied
Aber der Entscheidende.

PicNick
02.01.2012, 17:31
"der kleine Unterschied", in der Tat.
bei INKEY() kann man leicht eine Timeout-kontrolle einbauen, dafür muss man sich aber über die Fehlerbehandlung in so einem Fall Gedanken machen.
Bei WAITKEY() hilft ohnehin nur der reset-knopf oder der Watchdog.

pS: mit so Sachen wie Frame-control etc. hat sich Mark offenbar nicht auseinandergesetzt.

peterfido
02.01.2012, 17:54
Softuart ist nicht gepuffert. Ein "wait 3" in der Hauptschleife ist also fehl am Platze. Wenn ich Softuart nutze, dann packe ich die Routine in ein Sub und rufe dieses öfter mal aus der Hauptschleife auf. So funktioniert zuverlässig meine per Softuart angebundene Fernbedienung an meinem Radio. Einen wait-Befehl gibt es bei mir so gut wie gar nicht nach Beginn der Hauptschleife. Wenn, dann mal im Millisekundenbereich (waitms / waitus). Alles Andere wird per selbstgestrickter "Tickcount" API aufgerufen. Z.B. DS1820 sagen, er solle die Temperatur aufbereiten, den ticktemp auf 0 und wenn er 100 erreicht hat (mein Tickcount läuft im 10 ms Takt) wird die Temperatur abgeholt. Größere Projekte haben meist noch eine Uhr mit "an Board". Da kann man schön die Sekunden vergleichen.