mikrocontroller.net

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


Autor: RudiR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: MitLeser (Gast)
Datum:

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

Autor: RudiR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die schnelle Antwort!

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

RudiR

Autor: MitLeser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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()" ?

Autor: RudiR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lehrmann Michael (ubimbo)
Datum:

Bewertung
0 lesenswert
nicht 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 ...

Autor: RudiR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: RudiR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: MitLeser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: MitLeser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kannst Du kontrollieren was wirklich vom Modem gesendet wird ?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:

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

Autor: RudiR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

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.