www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PIC18F452 Daten auswerten


Autor: Michi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen

Zur Aufgabenstellung:
Ich muss einen PIC18F452 für eine Überwachung programmieren. (im Grunde 
einen kleinen Watchdog).
Dieser muss von der seriellen Schnittstelle die Daten auswerten, welche 
er empfängt. Stimmen diese (Status-)Daten nicht mehr, wird einfach ein 
Alarmausgang geschaltet. Als Eingang zum PIC verwende ich einen MAX202.

Das Problem liegt daran, dass ich keinen String (mit Abschluss CR) 
empfange.
Somit muss ich doch jede Zeichenkette, welche sporadisch an meinen PIC 
gesendet werden, auswerten.
Und weil zusätzlich noch andere Daten über die RS232 Schnittstelle 
gesendet werden, muss ich auf ein spezielles Muster im Datenstring 
ausschau halten.

Wie ich das gesehen habe, werden über die serielle Schnittstelle nur 
reine HEX-Werte geschickt.
Das Statusmuster sieht folgendermassen aus: 02 03 00 FF 00 FF
Sollte nach 02 03 00 FF keine 00 erscheinen, muss der Alarmausgang 
geschaltet werden.

Nach meinen Kenntnisse benutzt man doch hierfür einen #int_rda und dann 
den Befehl getc. Leider bin ich mir nicht sicher, ob ich die Konfig 
richtig eingestellt habe.

Hier einmal ein Teil des Codes
#include <18F452.H>
#device ADC=10 *=16 
// #device ICD=TRUE;
 #fuses NODEBUG
// #fuses DEBUG
#fuses  HS,NOPROTECT ,PUT,NOLVP  
#fuses NOWDT,BROWNOUT,BORV42
#use delay(clock=20000000)
#use FAST_IO(C)
#use rs232(baud=115200,Xmit=PIN_C6, rcv=PIN_C7,stream=HostPC)  

#opt 9


void main(void);

#include <input.c>
#include "Define.h"
#include <stdlib.h>


#int_rda
void IntRS(void){
//int RSstatus=0;
disable_interrupts(int_rda);  // Interrupts RS232 aus



// Serielle Schnittestelle auswerten
  getc(HostPC);
  if (HostPC==0x02){          // Kontrollbyte 1 (Wert 02)
    getc(HostPC);
    RSstatus=1;          
    if (HostPC==0x03){         // Status RS232 OK
      getc(HostPC);
      RSstatus=2;
       if (HostPC==0x00){
        getc(HostPC);
        RSstatus=3;
        if (HostPC==0xFF){
          getc(HostPC);
          RSstatus=4;
          if (HostPC==0x00){  // CES-Status OK
             Alarm=0;
          }
          else Alarm=1;
        }
      }
        }
  }

}                    // Ende IntRS


Vielen Dank für eure Hilfe

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich nehme an, der Empfang eines Zeichens generiert einen Interrupt und 
IntRS ist Deine Interrupt-Service-Routine.

Darin liest Du aber mehrere Zeichen, die ev. noch gar nicht eingetroffen 
sind.
Du solltest in IntRS eher eine Statemachine programmieren, jeweils genau 
ein Zeichen liest und RSstatus hochzählt.
Ausserdem brauchst Du einen Timer um einen Timeout zu generieren, wenn 
nach Empfang von FF innert einer von Dir zu definierenden Zeit kein 00 
folgt.

Alles klar?

Severino

Autor: Michi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Severino

>Ich nehme an, der Empfang eines Zeichens generiert einen Interrupt und
>IntRS ist Deine Interrupt-Service-Routine.

Das stimmt genau. Dies ist meine Interrupt-Service-Routine.

Mein Problem liegt jetzt genau in dieser Statemachine, welche nur 1 
Zeichen liest. Nach dürchstöbern von mehreren Literaturen komme ich 
nicht auf den Befehl, mit welchem ich nur 1 Zeichen einlesen kann. 
Vielleicht kannst du mir hier weiterhelfen.

>Ausserdem brauchst Du einen Timer um einen Timeout zu generieren, wenn
>nach Empfang von FF innert einer von Dir zu definierenden Zeit kein 00
>folgt.

Dieser Timer für den Timeout habe ich implementiert.


