Forum: Mikrocontroller und Digitale Elektronik PIC18F26K80 UART Problem (string)


von Marcel W. (macew)


Lesenswert?

Hallo,

seit kurzem verwende ich den PIC18F26K80 MC um Sensorsignale zu 
verarbeiten. Leider ist es mir auch nach tagelangem Probieren und 
Stöbern in verschiedenen Foren nicht möglich ein Signal über die 
UART-Schnittstelle nach außen zu transportieren.

Ich verwende MPLAB X IDE v3.55
und als Compiler XC8 v1.41

Dabei zeigt sich insbesondere das folgende Problem:

ich möchte das UART Transmit Register TXREG1 beschreiben und bestimmte 
Daten über die UART-Schnittstelle an einen PC zu übertragen.

folgende Zuweisung funktioniert:
1
TXREG1 = 'a';
-> dabei wird das Signal wie erwartet richtig per UART übertragen.

definiere ich aber hingegen wie folgt
1
char test = 'a';
2
TXREG1 = test;
wird nur ein \0 ausgesendet:

Im Forum konnte ich lesen, dass das evt. durch Zugriffe auf verschiedene 
Speicherareale (Programm- und Datenspeicher) verursacht wird. Nach 
weiterer Recherche sollte das aber nur beim C18 Compiler von microchip 
auftreten und nicht mehr beim XC8, der automatisch das richtige 
Verhalten zeigen sollte... leider haben die besprochenen 
Lösungsvorschläge keine Veränderung
gebracht.  (Beitrag "String-Ausgabe über UART funktioniert nicht bei PIC 18F")

Hat jemand ein ähnliches Problem schon gehabt und eine Lösung dafür 
gefunden?


Beste Grüße,

Marcel

: Bearbeitet durch User
von Achim.S (Gast)


Lesenswert?

Glaube ich nicht.

Poste vielleicht doch den Code, und schaue Dir ALLE Warnungen Deines 
Codes an.

Marcel W. schrieb:
> char test = 'a';
> TXREG1 = test;

sind die Zeilen wirklich direkt so übereinander?

von Thomas F. (_thomas_)


Lesenswert?

> Hat jemand ein ähnliches Problem schon gehabt und eine Lösung dafür
> gefunden?

Sowas ähnliches hatte ich bei einem PIC18F26K40-Projekt. Nach mehreren 
Stunden Suche, die Erkenntnis: es gibt einen PIC18-Core-Bug, der sich 
"TBLRD  Requires  NVMREG  Value  to  Point  to Appropriate Memory" nennt 
(am besten im Errata nachsehen, ob das bei deinem auch zutrifft).
Abhilfe: Linkeroption "--errata=+NVMREG" setzen.

von Volker S. (vloki)


Lesenswert?

Marcel,
deine Beschreibung passt nicht so ganz zum Titel.

Was hat dein Problem mit Strings zu tun?
(kannst du das nochmal genauer erleutern)

Beitrag #5049979 wurde vom Autor gelöscht.
von Thomas F. (_thomas_)


Angehängte Dateien:

Lesenswert?

Thomas F. schrieb:
> Abhilfe: Linkeroption "--errata=+NVMREG" setzen.

Im Anhang noch ein Screenshot, wie man das in MPLAB setzen kann.

von Volker S. (vloki)


Lesenswert?

Ich verwende gerade K80 und hatte soweit ich mich erinnern kann bisher 
keine Probleme mit der USART.

Besser mal den tatsächlichen Code posten...

von Marcel W. (macew)


Lesenswert?

Hallo zusammen,
schonmal vielen Dank für alle Hilfe. Ich habe heute morgen versucht ein 
Minimal-Programm zu erstellen um den Fehler zu reproduzieren. Den Fehler 
selbst bekomme ich nicht reproduziert, aber ein völlig unberechenbares 
Verhalten der UART-Schnittstelle. Entweder fehlt irgendeine 
grundsätzliche Einstellung oder ich mache irgendetwas grundsätzliches 
falsch.

Thomas F. schrieb:
> Thomas F. schrieb:
>> Abhilfe: Linkeroption "--errata=+NVMREG" setzen.
>
> Im Anhang noch ein Screenshot, wie man das in MPLAB setzen kann.

Das hatte ich auch schonmal gefunden, wusste aber nicht, wo ich es 
einstellen kann. Danke für die Info. Leider hat es nicht meine Fehler 
behoben...

