Forum: Mikrocontroller und Digitale Elektronik PIC12 UART einlesen, aber mit Timeoutabfrage


von Seppi (Gast)


Lesenswert?

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 
18
        exit sub      'Exit the sub      
19
     end if
20
     delay_ms(1)      'Wait one millisecond
21
           wend          
22
     InputBuffer[i] = UART1_Read()  'Get the data
23
     TimeOutCounter = 0      'Reset the timeoutcounter  
24
       next i          'Next char
25
    end if
26
end sub

von Seppi (Gast)


Lesenswert?

Keiner Erfahrung mit UART und PICs ?

von Klaus (Gast)


Lesenswert?

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

von Seppi (Gast)


Lesenswert?

Normalerweise wird vom PC ein String gesendet.
z.Bsp. GT12RTZUI

Der "Timeout" ist der maximale Abstand zwischen den einzelnen Zeichen.

von Klaus (Gast)


Lesenswert?

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

von kokisan2000 (Gast)


Lesenswert?

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

von Seppi (Gast)


Lesenswert?

Das Problem ist halt, das dann das Programm in der Schleife 
hängenbleibt, solange nicht noch ein Byte eintrifft.
Werde mal ein paar Versuche tätigen.

von PICianer (Gast)


Lesenswert?

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.

von Nagnarok (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Kirti (Gast)


Lesenswert?

Aha. Und wie würde das dann aussehen? Das ist ein PIC12!!

von Seppi (Gast)


Lesenswert?

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.

von Chris S. (schris)


Lesenswert?

wieso verwendest du keine Interrupts ?

von PICianer (Gast)


Lesenswert?

Kirti schrieb:
> Aha. Und wie würde das dann aussehen? Das ist ein PIC12!!
In etwas so?
1
uint8_t rx_finished = 0;
2
char rx_buffer[BUFFER_SIZE];  
3
char *p_rx_buf = rx_buf; 
4
5
//main loop
6
while(1)
7
{
8
  // Do something that has nothing to do with UART...
9
10
  if(rx_finished)
11
  {
12
    rx_finished = 0;
13
    // Process the received data
14
  }
15
16
  if(uartDataReady) // Could also be in the UART ISR
17
  {
18
    *p_rx_buf = uartGetData();
19
    
20
    if(*p_rx_buf == DELIMINTOR)
21
    {
22
      rx_finished = 1;
23
      p_rx_buf = rx_buf; 
24
    }
25
    else
26
      p_rx_buf++;
27
  }
28
}
Hab ich so ähnlich auf einem PIC16 laufen.

von Klaus (Gast)


Lesenswert?

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

von web (Gast)


Lesenswert?

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
22
  foo();
23
  bar();
24
}

von web (Gast)


Lesenswert?

das return is quatsch ^^
bitte so nicht übernehmen ..


aber das  kann man in funktionen so nehmen
bis eh fürs funktionenverwenden ^^

von Seppi (Gast)


Lesenswert?

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
18
       end if
19
end sub

von spontan (Gast)


Lesenswert?

Won welcher Quelle kopierst du den Code zusammen?
Gibts da nix vernünftiges?

von Seppi (Gast)


Lesenswert?

Detektieren möchte ich das Datenpacket wie folgt:

(Es wird nichts kopiert, sondern selbsterstellt)
1
Sub function DataValid() as boolean
2
'Valid Formats are:
3
'GZXXYYYYY or GZXX or SZXXYYYYY 
4
'G or S ist the command if we need Get or Set new data
5
'Z is the command, which data should be read, or set
6
'XX select the channel
7
'YYYYY are the datas
8
'
9
DataValid = 0 'Default
10
11
       if ((InputBuffer[0] <> "G") and (InputBuffer[0] <> "S")) then
12
    exit
13
       end if
14
15
       if ((InputBuffer[2] = "C") and (InputBuffer[3] = "1")) then
16
    DataValid = 1 'Found, that channel 1 should be selected
17
    exit
18
       end if
19
20
       if ((InputBuffer[2] = "C") and (InputBuffer[3] = "2")) then
21
    DataValid = 1 'Found, that channel 2 should be selected
22
    exit
23
       end if
24
25
end sub

von Little B. (lil-b)


Lesenswert?

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)

von Seppi (Gast)


Lesenswert?

Der String wird eben nicht abgeschlosen.
Es werden nur 4 oder 9 char übertragen.

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.