Forum: Mikrocontroller und Digitale Elektronik PIC läuft durch String viel zu langsam


von Jörg M. (joerg1)


Lesenswert?

Hey,
bei meinen neuen Projekt versuche ich zum ersten mal einen PIC18f4550 
über ein RS232-Kabel mit meinen PC zu verbinden. Das Empfangen und 
Senden von Daten von und zum PC funktioniert erstmal super. Nur leider 
nicht mehr wenn ich das vom PC Empfangene Zeichen in einen String 
schreibe.
Das blinken an PortA0 wird deutlich langsamer (immer 1sek an und 1aus). 
Singnale an PortA1 nur noch verzögert und an PortA2 kommt garnix mehr.

Pic läuft mit 18,432MHZ

Bitte helft mir! Ich bin am Verzweifeln...

main.c
1
#include <htc.h>
2
#include <pic18f4550.h>
3
#include <string.h>
4
#include "usart.h"
5
6
7
// main.c
8
void main(void);
9
void delay( int ms );
10
11
char usartbuffer[25] = 0;
12
int usartcount = 0;
13
14
void main(void)
15
{
16
  // PORT A
17
  LATA = 0b00000000;
18
  TRISA = 0b00000000;    // Alle Ports sind Ausgänge
19
20
  // PORT B
21
  LATB = 0b00000000;
22
  TRISB = 0b00000000;    // Alle Ports sind Ausgänge
23
24
  initUSART(239);  
25
  /* 
26
  Bound 9600   = 379
27
  Bound 19200  = 239
28
  Bound 38400  = 119
29
  Bound 57600  = 79
30
  Bound 76800  = 59
31
  Bound 115200 = 39
32
  Bound 230400 = 19
33
  */
34
35
  while(1) 
36
  { LATA0=!LATA0; delay(100);
37
    char received = getcUSART();
38
    if(  received ) {
39
      //usartbuffer[usartcount] = received;
40
      LATA1=!LATA1;
41
      if (received=='b') { LATA2=!LATA2;  putsUSART("Test"); }  
42
      /*if (usartbuffer[usartcount] == '\r') {
43
        usartbuffer[usartcount+1] = 0;
44
        putsUSART(usartbuffer);
45
        usartcount=0;
46
      } else {
47
        usartcount+=1;
48
      }*/        
49
    }  
50
  }
51
}
52
53
void delay( int ms ) {
54
  int i;
55
  i = 0;
56
  //1 ms = 4608 Befehlstakte (18,432 MHz Quarz / 4)
57
  for( i=0; i<ms; i++ ) {
58
    _delay(4608);
59
  }   
60
}

usart.h
1
//Initialisiert die USART Schnittstelle
2
void initUSART(unsigned int spbrg) {
3
  TXSTA = 0b00001110;  //Asynchroner Mode, 8bit
4
  RCSTA = 0b00000000;  //Empfang konfigurieren
5
6
  RCIE = 0;  //Empfangs-Interrupt disablen
7
  TXIE = 0;  //Sende-Interrupt disablen
8
9
  BAUDCON = 0b1001000;    //BRG16 = 1
10
11
  SPBRG = (spbrg&0x00FF);       //Baudrate festlegen
12
  SPBRGH = (spbrg&0xFF00) >> 8;
13
14
  TXREG = 0;        //Schreibregister löschen
15
  char temp = RCREG;      //Leseregister löschen
16
17
  CREN = 1;  //Kontinuierlicher Empfang
18
  TXEN = 1;  //Transmitter enablen
19
  SPEN = 1;  //Receiver enablen
20
21
  return;
22
}
23
24
//Schreibt ein Byte in das Tranmit-Register und
25
//überträgt dieses
26
void writeUSART(char data) {
27
  TXREG = data;      // Write the data byte to the USART
28
}
29
30
//Prüft, ob gerade Daten über die USART-Schnittstelle
31
//übertragen werden
32
int busyUSART(void) {
33
  if(!TRMT) { //Prüfe, ob das Schieberegister leer ist
34
    return 1; 
35
  }       //Nein, gebe 1 zurück
36
  return 0;          //Ja, gebe 0 zurück
37
}
38
39
//Überträgt mehrere Zeichen über die USART-Schnittstelle
40
void putsUSART(char *data) {
41
int i=0;
42
  while (data[i]) {
43
    while(busyUSART() == 1) {}
44
    writeUSART(data[i]);  //Übertrage das Zeichen
45
  i++;
46
  }
47
}
48
49
//liest ein Zeichen aus dem Empfangspuffer aus
50
char getcUSART(void) {
51
  //Prüfen, ob der Empfang gültig war
52
  if( FERR == 1 ) {
53
    //Framing Error aufgetreten
54
    return 0;
55
  }
56
  if( OERR == 1 ) {
57
    //Overrun Error aufgetreten
58
    CREN = 0;  //Empfang ausschalten
59
    CREN = 1;  //und wieder einschalten, um
60
                  //den Fehler zulöschen und
61
                  //das nächste Byte zu empfangen
62
    return 0;
63
  }
64
  if( RCIF == 1 ) {
65
    //Es wurde ein neues Zeichen empfangen
66
    return RCREG;    //gelesenes Byte zurückgeben
67
  } else {
68
    return 0;
69
  }  
70
}