hier der C-Code aus einem Minimalbeispiel. Hier wird auch ersichtlich, 
weshalb es um strings geht (als char arrays) - dabei funktioniert 
zurzeit nämlich gar nichts.
1
// Zum Auslesen der UART Schnittstelle wird HTERM 0.8.1beta verwendet.
2
3
#define PLL_ENABLED
4
5
#ifdef PLL_ENABLED
6
#define _XTAL_FREQ 64000000UL
7
#endif
8
9
#ifndef PLL_ENABLED
10
#define _XTAL_FREQ 16000000UL
11
#endif
12
13
#include <xc.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
18
#pragma config FOSC = HS1       // Oscillator High Speed Crystal/Resonator 16 MHz
19
20
#ifdef PLL_ENABLED
21
#pragma config PLLCFG = ON      // Use PLL-module to push up system clock to 64 MHz so that instruction clock becomes 16MHz (system_clock/4)
22
#endif
23
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
24
#pragma config PWRTEN = ON      // Power Up Timer (Disabled)
25
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
26
27
void putByte(char data)
28
{
29
    while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1);
30
    TXREG1 = data;   
31
}
32
33
void writeString(char *str)
34
{
35
    while(*str)
36
    {   
37
        putByte(*str);
38
        ++str;       
39
  }
40
}
41
42
void UARTInit(void)
43
{  
44
        TRISCbits.TRISC6 = 0;    
45
  TRISCbits.TRISC7 = 0;
46
    
47
    // Values from data sheet with Baudrate 9600 
48
    // Initialising BaudRate value 
49
50
        SPBRGH1 = 0x06;
51
        SPBRG1 = 0x82;        
52
        
53
        TXSTA1bits.BRGH      = 1;    // 1 = high speed baud rate
54
                                     // 0 = low speed baud rate 
55
        BAUDCON1bits.BRG16   = 1;    // 1 = 16 bit baud rate generator
56
                                     // 0 = 8 bit baud rate generator            
57
        TXSTA1bits.TX9       = 0;    // 0 = select 8-bit transmission
58
        TXSTA1bits.SYNC      = 0;    // 0 = async mode
59
        TXSTA1bits.SENDB     = 0;    // 1 = send sync break on next transmission
60
                                     // 0 = sync break transmission completed
61
        RCSTA1bits.SPEN      = 1;    // 1 = serial port enable
62
        RCSTA1bits.CREN      = 1;    // 1 = enable receiver
63
        BAUDCON1bits.TXCKP   = 0;    // 1 = idle state for transmit is HIGH
64
                                     // 0 = idle state for transmit is LOW
65
        
66
        TXSTA1bits.TXEN     = 1;    // 1 = transmit is enabled
67
}
68
69
int main(void)
70
{
71
    UARTInit();
72
73
    volatile char a = 'a';
74
    volatile char d;
75
    volatile char c;
76
    while(1)
77
    { 
78
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1);
79
        TXREG1 = a;                 // -> funktioniert nicht, Ausgabe per UART ist "c" (0x63) ?!?!?!? 
80
81
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1); 
82
        TXREG1 = 'b';               // -> funktioniert, Ausgabe per UART ist "b" (0x62)
83
        
84
        __delay_ms(200);
85
86
        c = 'c';    
87
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1); 
88
        TXREG1 = c;                 // -> funktioniert nicht, Ausgabe per UART ist ein quadrat (0x06) ?!?!?!?
89
90
           
91
        d = 'd';
92
        putByte(d);                 // -> funktioniert, Ausgabe per UART ist "d" (0x64))
93
94
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1); 
95
        TXREG1 = '\r';
96
        
97
        writeString("HelloWorld");  // -> hier funktioniert gar nichts, es werden keinerlei Signale am UART Pin ausgegeben
98
        char test[]= "Test-String";
99
        writeString(test);          // -> hier funktioniert gar nichts, es werden keinerlei Signale am UART Pin ausgegeben
100
        
101
        __delay_ms(2000);
102
    }
103
    return 1;
104
}

von Volker S. (vloki)


Lesenswert?

Also bei mir tut dein Programm im Wesentlichen. (xc8 v1.41, ältere IDE)
- Target voltage detected (5V)
- Target device PIC18F26K80 found.
- Device ID Revision = 2

Einige Sachen sind mir aber aufgefallen.

1. alle #includes ausser xc.h kann man sich sparen
2. void main(void) nicht int main(void)
3. C7 und C7 Pins sollten als Eingang konfiguriert werden
4. die Kommentare zum Idle-State sind falsch


Weil ich den internen Oszillator verwendet habe, sieht das jetzt so aus:
1
/*
2
 * File:   usart26K80.c
3
 * Author: vloki
4
 *
5
 * Created on 22. Juni 2017, 09:30
6
 */
