Forum: Mikrocontroller und Digitale Elektronik String-Ausgabe über UART funktioniert nicht bei PIC 18F


von BWW (Gast)


Lesenswert?

Hallo zusammen,

ich beschäftige mich jetzt seit einigen Tagen mit PIC-Prozessoren, 
wesentlich mehr Erfahrung habe ich mit den ATMega's von Atmel.

Es ist nicht möglich, mehrere Zeichen über die UART-Schnittstelle an ein 
Terminalprogramm zu senden. Es kommt immer nur das erste und das letzte 
Zeichen an (Wenn ich "MICROCHIP." senden will, kommt nur "M.").
Senden per String über die Funktion "UART_Zeile_senden" geht überhaupt 
nicht, da kommt am PC gar nix an.

Ich tüftel nun schon einige Tage und studiere das Datenblatt und 
Internetseiten rauf und runter, aber ich komm nicht drauf...

Ich verwende MPLAB x IDE v 1.60, einen PIC 18F258, einen MAX232, und 
HTERM 0.8.1

Danke ;)

Christian


main.c:
1
#pragma config OSC = HS         // 14,7456 MHz
2
#pragma config PWRT = ON        // Power-On-Timer
3
#pragma config WDT = OFF        // Watchdog off
4
5
#include <delays.h>
6
#include <p18f258.h>
7
#include "myports.h"            // Ein- und Ausgänge
8
#include "myuart.h"             // UART-Schnittstelle
9
10
int main(void)
11
{
12
    // Ausgänge initialisieren
13
    Ausgaenge_Init();
14
15
    // Eingänge initialisieren
16
    Eingaenge_Init();
17
18
    // UART initialisieren
19
    UART_Init();
20
21
    // Ausgang C4 auf High
22
    Set_LED_gruen(1);
23
24
    // Hauptschleife
25
    while(1)
26
    {
27
        // Ausgang C3 auf high
28
        Set_LED_rot(1);
29
30
        // Warten
31
        Delay10KTCYx(64);
32
33
        // Ausgang C3 auf low
34
        Set_LED_rot(0);
35
36
        // Warten
37
        Delay10KTCYx(255);
38
39
        // UART Test
40
        UART_Zeichen_senden('M');
41
        UART_Zeichen_senden('I');
42
        UART_Zeichen_senden('C');
43
        UART_Zeichen_senden('R');
44
        UART_Zeichen_senden('O');
45
        UART_Zeichen_senden('C');
46
        UART_Zeichen_senden('H');
47
        UART_Zeichen_senden('I');
48
        UART_Zeichen_senden('P');
49
        UART_Zeichen_senden('.');
50
51
        UART_Zeile_senden("TECHNOLOGY.");
52
   }
53
54
   return 0;
55
}

myuart.h:
1
// Bitdefinitionen
2
#define SPEN 7
3
#define TX9  6
4
#define TXEN 5
5
#define SYNC 4
6
#define BRGH 2
7
#define TRMT 1
8
#define TXIF 4
9
10
// UART initialisieren
11
void UART_Init(void)
12
{
13
    SPBRG = 3;                   // Baud Rate Generator Register, 57600 bd
14
    TXSTA &= ~(1<<BRGH);         // High Speed Aus
15
    TXSTA &= ~(1<<SYNC);         // Asynchroner Modus
16
    TXSTA &= ~(1<<TX9);          // 8-bit-Übertragung
17
    TXSTA |=  (1<<TXEN);         // Transmit Enable
18
    RCSTA |=  (1<<SPEN);         // RX und TX Pins aktivieren
19
}
20
21
void UART_Zeichen_senden(unsigned char zeichen)
22
{
23
    // Zeichen in den Ausgabepuffer schreiben
24
    TXREG = zeichen;
25
26
    // Warten, bis das Zeichen gesendet wurde
27
    while( (PIR1 & (TXIF)) );
28
}
29
30
void UART_Zeile_senden(char *zeile)
31
{
32
    // Solange senden, bis Stringende erreicht
33
    while(*zeile)
34
    {
35
        // Einzelnes Zeichen senden
36
        UART_Zeichen_senden(*zeile);
37
38
        // Nächstes Zeichen
39
        *zeile++;
40
    }
41
}

von holger (Gast)


Lesenswert?

void UART_Zeichen_senden(unsigned char zeichen)
{
    // Zeichen in den Ausgabepuffer schreiben
    TXREG = zeichen;

    // Warten, bis das Zeichen gesendet wurde
    while( (PIR1 & (1 << TXIF)) );
}