Danke für deine Bemühungen

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
getc() liest meines Wissens genau ein Zeichen ein.
(Was geschieht, wenn gar kein Zeichen da ist, weiss ich nicht auswendig, 
ich denke, getc() wartet dann bis eines eintrifft).

IntRS liest mehrere Zeichen ein, solange es sich um die erwarteten 
Zeichen handelt und sie in der richtigen Reihenfolge eintreffen.
Was andernfalls geschieht, bleibt offen (kein else). Alarm ist dann 
undefiniert (übrigens, wo wird die Variable definiert?)
Mindestens sollte Alarm vor dem ersten if auf 1 gesetzt werden, damit es 
(nur) im korrekten Fall gegen Ende auf 0 zurückgesetzt wird.

Bleibt das Problem, dass Du in der ISR mehrere getc() hast, und das 
Programm dort wartet, bis ein weiteres Zeichen eintrifft. In einer ISR 
sollte man nie warten.

Prüfe mal in der Doku zu getc(), was geschieht, wenn gar kein Zeichen 
ansteht. Wenn getc() ewig wartet, brauchst Du eine Funktion, die Dir 
sagt, ob überhaupt ein Zeichen im Empfangspuffer steht. Dann könntest Du 
das Ganze sogar ohne Interrupts lösen.

Severino

Autor: Michi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
getc() liest ein Zeichen, dies funktioniert jetzt auch. Schon einmal 
hier ein Dankeschön Severino.

Nun habe ich dies folgendermassen gelöst: Ich verwende keinen Interrupt 
für die Datenauswertung. Sondern löse dies über eine Schlaufe. Dort 
wartet der PIC mit dem Einlesen (getc();) bis Daten auch vorhanden sind.
Das ist für mich so in Ordnung.

Nun habe ich nur noch ein anderes Problem.
Nach dem dritten Einlesen steht der PIC still. Ich kann weder Daten 
einlesen, noch welche aussenden. Überhaupt passiert nichts mehr.

Kann es sein, dass die Daten langsamer/schneller empfangen werden 
müssen, als dies ich eingestellt habe (RS232 Geschwindigkeit stimmt mit 
der anderen überein)?

Hier nochmals der Code von der Schlaufe.
Danke
// Von RS232 lesen

boolean IntRS(void){
boolean OK=true;
//char RSBuf;              // RS232-Zeichenlänge definieren
disable_interrupts(int_rda);    // Interrupts RS232 aus
//enable_interrupts(int_timer2);  // Timer2 "Stringlänge empfangen" ein


if (Out_Counter2<3){
// Serielle Schnittestelle auswerten
printf("Lesen    ");
  while (!kbhit()){} if (getc()==0x02){          // Kontrollbyte 1 (Wert 02)
    RSstatus=1;
    printf("Zahl_1 (02) OK   ");          
    while (!kbhit()) {} if (getc()==0x03){         // Status RS232 OK
      RSstatus=2;
      printf("Zahl_2 (03)  OK   ");
       while (!kbhit()) {} if (getc()==0x00){
        RSstatus=3;
        printf("Zahl_3 (00)  OK   ");
        while (!kbhit()) {} if (getc()==0x00){      // --> ACHTUNG falsche Zahl
          RSstatus=4;
          printf("Zahl_4 (FF)  OK   ");
          while (!kbhit()) {} if (getc()==0x00){  // CES-Status OK
            Out_Counter2=0;  // Reboot-Counter rücksetzen
               set_timer1(0);
               timer1Count=0;
            RSstatus=0;
            printf("Statuszahl (00)  OK   ");
          }
          else Menu=4; 
        } else printf("   FF false ");  
      }  
        }  
  }  
 }                    // Ende Out_Counter
//enable_interrupts(int_rda);

  return(OK);
}

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei der vierten Zahl prüfst Du zwar auf ==0x00, schreibst dann aber:
      printf("Zahl_4 (FF)  OK   ");
(Schönheitsfehler?)

Sendest Du dem PIC überhaupt eine vierte (und fünfte) Zahl?
Wenn nicht, "hängt" er in while (!kbhit()).