von B. S. (bestucki)


Lesenswert?

Wo benutzt du einen string? Du hast zwar die Library eingebunden, nutzt 
sie aber nicht. Du verwendest ein char Array, was zugegebenermassen auch 
ein string ist.

Die einzige "Falle", wo das Programm stecken bleiben könnte, sehe ich in 
der Funktion putsUSART:
Du übergibst ein Array (hier ein string). Du sendest solange Zeichen, 
bis im übergebenen Array der Wert 0 steht. Am Ende eines strings steht 
jedoch immer ein '\0'. Finde heraus, was dein Programm dort wirklich 
tut. Ausserdem kann das Programm auch hier
1
while(busyUSART() == 1) {}
steckenbleiben

Was ich sonst noch gesehen habe:
- In der main Funktion wird nicht geprüft, ob die Variable usartcount 
grösser gleich 25 ist (ist zwar auskommentiert, vielleicht willst du's 
ja mal verwenden).
- Warum wartest du zwischen den einzelnen Zeichen immer 100ms? Bei 
19.2kbaud dauert das Senden/Empfangen eines Zeichens ca. 520us (8 Bits + 
2 Start-/Stoppbits).

von B. S. (bestucki)


Lesenswert?

Noch was. Wenn dieser Teil nicht auskommentiert ist:
1
if (usartbuffer[usartcount] == '\r') {
2
  usartbuffer[usartcount+1] = 0;
3
  putsUSART(usartbuffer);
4
  usartcount=0;
5
} else {
6
  usartcount+=1;
7
}
wirst du Probleme haben. In der Funktion putsUSART werden Zeichen 
gesendet, bis der Wert 0 im Array steht. Du schreibst aber nie den Wert 
0 in das Array. Daher kann das Programm quer durch den Speicher Werte 
senden und mit etwas Glück hört es irgendwann auf.

von W.S. (Gast)


Lesenswert?