von PIC (Gast)


Lesenswert?

void UART_Zeichen_senden(unsigned char zeichen)
{
    // Zeichen in den Ausgabepuffer schreiben
    TXREG = zeichen;

    // Warten, bis das Zeichen gesendet wurde
    while(PIR1bits.TXIF);
}

von BWW (Gast)


Lesenswert?

Danke für diese fixe Antwort. Manchmal kann's so einfach sein... Hab das 
1<< übersehen...

Klappt aber leider nicht ganz.

so:
1
    while( (PIR1 & (1 << TXIF)) );

sendet er gar nix. Terminalfenster bleibt leer.

und so:
1
    while( !(PIR1 & (1 << TXIF)) );

funktioniert's zwar teilweise, aber mit dem oben angegebenen Quellcode 
kommt nur "MCOHP." im Terminalfenster an.

Irgendwie vergisst der da die Hälfte, aber ich weiß nicht warum

:-(

Christian

von PIC (Gast)


Lesenswert?

Du musst warten bis das Flag 1 wird, und es dann löschen:


    while(PIR1bits.TXIF==0);
    PIR1bits.TXIF=0;

von holger (Gast)


Lesenswert?

Oder günstiger:

void UART_Zeichen_senden(unsigned char zeichen)
{
 while(!TXSTAbits.TRMT);   // Loop til TXREG empty
 TXREG = zeichen;    //Send data
}

von BWW (Gast)


Lesenswert?

Hier mal der aktuelle Code meiner Funktion:

1
void UART_Zeichen_senden(unsigned char zeichen)
2
{
3
    // Zeichen in den Ausgabepuffer schreiben
4
    TXREG = zeichen;
5
6
    // Warten, bis das Zeichen gesendet wurde
7
    while(PIR1bits.TXIF==0);
8
9
    // Flag löschen
10
    PIR1bits.TXIF=0;
11
}

Das ergibt als Ausgabe: "MCOHP."

Sieht ganz so aus, als würde er jedes zweite Zeichen weglassen.

Christian

von holger (Gast)


Lesenswert?

>Sieht ganz so aus, als würde er jedes zweite Zeichen weglassen.

Nimm mal meine Version mit dem TXSTA Register.
Das hat bei mir immer funktioniert.

von Dominic A. (neo123)


Lesenswert?

1
void UART_Zeichen_senden(unsigned char zeichen)
2
{
3
    TXREG = zeichen;    // Zeichen in den Ausgabepuffer schreiben
4
    while(!TRMT);
5
}

So funktioniert es bei mir.

von BWW (Gast)


Lesenswert?

Ich glaub ich geb's auf mit den PIC's, und kehre doch wieder zu den 
ATMegas zurück, die ich schon 3 Jahre "kenne" :-)

Mit dem Code:
1
void UART_Zeichen_senden(unsigned char zeichen)
2
{
3
    TXREG = zeichen;    // Zeichen in den Ausgabepuffer schreiben
4
    while(!TRMT);
5
}

kommt:

M(

großes M und ne Klammer dahinter, warum auch immer...

Christian

von holger (Gast)


Lesenswert?

Nochmal: Was passiert hiermit?

void UART_Zeichen_senden(unsigned char zeichen)
{
 while(!TXSTAbits.TRMT);   // Loop til TXREG empty
 TXREG = zeichen;    //Send data
}

von BWW (Gast)


Lesenswert?

ein syntax error vom compiler

von holger (Gast)


Lesenswert?

>ein syntax error vom compiler

Komplette Fehlermeldung posten.
Welcher Compiler?

Und wieso definiert du den ganzen Kram hier neu?

myuart.h:

// Bitdefinitionen
#define SPEN 7
#define TX9  6
#define TXEN 5
#define SYNC 4
#define BRGH 2
#define TRMT 1
#define TXIF 4

Das steht mit Sicherheit irgendwo in einer Headerdatei vom Compiler.

von BWW (Gast)


Lesenswert?

ok hier die Meldung:

Error: syntax error

in Zeile:

while(!TXSTAbits.TRMT);   // Loop til TXREG empty

Die Definitionen deswegen, weil der Compiler die Bits nicht kennt, und 
rot unterstreicht. Ich hab mir auch noch nicht die Mühe gemacht, die 
entsprechende Headerdatei zu suchen und einzubinden.

Christian

von holger (Gast)


Lesenswert?

>weil der Compiler die Bits nicht kennt

Welcher Compiler?

Was passiert wenn du diese Zeile

    TXSTA &= ~(1<<BRGH);         // High Speed Aus

so schreibst

    TXSTAbits.BRGH = 0;         // High Speed Aus

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

1
void UART_Zeile_senden(char *zeile)
2
{
3
    // Solange senden, bis Stringende erreicht
4
    while(*zeile)
5
    {
6
        // Einzelnes Zeichen senden
7
        UART_Zeichen_senden(*zeile);
8
9
        // Nächstes Zeichen
10
        *zeile++;  // <--- ?
11
    }
12
}

In der gekennzeichneten Zeile:

Was genau wird da inkrementiert?
Und was soll inkrementiert werden?

von BWW (Gast)


Lesenswert?

holger schrieb:
> TXSTAbits.BRGH = 0;

holger schrieb:
>>weil der Compiler die Bits nicht kennt
>
> Welcher Compiler?
>
> Was passiert wenn du diese Zeile
>
>     TXSTA &= ~(1<<BRGH);         // High Speed Aus
>
> so schreibst
>
>     TXSTAbits.BRGH = 0;         // High Speed Aus

Compiler: C18 (v3.45) [C:\Program Files\Microchip\mplabc18\v3.45\bin]

Da passiert: myuart.h:19:Error: syntax error



Rufus Τ. Firefly schrieb:
> void UART_Zeile_senden(char *zeile)
> {
>     // Solange senden, bis Stringende erreicht
>     while(*zeile)
>     {
>         // Einzelnes Zeichen senden
>         UART_Zeichen_senden(*zeile);
>
>         // Nächstes Zeichen
>         *zeile++;  // <--- ?
>     }
> }
>
> In der gekennzeichneten Zeile:
>
> Was genau wird da inkrementiert?
> Und was soll inkrementiert werden?

oh, der Stern muss da weg ;-)

Christian

von holger (Gast)


Lesenswert?

>Da passiert: myuart.h:19:Error: syntax error

Dann mach mal ein

#include <p18f258.h>

da rein.

Wie kommt man eigentlich auf die Idee Funktionen in
eine Header Datei zu legen?

von Fragenüberfragen (Gast)


Lesenswert?

holger schrieb:
> Wie kommt man eigentlich auf die Idee Funktionen in
> eine Header Datei zu legen?

Sowas lernt man wohl in drei Jahren der AVR "Programmiererei".

von Fragenüberfragen (Gast)


Lesenswert?

Für nen PIC16F887 hab ich das wie folgt gemacht. Vielleicht hilfts ja.
1
void UART_Send(uint8_t Byte)
2
{
3
    uint8_t byteSend = 0;
4
    
5
    do {
6
      if(TXIF){
7
        TXREG = Byte;
8
        byteSend = 1;
9
      
10
      }else{
11
        while( !TRMT );
12
      }   
13
    } while (byteSend == 0);
14
15
    
16
}

von BWW (Gast)


Lesenswert?

Das "#include <p18f258.h>" bewirkt leider nix.

Wieder:

myuart.h:21:Error: syntax error

In Zeile:

TXSTAbits.BRGH = 0;         // High Speed Aus

Christian

von Fragenüberfragen (Gast)


Lesenswert?

Mach mal bitte deine aktuelle header datei hier rein.

von holger (Gast)


Lesenswert?

>Für nen PIC16F887 hab ich das wie folgt gemacht. Vielleicht hilfts ja.

Nein, das hilft nicht. Beim C18 läuft das anders.

von holger (Gast)


Lesenswert?

>Das "#include <p18f258.h>" bewirkt leider nix.

Dann mach das

#define BRGH 2

mal weg.

von Fragenüberfragen (Gast)


Lesenswert?

Erklärbär doch mal wieso das nicht gehen soll.

von BWW (Gast)


Lesenswert?

