Forum: Mikrocontroller und Digitale Elektronik PIC & GSM-Modem über RS232


von RudiR (Gast)


Lesenswert?

Hallo folks,

ich bin auf Euren Rat bzw Eure Hilfe dringend angewiesen.

ich schreibe für einen PIC16F887 ein Programm, welches mit einem 
GSM-Modem mc35i (Siemens/Cinterion) kommuniziert.

Reines Senden PIC > Modem (zB 'ATDTnnnnnnnnn') funktioniert einwandfrei.

Beim Empfang haperts jedoch gewaltig.
Hier der relevante Codeausschnitt:

rs232-settings:
  BRGH=1;        // Baudrate 9600 Bits/s @ 4MHz
  SPBRG=25;
  SYNC=0;        // USART Empfaenger enablen
  SPEN=CREN=TXEN=1;  // USART Sender enablen

wenn ich jetzt folgendes mache
PIC > Modem sendet: 'ATI[CR]'
krieg ich bei einem normalen Terminalprogramm (hyperterminal) die 
normale Antwort (drei Zeilen 'Selbstgespräche' des Modems ;.))

mit meinem Programm/schnipsel/ (im Anschluss an obiges ATI-command)

while(1) {
  if(RCIF) {          // interrupt gesetzt?
     z=RCREG;         // Empfangsregister auslesen
     lcd_dat(z);      // Ausgabe am LCD
  }

}

erhalte ich jedoch nur ZWEI buchstaben ("AT"). Das ist genau die Anzahl 
von Zeichen, die der USART aufnehmen kann, ohne ausgelesen werden zu 
müssen.

In der Doku zum USART steht weiters, dass nach dem Lesen des RCREG das 
RCIF Interruptflag gelöscht wird.
Hab auch schon versucht, nach dem Lesen von RCREG das RCIF 'händisch' im 
Prog zu löschen - erfolglos.

Kann mir jemand einen Tipp oder eine funktionierende C-routine geben?

Vielen Dank schon mal jetzt!!

Rudi Ratlos

von MitLeser (Gast)


Lesenswert?

mal über den Rx-Interrupt die empfangenen Zeichen
in einen Buffer schreiben.
gruss

von RudiR (Gast)


Lesenswert?

Danke für die schnelle Antwort!

Interrupt wollt ich mir dafür eigentlich sparen....
Geht es auch anders?

RudiR

von MitLeser (Gast)


Lesenswert?

du weisst schon, dass Deine Variable z immer den Wert des aktuell 
empfangenen Zeichens annimmt. Was "lcd_dat()" macht weiss ich nicht.
Wenn Du das Flag von Hand gelöscht hast (richtig ;-)) und Du nicht alle 
Zeichen empfängst..., hmmm wie lange dauert "lcd_dat()" ?

von RudiR (Gast)


Lesenswert?

> du weisst schon, dass Deine Variable z immer den Wert des aktuell
> empfangenen Zeichens annimmt.

ja, dieses will ich ja auslesen. Oder willst Du mir damit etwas anderes 
sagen?

> Was "lcd_dat()" macht weiss ich nicht.

sorry, dachte, geht aus dem comment hervor. es gibt das zeichen am 
lcd-display des uC aus.

> Wenn Du das Flag von Hand gelöscht hast (richtig ;-))

wobei mir die Doku in dem Moment sagt: das RCIF ist readonly....

> und Du nicht alle Zeichen empfängst..., hmmm wie lange dauert "lcd_dat()" ?

hmm, schwer zu sagen. Bin kein timing-experte.
Sind insgesamt 18 einfache C-Zuweisungen, ein nop() in C sowie ein delay 
von 1ms.
Hilft das weiter?
Denke mal, mit den 9600 baud sollte das aber mithalten können...

LG Rudi

von Lehrmann M. (ubimbo)


Lesenswert?

RudiR schrieb:
> Interrupt wollt ich mir dafür eigentlich sparen....
> Geht es auch anders?

Nein geht es nicht. Zumindest nicht sinnvoll. Das wird sonst nur so ein 
hingekrempeltes Zeug.