7
8
9
#include <xc.h>
10
11
// #pragma config statements should precede project file includes.
12
// Use project enums instead of #define for ON and OFF.
13
14
// CONFIG1L
15
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
16
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
17
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
18
#pragma config XINST = OFF       // Extended Instruction Set (Disabled)
19
20
// CONFIG1H
21
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
22
#pragma config PLLCFG = ON      // PLL x4 Enable bit (Enabled)
23
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
24
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
25
26
// CONFIG2L
27
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
28
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
29
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
30
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)
31
32
// CONFIG2H
33
#pragma config WDTEN = SWDTDIS  // Watchdog Timer (WDT enabled in hardware; SWDTEN bit disabled)
34
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)
35
36
// CONFIG3H
37
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
38
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
39
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)
40
41
// CONFIG4L
42
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
43
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)
44
45
// CONFIG5L
46
...
47
48
49
#define _XTAL_FREQ 64000000UL
50
51
void putByte(char data);
52
void writeString(char *str);
53
void UARTInit(void);
54
55
void main(void) {
56
    OSCCONbits.IRCF = 0b111;    // interner Oszillator 16MHz
57
    OSCTUNEbits.PLLEN = 1;
58
//    while(OSCCONbits.HFIOFS == 0){;}  // wait until stable
59
    __delay_ms(1);
60
    
61
    UARTInit();
62
    
63
    volatile char a = 'a';
64
    volatile char d;
65
    volatile char c;
66
    while(1)
67
    { 
68
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1);
69
        TXREG1 = a;                 // -> funktioniert
70
        __delay_ms(500);
71
        
72
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1); 
73
        TXREG1 = 'b';               // -> funktioniert
74
        
75
        __delay_ms(200);
76
77
        c = 'c';    
78
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1); 
79
        TXREG1 = c;                 // -> funktioniert
80
81
           
82
        d = 'd';
83
        putByte(d);                 // -> funktioniert
84
        __delay_ms(200);
85
        
86
        while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1); 
87
        TXREG1 = '\r';
88
        __delay_ms(200);
89
        writeString("HelloWorld");  // -> funktioniert
90
        __delay_ms(1000);
91
        char test[]= "Test-String";
92
        writeString(test);          // -> funktioniert
93
        
94
        __delay_ms(1000);
95
    }
96
//    return;
97
}
98
99
void putByte(char data)
100
{
101
    while(TXSTA1bits.TRMT!=1 || PIR1bits.TX1IF!=1);
102
    TXREG1 = data;   
103
}
104
105
void writeString(char *str)
106
{
107
    while(*str)
108
    {   
109
        putByte(*str);
110
        ++str;       
111
  }
112
}
113
114
void UARTInit(void)
115
{  
116
    TRISCbits.TRISC6 = 1;    
117
    TRISCbits.TRISC7 = 1;
118
    
119
    // Values from data sheet with Baudrate 9600 
120
    // Initialising BaudRate value 
121
    SPBRGH1 = 0x06;
122
    SPBRG1 = 0x82;        
123
124
    TXSTA1bits.BRGH      = 1;    // 1 = high speed baud rate
125
                                 // 0 = low speed baud rate 
126
    BAUDCON1bits.BRG16   = 1;    // 1 = 16 bit baud rate generator
127
                                 // 0 = 8 bit baud rate generator            
128
    TXSTA1bits.TX9       = 0;    // 0 = select 8-bit transmission
129
    TXSTA1bits.SYNC      = 0;    // 0 = async mode
130
    TXSTA1bits.SENDB     = 0;    // 1 = send sync break on next transmission
131
                                 // 0 = sync break transmission completed
132
    RCSTA1bits.SPEN      = 1;    // 1 = serial port enable
133
    RCSTA1bits.CREN      = 1;    // 1 = enable receiver
134
//    BAUDCON1bits.TXCKP   = 0;    // 1 = idle state for transmit is HIGH
135
                                 // 0 = idle state for transmit is LOW
136
137
    TXSTA1bits.TXEN     = 1;    // 1 = transmit is enabled
138
}
Getestet habe ich es mit einem Oszilloskop, das auch Bussignale 
auswerten kann. (Darum sind auch viele der neuen Delays drin)

Zumindest bei der Verwendung des internen Oszillators auf 64MHz wird das 
aller erste Byte falsch übertragen, wenn es zu schnell nach dem Startup 
gesendet wird. Die Oszillator/PLL Kombination scheint dann noch nicht zu 
laufen.

: Bearbeitet durch User
von Marcel W. (macew)


Lesenswert?

Yaaayyyy, es funktioniert !!! Nach einer Woche verzweifelten 
Fehlersuchens funktioniert es endlich!! Vielen Dank, Volker, für deinen 
Code.

Ich vermute, dass es daran lag, dass ich nicht alle configs definiert 
hatte, weil ich dachte, dass ich sie nicht brauche und die 
Standardeinstellungen genügen. Dem war wohl leider nicht so. Jedenfalls 
freue ich mich sehr, dass ihr mir geholfen habt, DANKE!!!

von Volker S. (vloki)


Lesenswert?

Marcel W. schrieb:
> Ich vermute, dass es daran lag, dass ich nicht alle configs definiert
> hatte, weil ich dachte, dass ich sie nicht brauche und die
> Standardeinstellungen genügen.

Ob es daran jetzt lag oder nicht, es ist auf jeden Fall gut immer alle 
zu definieren. Das geht auch sehr einfach:
-> http://microchipdeveloper.com/mplabx:view-and-set-configuration-bits

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.