Hier mal die aktuelle Version der "myuart.h"
1
#include <p18f258.h>
2
3
// Bitdefinitionen
4
#define SPEN 7
5
#define TX9  6
6
#define TXEN 5
7
#define SYNC 4
8
// #define BRGH 2
9
#define TRMT 1
10
11
// UART initialisieren
12
void UART_Init(void)
13
{
14
    SPBRG = 3;                   // Baud Rate Generator Register, 57600 bd
15
    TXSTAbits.BRGH = 0;          // High Speed Aus
16
    TXSTA &= ~(1<<SYNC);         // Asynchroner Modus
17
    TXSTA &= ~(1<<TX9);          // 8-bit-Übertragung
18
    TXSTA |=  (1<<TXEN);         // Transmit Enable
19
    RCSTA |=  (1<<SPEN);         // RX und TX Pins aktivieren
20
}
21
22
void UART_Zeichen_senden(unsigned char zeichen)
23
{
24
    TXREG = zeichen;
25
    while(!TRMT);
26
}
27
28
void UART_Zeile_senden(char *zeile)
29
{
30
    // Solange senden, bis Stringende erreicht
31
    while(*zeile)
32
    {
33
        // Einzelnes Zeichen senden
34
        UART_Zeichen_senden(*zeile);
35
36
        // Nächstes Zeichen
37
        zeile++;
38
    }
39
}

Die aktuelle Ausgabe im Terminalprogramm:

M(

von holger (Gast)


Lesenswert?

Jetzt nimmst du mal das:

void UART_Zeichen_senden(unsigned char zeichen)
{
 while(!TXSTAbits.TRMT);   // Loop til TXREG empty
 TXREG = zeichen;    //Send data
}

Und entfernst das

#define TRMT 1



>Erklärbär doch mal wieso das nicht gehen soll.

Weil

 while(!TRMT);

mit seinem define mit Sicherheit nicht auf TXSTA zugreift.

von BWW (Gast)


Lesenswert?

Danke! Sieht gut aus.

Es kommt: "MICROCHIP."

Nur diese Zeile: UART_Zeile_senden("TECHNOLOGY.");

ist noch ohne Funktion... Da kommt leider nix.

Christian

von holger (Gast)


Lesenswert?

Noch ein Versuch:

void UART_Zeile_senden(char *zeile)
{
 unsigned char c;

   // Solange senden, bis Stringende erreicht
    while((c = *zeile++))
    {
        // Einzelnes Zeichen senden
       UART_Zeichen_senden(c);
    }
}

von BWW (Gast)


Lesenswert?

holger schrieb:
> Noch ein Versuch:

Leider nicht :-(

Mit dem unten angegebenen Code kommt im Terminalfenster "MICROCHIP." an. 
Das "TECHNOLOGY." fehlt.

Hier mal im Anhang mein aktueller Quellcode, damit man mal einen 
Überblick hat, was alles mittlerweile verändert wurde.

Aktueller Stand "main.c":
1
#pragma config OSC = HS         // 14,7456 MHz
2
#pragma config PWRT = ON        // Power-On-Timer
3
#pragma config WDT = OFF        // Watchdog off
4
5
#include <delays.h>
6
#include <p18f258.h>
7
8
// Ausgänge initialisieren
9
void Ausgaenge_Init(void)
10
{
11
    TRISCbits.RC3 = 0;      // C3: LED rot
12
    TRISCbits.RC4 = 0;      // C4: LED grün
13
}
14
15
// Eingänge initialisieren
16
void Eingaenge_Init(void)
17
{
18
    // A0: Fotowiderstand
19
}
20
21
// Funktion Pin C3 Ein- oder Ausschalten
22
void Set_LED_rot(char status)
23
{
24
    if(status)  LATCbits.LATC3 = 1;
25
    if(!status) LATCbits.LATC3 = 0;
26
}
27
28
// Funktion Pin C4 Ein- oder Ausschalten
29
void Set_LED_gruen(char status)
30
{
31
    if(status)  LATCbits.LATC4 = 1;
32
    if(!status) LATCbits.LATC4 = 0;
33
}
34
35
// UART initialisieren
36
void UART_Init(void)
37
{
38
    SPBRG = 3;                  // Baud Rate Generator Register, 57600 bd
39
    TXSTAbits.BRGH = 0;         // High Speed Aus
40
    TXSTAbits.SYNC = 0;         // Asynchroner Modus
41
    TXSTAbits.TX9  = 0;         // 8-bit-Übertragung
42
    TXSTAbits.TXEN = 1;         // Transmit Enable
43
    RCSTAbits.SPEN = 1;         // RX und TX Pins aktivieren
44
}
45
46
void UART_Zeichen_senden(unsigned char zeichen)
47
{
48
    while(!TXSTAbits.TRMT);     // Warten, bis TXREG leer ist
49
    TXREG = zeichen;            // Zeichen senden
50
}
51
52
void UART_Zeile_senden(char *zeile)
53
{
54
    unsigned char c;
55
56
    // Solange senden, bis Stringende erreicht
57
    while((c = *zeile++))
58
    {
59
        // Einzelnes Zeichen senden
60
       UART_Zeichen_senden(c);
61
    }
62
}
63
64
int main(void)
65
{
66
    // Ausgänge initialisieren
67
    Ausgaenge_Init();
68
69
    // Eingänge initialisieren
70
    Eingaenge_Init();
71
72
    // UART initialisieren
73
    UART_Init();
74
75
    // Ausgang C4 auf High
76
    Set_LED_gruen(1);
77
78
    // Hauptschleife
79
    while(1)
80
    {
81
        // Ausgang C3 auf high
82
        Set_LED_rot(1);
83
84
        // Warten
85
        Delay10KTCYx(64);
86
87
        // Ausgang C3 auf low
88
        Set_LED_rot(0);
89
90
        // Warten
91
        Delay10KTCYx(255);
92
93
        // UART Test
94
        UART_Zeichen_senden('M');
95
        UART_Zeichen_senden('I');
96
        UART_Zeichen_senden('C');
97
        UART_Zeichen_senden('R');
98
        UART_Zeichen_senden('O');
99
        UART_Zeichen_senden('C');
100
        UART_Zeichen_senden('H');
101
        UART_Zeichen_senden('I');
102
        UART_Zeichen_senden('P');
103
        UART_Zeichen_senden('.');
104
105
        UART_Zeile_senden("TECHNOLOGY.");
106
   }
107
108
   return 0;
109
}

von holger (Gast)


Lesenswert?

Dann vieleicht so:

void UART_Zeile_senden(const rom char *zeile)

So ging das bei mir immer.

von BWW (Gast)


Lesenswert?

holger schrieb:
> Dann vieleicht so:
>
> void UART_Zeile_senden(const rom char *zeile)
>
> So ging das bei mir immer.

ok vielen Dank! :-)

Werd mich aber dann doch wohl wieder der AVR-"Programmiererei" zuwenden, 
und mich mal durch gute C-Bücher lesen...

Christian

von Erich (Gast)


Lesenswert?

>und mich mal durch gute C-Bücher lesen

Das wird leider auch nichts helfen, wenn du das Grundprinzip der 
seriellen Datenübertragung beim Senden nicht kapieren willst!

Man muss ERST abfragen, ob das VORHERIGE Zeichen rausgegangen ist und 
der Sendebuffer somit frei (geworden) ist.
NUR DANN darf man in das Sende-Datenregister schreiben.

Du machst das genau falsch herum und so hast du den Effekt "jeden 2. 
Zeichen fehlt" und ähnliches.

Anschliessend warten braucht man nicht bzw. sollte das auch nicht tun.
Warum?  Das kannst dir jetzt selbst überlegen!

Gruss

von Karl H. (kbuchegg)


Lesenswert?

Erich schrieb:

> Man muss ERST abfragen, ob das VORHERIGE Zeichen rausgegangen ist und
> der Sendebuffer somit frei (geworden) ist.


Macht er ja jetzt auch nicht mehr
1
void UART_Zeichen_senden(unsigned char zeichen)
2
{
3
    while(!TXSTAbits.TRMT);     // Warten, bis TXREG leer ist
4
    TXREG = zeichen;            // Zeichen senden
5
}
´
Das sieht für mich durchaus OK aus.

Aber wenn ich mich recht erinnere, und worauf auch Holger hinauswollte: 
Auf einigen PIC gibt es da so einen Fallstrick, dass ein 
Character-Literal, also ein konstanter String - eben nicht ein const 
char* ist, sondern dass das ganze übers Flash abgewickelt wird (da wird 
der String in den Programmcode eingebettet). D.h. man muss dauernd drauf 
achten, ob man jetzt eine String-Konstante oder ein tatsächlich 
variables char-Array hat und dann je nachdem die richtige Funktion 
aufrufen.

von Erich (Gast)


Lesenswert?

Ok, Nachtrag:

putrsUSART

http://www.tcnj.edu/~hernande/ELC343/Chapter_09.pdf
siehe Seite 34/57


Lt. http://www.microchip.com/forums/m629329.aspx
 void putrsUSART(const rom char *data)
 {
     while (*data) {  // Transmit a byte
         while(BusyUSART());
         putcUART(*data++);
     }
 }

Siehe auch  http://www.microchip.com/forums/m681164.aspx

Gruss

von BWW (Gast)


Lesenswert?

Nochmal Danke.

Christian ;)

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.