Interrupts sind garnicht so schlimm wie man als Anfänger denkt. Ein paar 
Register und fertig ...

ich helf dir gerne ...

von RudiR (Gast)


Lesenswert?

Danke für Dein Angebot, Michael!

Ich bin schon mal dran, das auf interrupts umzuschreiben, im Mom kämpf 
ich noch mit Compilerdirektiven, damit er die richtigen Register rettet 
(ich arbeite mit dem cc5x).

Ich komm sicher wieder auf Dich zu!

LG Rudi

von RudiR (Gast)


Lesenswert?

Und da bin ich auch schon wieder...

meine int-routine sieht jetzt so aus:

interrupt ISR(void) {      // Interruptroutine
  int_save_registers    // W, STATUS (und  PCLATH) retten
  if(RCIF) {
     usartbuff[usartind]=RCREG;
     usartind++;
  }

    //  und hier weiterer code, der interruptmäßig abgefackelt wird....
    ...
    ...
  int_restore_registers  // W, STATUS (und PCLATH) wiederherstellen
}

also will ich bei einem INT das RCREG in den 80-stelligen usartbufffer 
schreiben...

mein hauptprogramm:

for(i=0; i<=79; i++)
  usartbuff[usartind]='.';   // usartbuffer sicherheitshalber löschen
usartind=0;                        //
rs232_print("ATI"); delay(100);   // Modeminfo abholen
for(i=0; i<=20; i++)
  lcd_string(usartbuff[usartind]);   // usartbuffer ans LCD senden

ergebnis: seltsame zeichenfolgen am display:
ART ART ART ART ART ART
ART ART ART ART ART ART

Diese Buchstabenkombi ist Teil einer Zeichenkette, die an den USART 
gesendet wird, der aber in einem anderen Programmteil liegt und 
überhaupt nicht angesprochen wird.... Merkwürdig...

kannst Du mir bitte vll. helfen?

Danke, RudiR

von MitLeser (Gast)


Lesenswert?

warum nicht gleich so ;-)
vielleicht leigt es daran, dass Deine Lcd-Ausgabe ist nicht mit dem
Empfang synchronisiert ist.
Du kannst ein Flag im INT setzen, wenn der String vom Modem
komplett eingelesen wurde. Ich meine mich zu erinnern, dass die
Strings mit Carriage Return oder ähnlichem abgeschlossen werden.

von MitLeser (Gast)


Lesenswert?

kannst Du kontrollieren was wirklich vom Modem gesendet wird ?

von holger (Gast)


Lesenswert?

Versuchs mal so:

for(i=0; i<=79; i++)
  usartbuff[usartind]=0;   // usartbuffer sicherheitshalber löschen
usartind=0;                        //
rs232_print("ATI"); delay(1000);   // Modeminfo abholen
lcd_string(usartbuff);   // usartbuffer ans LCD senden

von holger (Gast)


Lesenswert?

Nachtrag:

rs232_print("ATI\n"); delay(1000);   // Modeminfo abholen

von RudiR (Gast)


Lesenswert?

hallo folks,

dank Eurer Hilfe läuft das Ding jetzt zufriedenstellen.

Zusammengefassst:

Meine Interruptroutine (unverändert):

interrupt ISR(void)      // Interruptroutine
{  int_save_registers    // W, STATUS (und  PCLATH) retten
  if(RCIF)
  { usartbuff[usartind]=RCREG;
    usartind++;
  }
        ... und noch einiges anderes hier
}

Im Hauptprogramm:

for(i=0; i<=80; i++)
  usartbuff[usartind]=0;      // buff löschen

usartind=0;                     // alles im rs232-lesepuffer befindliche 
verwerfen

rs232_println("ATI");               // senden befehl an modem
delay(10000);                  // testbetrieb: 10 sec warten in schleife 
auf modemantwort

for(i=0; i<usartind; i++)
  lcd_dat(usartbuff[i]); // ausgeben des lesebuffers am  LCD > tadellos

es war tatsächlich irgendwie die zeitliche koppelung von LCD und 
rs232-interrupts..

Danke nochmals, liebe Grüße

Rudi

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.