Hallo Leute,
Möchte gerne die Daten von meinem UART abholen.
Der verwendete Prozessor ist ein PIC12F1572.
Einmal werden 9 Bytes übertragen, einmal nur 4.
Die Gültigkeit wird in einem anderen Teil des Programms überprüft.
Diese Routine soll eben nur die Daten abholen.
Kann das so funktionieren, oder stehe ich auf der Leitung?
Wie lange ist ein Timeout (in Millisekunden) bei einer Baudrate von
9600?
1
Sub Procedure CheckUARTForData()
2
'
3
'Check the UART, if data are available and store it into the buffer.
4
'It also check, if a timeout occurs.
5
'
6
'
7
dim TimeOutCounter as byte = 0 'Declare TimeOutCounter variable
8
if UART1_Data_Ready() = 1 then 'There are data in the UART
9
if RCSTA.OERR = 1 then 'There was an overrun in the UART
10
RCSTA.OERR = 0 'Reset the UART buffer
11
delay_ms(1) 'Wait one millisecond
12
end if
13
for i = 0 to 8 'Get 9 UART data
14
while UART1_Data_Ready() = 0 'If no data available
15
clrwdt 'Clear the watchdog
16
inc(TimeOutCounter) 'Increment the TimeOutCounter
17
if TimeOutCounter > 10 then '10ms elapsed -> TimeOut
Seppi schrieb:> Wie lange ist ein Timeout (in Millisekunden) bei einer Baudrate von> 9600?
Bei einer asynchronen Übertragung gibt es kein Timeout. Der Sender kann
sich alle Zeit dieser Welt zwischen den Zeichen lassen. Wenn man den
Sender kennt, kann man einen Wert vermuten, mehr aber auch nicht.
MfG Klaus
Seppi schrieb:> Der "Timeout" ist der maximale Abstand zwischen den einzelnen Zeichen.
Der Timeout muß größer sein, als der maximale Abstand zwischen den
Zeichen. Sonst verpasst man immer das nächste Zeichen.
Wie groß darf denn bei einer asynchronen Übertragung der Abstand
zwischen den Zeichen sein? 1 Sekunde, 1 Minute oder 1 Tag? Da gibt es
keinen Wert, auch eine Woche ist ok. Es ist halt asynchron, da gibt es
eine Zeitbeziehung nur innerhalb eines Zeichens.
MfG Klaus
Hallo Seppi,
komm mal von der Leitung runter ;-) und schmeiße Dein Timeout raus.
Checke die Kommunikation primär auf Buffer Overrun und wenn Du magst
noch auf Frame Error (sekundär). Der Timeout ist asynchron nicht
definiert und macht auch nicht wirklich Sinn. Checke ob Deine
Kommunikation vollständig ist und wenn ein Zeichen fehlt, dann fordere
es vom Sender noch einmal an. In der Regel ist aber auch das nicht
notwendig.
Gruß
kokisan
Seppi schrieb:> Das Problem ist halt, das dann das Programm in der Schleife> hängenbleibt, solange nicht noch ein Byte eintrifft.
Dann solltest du vllt. etwas an deiner Programmlogik ändern.
PICianer schrieb:> Seppi schrieb:> Das Problem ist halt, das dann das Programm in der Schleife> hängenbleibt, solange nicht noch ein Byte eintrifft.>> Dann solltest du vllt. etwas an deiner Programmlogik ändern.
Und was würdest du an seiner Stelle andern?
Er hat doch geschrieben das die Botschaften unterschiedlich lang sind.
Da wird er ein "Timeout" benötigen.
Nagnarok schrieb:> Und was würdest du an seiner Stelle andern?> Er hat doch geschrieben das die Botschaften unterschiedlich lang sind.> Da wird er ein "Timeout" benötigen.
Nein, das ist natürlich nicht zwingend. Man kann ein Protokoll
definieren, welches auf UART aufsetzt und einen Timeout zur
Nachrichtensynchronisation benutzt, aber man muß das keinesfalls tun.
Einfach deshalb, weil es noch andere Möglichkeiten gibt, Nachrichten
voneinander abzugrenzen. Und diese sind bezüglich UART als Medium
durchaus sehr viel weiter verbreitet die Arbeit mit Timeouts. Man denke
nur an die klassischen Zeilentrenner...
Die Frage ist einfach nur, welche der grundsätzlichen Möglichkeiten (mit
noch viel mehr Varianten) denn nun der Sender tatsächlich benutzt...
Oder anders ausgedrückt: Es kann keinen allgemeinen Code geben, der das
auf Empfängerseite leisten kann. Der Code muß entweder genau wissen, wie
der Sender seine Nachrichten trennt, nur dann kann er wirklich einzelne
Nachrichten an die nächste Softwareschicht weiter reichen oder es muß
ihm völlig egal sein, dann kann er nur einen (üblicherweise gepufferten)
Bytestrom weiter reichen, aus dem dann die nächste Softwareschicht
liest, die dann (hoffentlich) die Kriterien kennt, um die Nachrichten
voneinander zu trennen.
Wenn man physische Eigenheiten der UARTs zur Nachrichtentrennung
verwendet, muß natürlich logischwerweise die unterste Softwareebene auch
die Nachrichtentrennung vornehmen, denn höhere Ebenen bekommen davon ja
garnix mehr mit. Beim Timeout ist das schon schwieriger zu entscheiden,
der kann ganz unten verwaltet werden, aber auch eine Ebene höher. Er muß
dann aber wahrscheinlich etwas länger sein, um zuverlässig als
Nachrichtentrenner dienen zu können.
Wenn aber, wie weithin üblich, eine frame- oder trennzeichenbasierte
Nachrichtentrennung vorgenommen wird, dann kann die Sache zuverlässig in
höheren Schichten der Software erfolgen. Dann kann es auch eine
universelle UART-Routine geben. Und nur dann!
Genau das wäre die üblichste Implementierung. Eine Schicht unten, die in
einen FIFO liest, und eine Schicht darüber, die den vom FIFO gelieferten
Datenstrom in Inhalte aufdröselt. Genau so arbeiten alle normalen OS.
Und nur mit einem gewissen Faktendruck wird man sinnvollerweise von
diesem Schema abweichen wollen...
Timeouts brauch man übrigens oft auch dann, wenn die Nachrichtentrennung
nicht über selbige erfolgt. Aber das sind dann schon Sachen, die sich
auf höheren Protokollebenen abspielen.
Kirti schrieb:> Aha. Und wie würde das dann aussehen? Das ist ein PIC12!!
Das Problem sehe ich genauso.
Der PIC12 ist einfach zu langsam dafür.
Daher die Idee mit dem Timeout.
Seppi schrieb:> Der PIC12 ist einfach zu langsam dafür.
Quatsch! Der hat einen Instruction-Cycle von 125ns (AKA 8 MHz) und ist
damit schneller als ein original IBM-XT. Und der wiederum kam neben
einer kaufmannischen Buchhaltung auch mit Ethernet klar. Ein popelliger
UART kann den PIC nicht schrecken, der hat eher Angst vor seinem
Programmierer.
MfG Klaus
kommen die daten von einem PC?
gibts evtl ein \r oder \n am ende?
dann die daten einfach in einen buf[] werfen und bei eintreffen des
endezeichens auf plausiblität prüfen
dann brauchst kein timeout und deine programmlogig hängt nicht
mal ganz rudimentär
1
buf[10]
2
3
while(1){
4
if(uartdaten){// überhaupt was im uart ???
5
6
buf[i]=uartdaten;// hole daten und erstmal in buf schieben
7
8
if(buf[i]=='\n'){// datenende erreicht ??
9
10
// ich prüfe buf[] und länge "i" und verarbeite
11
12
13
i=0;// fertig mit verarbeiten reset von buf
14
return;
15
}
16
i++;// kein ende erreicht wir warten ...
17
18
if(i>=10)// sicherheit ggü bufferoverflow
19
i=0;
20
}
21
// hier kann ich noch andere dinge tun ... blinky oder sonstwas
Soooo.
Habe mir nochmals Gedanken gemacht.
Wie gesagt, gibt es keinen delimiter.
Möchte also zuerst die eingegangenen Daten in einen FIFO schreiben und
danach von einer Routine prüfen, ob ein Datenpacket da ist.
Kann es so wie folgt funktionieren?
1
dim InputBuffer as char[9]
2
dim i as word
3
4
5
Sub Procedure UART_FIFO ()
6
If UART1_Data_Ready() <> 0 then 'There are data in the buffer
7
8
If ((RCSTA.FERR = 1) or (RCSTA.OERR = 1)) then 'Framing Error or buffer overflow detected
9
RCSTA.SPEN = 0 'Reset the UART
10
RCSTA.SPEN = 1
11
end if
12
13
for i = 0 to 7 'Shift my FIFO
14
InputBuffer[i] = InputBuffer[i + 1]
15
next i
16
17
InputBuffer[8] = UART1_Read() 'Load new value in FIFO
Ist das Basic?
Programmierst du einen PIC tatsächlich in BASIC??? Welcher compiler
unterstützt das denn?
Seppi schrieb:> Normalerweise wird vom PC ein String gesendet.> z.Bsp. GT12RTZUI
Wenn du einen string empfangen willst, dann solltest du auf \0 prüfen.
Ein String sollte immer \0 terminiert sein!
Einen Timeout würde ich mit zwei interrupts realisieren:
1. Interrupt zum emfpangen von einzelnen Datenbytes. Nach dem Empfang
wird ein Timer deiner wahl auf 0 zurückgesetzt und ggf. eingeschaltet
2. Interrupt beim Überlauf des Timers, alle Daten scheinen empfangen
worden zu sein. Timer ausschalten und Flag setzen für die Auswertung der
Daten (die Auswertung würde ich nicht in der ISR machen)