Jörg Marschner schrieb:
> while(1)
>   { LATA0=!LATA0; delay(100);
>     char received = getcUSART();
>     if(  received ) {

Ich hasse solche Art des Quellcodeschreibens. Versuche doch wenigstens, 
nicht ständig Variablendeklarationen und deren Benutzung in einen Topf 
zu werfen. So unsäglich faul kannst du doch wohl nicht sein!

void MyBlaBla(void)
{ char received;

  while(mycondition)
  { if CharAvailable()
    { received = GetTheChar();
      DoSomethingWithIt(received);
    }
  }
}

Es ist immer eine oberfaule Sache, ein Array einfach vollaufen zu 
lassen, ohne zu prüfen, ob man damit einen Bufferoverrun verursacht. Am 
PC ist das immer noch die beliebteste Methode, um Scheunentore für 
Malware aufzureißen. Also lerne mal, einen Ringpuffer zu programmieren.

Ansonsten sieht dein Programm reichlich prozedural aus und das ist keine 
gute Sache, wenn man mehrere Dinge erledige will, z.B. Empfangen, darauf 
vor Ort reagieren und obendrein noch was senden. Für sowas solltest du 
dir einen anderen Ansatz für's Ganze angewöhnen: Ereignisorientierte 
Programmierung.

Und wozu du unbedingt 100 ms vertrödeln willst, außer zum Verpassen von 
empfangenen Zeichen, ist mir ebenfalls unklar.



W.S.

von ich bin so schön ich bin so toll ich bin EIN TROLL (Gast)


Lesenswert?

In die Headerdatei gehören die Prototypen, nicht die ganzen Funktionen!

von Michael L. (michaelx)


Lesenswert?

Jörg Marschner schrieb:
> Hey,
> bei meinen neuen Projekt versuche ich zum ersten mal einen PIC18f4550
> über ein RS232-Kabel mit meinen PC zu verbinden.

Nur mal so aus Neugier: Hat dein PC kein USB?
Der Rest wurde ja schon gesagt.

Grüße.

von Jörg M. (joerg1)


Lesenswert?

Vielen Dank für die Hinweiße! Ich wird es mir zu Herzen nehmen und mich 
heut Abend gleich noch mal hinsetzen und die ganze Sache überarbeiten.
Die 100-ms-Verzögerung hab ich nur zum Debuggen einprogrammiert, um 
besser sehen zu können wann und wo meine LEDs angesteuert werden bzw. 
die Ports ein Signal ausgeben. Später soll die Verzögerung natürlich 
komplett weg.

Also dann vielen Dank ich werd euch informieren, wenn es funktioniert!

Gruß Jörg

von Jörg M. (joerg1)


Lesenswert?

Update: Ich hab in den letzten Wochen fast alles Getestet... Ich hab mir 
extra noch 2 PICs zugelegt mit dem ergebnis das ich Daten zum Pic 
schicken kann und vom Pic zum PC. Allerdings scheinen sich die Pics alle 
zu weigern meine einzeln gesendeten Zeichen in eine Array zuschreiben 
und auf ein Enter (\r) an mich zurückzusenden...
Bitte schaut doch nochmal drüber ihr seit meine letzte Hoffnung!


PIC18F4550
18,432MHZ
9600Bound


usart.h (Ja ich weiß ich verwende den Datentyp hier falsch - bitte ni 
böse sein)
1
//Initialisiert die USART Schnittstelle
2
void initUSART(unsigned int spbrg) {
3
  SPBRG=spbrg;                 
4
  RCSTAbits.SPEN=1;          
5
  TXSTAbits.TXEN=1;    
6
  RCSTAbits.CREN=1;    
7
}
8
9
//Schreibt ein Byte in das Tranmit-Register und
10
//überträgt dieses
11
void writeUSART(unsigned char data) {
12
  while(PIR1bits.TXIF==0);       // Wait for USART
13
  TXREG=data;                    // Store data in Transmit register
14
}
15
16
17
//Überträgt mehrere Zeichen über die USART-Schnittstelle
18
void putsUSART(unsigned char *data) {
19
  int i=0;
20
  while(data[i]) {
21
    writeUSART(data[i]);  //Übertrage das Zeichen
22
    i++;
23
  }
24
}
25
26
//liest ein Zeichen aus dem Empfangspuffer aus
27
unsigned char getcUSART(void) {
28
  if(PIR1bits.RCIF!=0) {   // Wait until RCIF gets low
29
    return RCREG;        // Retrieve data from reception register
30
  }
31
  return 0;
32
}

main.c
1
#include <htc.h>
2
#include <pic18f4550.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include "usart.h"
7
8
#define FREQ 18432000    // Frequency = 12MHz
9
#define baud 9600
10
#define spbrg_value (((FREQ/64)/baud)-1)    // Refer to the formula for Baud rate calculation in Description tab
11
12
void main(void)
13
{
14
  // PORT A
15
  LATA = 0b00000000;
16
  TRISA = 0b00000000;    // Alle Ports sind Ausgänge
17
18
  // PORT B
19
  LATB = 0b00000000;
20
  TRISB = 0b00000000;    // Alle Ports sind Ausgänge
21
22
  TRISCbits.TRISC7=1; //Make UART RX pin input
23
  TRISCbits.TRISC6=1; //Make UART TX pin output
24
25
  void initUSART(spbrg_value);
26
  
27
  unsigned char buf[32];
28
  unsigned int count=0;
29
30
  putsUSART("Hallo "); // Funktioniert und kommt am pc ohne fehler an
31
  putsUSART("TEST"); // Funktioniert und kommt am pc ohne fehler an
32
  
33
  while(1)
34
  {
35
    unsigned char usartin = getcUSART(); // Funktioniert
36
    if ( usartin != 0 ) {
37
      if (usartin=='\r') { // Funktioniert wird aufgerufen
38
          buf[count] = '\0';
39
          putsUSART(buf); // Geht nicht
40
          count=0;
41
      } else {         
42
          writeUSART(usartin); // Funktioniert und kommt am pc ohne fehler an
43
          buf[count] = usartin; // Scheint nicht zu funktonieren.. WARUM????
44
          count++;
45
      }
46
    }
47
    if(count == 32) { count = 0; }
48
  }
49
}

Ich danke euch jetzt schon wie verrückt

von Martin (Gast)


Lesenswert?

Jörg Marschner schrieb:
> buf[count] = usartin; // Scheint nicht zu funktonieren.. WARUM????
Probiere direkt nach dieser Zeile mal ein
writeUSART(buf[count]);
Kommt das auch an? (Bitte mit -O0 kompilieren.)

von Jörg M. (joerg1)


Lesenswert?

wenn ich direkt nach: buf[count] = usartin;
writeUSART(buf[count]); schreibe,
dann kommt von der Funktion nur Mist zurück der Rest funktioniert...
Also scheint ja wirklich mit der Zuweisung was nicht zu stimmen..

von Martin (Gast)


Lesenswert?

Von welcher Funktion kommt Mist zurück? Und was funktioniert dann 
plötzlich? Die spätere Ausgabe von buf?

Verschiebe die Deklaration von buf mal aus der main raus. Also mache 
eine globale Variable daraus. Ich hätte evtl. noch ein Bug beim Inlining 
von getcUSART vermutet, aber wenn es mit -O0 auch auftritt, dann kann 
man das ausschließen. Ansonsten poste mal noch die Ausgabe von 
avr-objdump -S "dein binary". Dann kann man mal schauen ob mit dem 
generierten Code etwas nicht stimmt.

von Martin (Gast)


Lesenswert?

Args, du verwendest ja ein PIC und kein avr, dann halt das entsprechende 
Äquivalent für PIC um ein binary zu disassemblieren.

von Jörg M. (joerg1)


Angehängte Dateien:

Lesenswert?

Hier mal das ganze Projekt incl des HEX-Files. Das verschieben von buf 
und count vor die main-Funktion hat nix gebracht.

von egr25z2h (Gast)


Lesenswert?

So ein Rumgestocher im Code.

Gibt es für den µC keine vernünftige Debug-Möglichkeit?

von Jörg M. (joerg1)


Lesenswert?

Ich hab den PIC18-Simulator von OshonSoft... Dort funktioniert das 
Programm/das HEX-File jedoch fehlerfrei. Und die Fehlersuche im 
Schaltkreis hat Ergeben das der PIC keine Daten in die char array 
schreiben kann/will. Weder so wie es im Programm steht noch mit 
strcpy(); und auch nicht wenn man direkt char buf[] = "Text der rein 
soll"; schreibt.
Mir ist leider absulut nicht klar warum, vorallen da alles andere 
Funktioniert und dieser Fehler bei 3 verschiedenen PICs auftritt.

von Chris B. (dekatz)


Lesenswert?

Auch wenn mit SPEN=1 die Portpins für den UART geschaltet werden, würde 
ich sicherheitshalber
"TRISCbits.TRISC6=1; //Make UART TX pin output" in
"TRISCbits.TRISC6=0;" ändern. Bei dir ist der Pin auf INPUT gestellt.

von Jörg M. (joerg1)


Lesenswert?

Laut Datenblatt sollen TRISC6 und TRISC7 auf 1 gestellt werden. Habs 
trotzdem probiert und es bringt keine Veränderung. Die reine 
USART-Übertragung funktioniert ja auch ohne Probleme.

von Chris B. (dekatz)


Lesenswert?

Eventuell findet sich ja auch hier etwas:
http://ww1.microchip.com/downloads/en/DeviceDoc/80478a.pdf

von Jörg M. (joerg1)


Lesenswert?

Wie gesagt USART-Kommunikation funktioniert.

von RAY (Gast)


Lesenswert?

Jörg Marschner schrieb:
> Wie gesagt USART-Kommunikation funktioniert.

Tja - vielleicht wird der String / Array falsch übergeben, wenn es an 
der USART nicht liegt.

Kannst ja mal probieren statt

unsigned char buf[32];

char *buf='dummytext........................'; // <- genügend Zeichen in 
den String, damit Speicherplatz belegt wird

zu verwenden.

VG
Ray

von Martin B. (Gast)


Lesenswert?

teste doch mal:

...
      if (usartin=='\r') { // Funktioniert wird aufgerufen
          buf[count] = '\0';
          putsUSART("TEST");
          writeUSART('0'+count);
          putsUSART(buf); // Geht nicht
          count=0;
      } else {

...

vg
Martin

von Jörg M. (joerg1)


Lesenswert?

Hey Ray, dein Vorschlag liefert ein echt interessantes Ergebnis. Wenn 
ich Enter drücke bekomm ich vom PIC immer den Dummytext zurück. 
Komischerweiße nie die Zeichen die der PIC vorher empfangen hat... 
komisch

@Martin: writeUSART(count); funktioniert und liefert mir die Anzahl der 
Zeichen die der PIC vorher empfangen hat.

Hier noch der Code von main.c an usart.h hat sich nix geändert...
1
#include <htc.h>
2
#include <pic18f4550.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include "usart.h"
7
8
#define FREQ 18432000    // Frequency = 18,432MHz
9
#define baud 9600
10
#define spbrg_value (((FREQ/64)/baud)-1)    // Refer to the formula for Baud rate calculation in Description tab
11
12
void main(void)
13
{
14
  // PORT A
15
  LATA = 0b00000000;
16
  TRISA = 0b00000000;    // Alle Ports sind Ausgänge
17
18
  // PORT B
19
  LATB = 0b00000000;
20
  TRISB = 0b00000000;    // Alle Ports sind Ausgänge
21
22
  TRISCbits.TRISC7=1; //Make UART RX pin input
23
  TRISCbits.TRISC6=1; //Make UART TX pin output
24
25
  initUSART(spbrg_value);
26
27
  unsigned char *buf = "....a....a....a....a....a....a....a";
28
  unsigned int count=0;
29
30
  putsUSART(buf); // Funktioniert und kommt am pc ohne fehler an
31
  putsUSART("TEST"); // Funktioniert und kommt am pc ohne fehler an
32
33
  while(1)
34
  {
35
    unsigned char usartin = getcUSART(); // Funktioniert
36
    if ( usartin != 0 ) {
37
      if (usartin=='\r') { // Funktioniert wird aufgerufen
38
          buf[count] = '\0';
39
          putsUSART(buf);
40
          count=0;
41
      } else {         
42
          writeUSART(usartin); 
43
          buf[count] = usartin; 
44
          count++;
45
      }
46
    }
47
    if (count==32) { count=0;  }
48
  }
49
}

von Karl H. (kbuchegg)


Lesenswert?

Jörg Marschner schrieb:

>   unsigned char *buf = "....a....a....a....a....a....a....a";

so und jetzt wirfst du das gleich wieder raus und ersetzt es, wie 
gehabt, duch

    unsigned char buf[30];


Denn so, mit dem Pointer, ist es definitiv falsch. Nicht wegen dem 
Pointer, sondern weil der Pointer auf ein Stringliteral zeigt. Und an 
dem hast du nichts rumzufummeln.

von Karl H. (kbuchegg)


Lesenswert?

Welcher Compiler ist das?

Es gibt/gab da auf den PIC mal ein Gewirx, so dass StringLiterale anders 
behandelt wurden als char-Arrays.

von Jörg M. (joerg1)


Lesenswert?

Echt? Da werd ich direkt ma google anwerfen...

von Karl H. (kbuchegg)


Lesenswert?

Jörg Marschner schrieb:
> Echt? Da werd ich direkt ma google anwerfen...

zb hier
Beitrag "[Pic] C18 Probleme mit Strings"


ist aber Fehlalarm. Da müsste dann das Problem genau umgekehrt sein.

von temp (Gast)


Lesenswert?

also bei jedem halbwegs normalen Compiler wird bei folgendem Ausdruck:

unsigned char *buf = "....a....a....a....a....a....a....a";

die Variable buf ins Ram gelegt und mit der Adresse des Strings 
"....a....a....a....a....a....a....a" initialisieren. Compiler und 
Linker sorgen dafür, dass ale Strings sortiert und von Doubletten 
befreit ins Flash wandern. Und dort kann man nun mal nichts 
hinschreiben. Du kannst zwar buf eine andere Adresse zuweisen aber den 
String selbst nicht ändern. Kommst du von AVR? Dort würdes das gehen, 
deshalb macht man auch die Krücke mit dem PROGMEM um solche Strings in 
den Flash zu verlagern um nicht den Ram damit zu zu müllen. "buf[count] 
= usartin;" geht des wegen nicht!

unsigned char buf[] = "....a....a....a....a....a....a....a";

Dieser Ausdruck (ob das bei allen Comiplern geht weiss ich nicht) macht 
das anders. Er belegt soviel Bytes im Ram wie der String lang ist +1. 
Diesen Buffer kann man dann nach belieben ändern.

Hoffe das das bei deinem PIC Compiler so ist. Zumindestens ist das der 
normalfall für den gcc.

von Jörg M. (joerg1)


Lesenswert?

Würde unsigned char buf[] = "....a....a....a....a....a....a....a"; nicht 
das selbe bewirken wie unsigned char buf[30];?
Also RAM freihalten/belegen?
Funktioniert aber jedenfalls auch nicht.
Ich verwende MPLAB X IDE und Hi-Tech PICC18-PRO (v9.80) als Compiler

Ich hab vorher keine noch nie Programme für mC geschrieben (Außer ein 
paar kleine LED I/O für PIC16). Daher hab ich mit Arrays nie viel 
gemacht. (Zumindest bei mC). Ansonsten schreibe ich abundan PC-Programme 
(c/c++ und das nur als xxs-Hobby! Also ohne viel Ahnung) wo ich so ein 
Problem noch nie hatte.

von temp (Gast)


Lesenswert?

das schon, aber wenn man macht:

unsigned char buf[30];
buf="....a....a....a....a....a....a....a";

hat man wieder das gleiche Problem. buf zeigte am Anfang schön auf 30 
Bytes im Ram. Nach der Zuweisung zeigt er auf einen readonly Bereich im 
Flash.

Ich habe den Thread aber nicht im Detail verfolgt. (Heute ist Feiertag!) 
Also mit anderen Worten, ob du das so machst weiss ich nicht,, aber wenn 
dann ist das falsch!

von Jörg M. (joerg1)


Lesenswert?

@Gast
Kurz und Knapp. Nein das mach ich nicht.
Das Feiertag ist weiß ich und nimm es mir bitte nicht übel aber niemand 
zwingt dich zum Feiertag oder sonstwann sich um meine Probleme zu 
kümmern.
Nicht falsch verstehen ich bin für alle Hinweiße und Ratschläge dankbar 
und ich weiß zu schätzen das es Leute gibt die sich vollkommen 
unentgeldlich um Probleme anderer kümmern! Wenn es so eine Seite bzw so 
ein Forum mit all seinen Mitgliedern nicht gäbe.... Ich will gar ni dran 
denken... Aber trotzdem muss ich sagen niemand zwingt dich (schon 
garnicht an einem Feiertag)
Gruß Jörg

von Jörg M. (joerg1)


Lesenswert?

Hey Leute! Vielen Dank für eure Hilfe, jetzt hab ich die Lösung...
Seht hier Beitrag "Array beschreiben schlägt fehl"

Einfach volatile vor die char-Array und vor int count=0; und schon 
gehts...

Optimierung steht zwar schon auf none aber na gut...

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.