Hast Du einen ICD2 oder sonst ein Debug-Werkzeug, um zu sehen, was der 
PIC macht?
Oder könntest Du das Ding in MPLABs Simulator testen (weiss nicht, wie 
weit die UART-Simulation läuft).

Jedenfalls denke ich, dass in der while-Schleife zusätzlich nach einem 
Timeout abgefragt werden sollte, z.B.
while ( !kbhit() & !TimerExpired() ) {}
if TimerExpired() { /* Timeout behandeln (Fehler?) */ }
else { /* Zeichen einlesen */ }

Severino

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, ich meinte:
while ( !kbhit() && !TimerExpired() ) {}
statt
while ( !kbhit() & !TimerExpired() ) {}

Autor: Michi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Severino.
(sorry die Verspätung, war unvorhersehbar geschäftlich unterwegs)

Nun zu meinem Programm:
Ich habe zwar ein ICD2, kann diese Anwendung jedoch dort nicht 
einsetzen. Die Überwachung muss in einem Gerät (mit einer bereits 
angefertigten Plattine) eingesetzt werden.
Ich sehe also nur, ob das Programm läuft (oder eben nicht :-(  )


Ich habe die serielle Schnittstelle über einen Interrupt eingelesen:
Und wie ich dies gesehen habe, funktioniert das Einlesen bis zur Zahl 03 
recht gut. Im Moment habe ich noch zwei Probleme:
1. Wenn ich das Programm laufen lasse, bleibt er mir beim Wert 00 
"stehen".
2. Wenn ich die dritte Überprüfung (0x00) nicht vornehme (also 
auskommentiert) und ich die Zeile "RS232 Counter reset" gesendet habe, 
bleibt das Programm auch stehen.
Es müsste doch mindestens noch den printf("Durchlauf OK"); gesendet 
werden, was leider nicht der Fall ist.
#int_rda
void IntRS(void){
disable_interrupts(int_rda);

if (Out_Counter2<3){
// Serielle Schnittstelle auswerten
timerRSCount=0;
timerRSOut=0;

while (timerRSCount<=0x0032){                      // Timeout 35 sek
while ((!kbhit()) && (timerRSCount<=0x000A)){}     // Timeout 2 sek. 
    if (timerRSCount>=0x000A) { Set_tris_c(0x80);  // Eingänge reset
        timerRSOut=1;}      
    else {}
     if ((!timerRSOut) && (getc()==0x02)){
        printf("Startzahl 02 OK\n\r");
        while ((!kbhit()) && (timer1Count<=0x0014)){}  //Timeout 4 sek.
        if (timerRSCount>=0x0014) { Set_tris_c(0x80); 
           timerRSOut=1;}
        else{}
        if ((!timerRSOut) && (getc()==0x03)){
           printf("Startzahl 03 OK\n\r");
           while ((!kbhit()) && (timerRSCount<=0x001E)){} // 6 sek.
           if (timerRSCount>=0x001E) { Set_tris_c(0x80); 
               timerRSOut=1;}
           else{}
           if ((!timerRSOut) && (getc()==0x00)){
               printf("Startzahl 00 OK\n\r");
               while ((!kbhit()) && (timerRSCount<=0x0028)){}  // 8 sek
               if (timerRSCount>=0x0028) { Set_tris_c(0x80);   
                   timerRSOut=1;}
               else {}
               if ((!timerRSOut) && (getc()==0x00)){
                   Out_Counter2=0;          // Reboot-Counter rücksetzen
                   set_timer1(0);
                   timer1Count=0;
                   Set_tris_c(0x80);
                   printf("RS232 Counter reset\n\r");
                   }
                else { printf("Reboot\n\r");
                       Menu=4;
                      }    
                }                        // Ende 0x00
                else  printf("Fehler 00\n\r");
            }                            // Ende 0x00
            else  printf("Fehler 03\n\r");
        }                                // Ende 0x03
        else  printf("Fehler 02\n\r");
}                                        
if (timerRSCount>=0x0032){                            // Timeout 35 sek.
  timerRSCount=0;
  Set_tris_c(0x80);
  printf("Timerueberlauf");
  Delay_ms(50);
  }
}
Set_tris_c(0x80);
printf("Durchlauf OK");
enable_interrupts(int_rda);
}

Nochmals vielen Dank für Deine Bemühungen

Michi

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.