Forum: Mikrocontroller und Digitale Elektronik PIC18F4550 uart tx sendet dauerhaft, Break ingoriert der chip


von Rainer (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen,

ich brauch mal eure Hilfe.

Allgemeine Daten:
Microcontroller: PIC18F4550
Software: MPLABX
Compiler: CX8

Problem: UART

Allgemein möchte ich ein RN4020 Bluetooth Chip mit einem PIC18F4550 
verbinden. Dies funktioniert soweit auch ganz gut, nur, dass ich eine 
anscheinend eine Wiederholungsschleife in meinem UART Transmitter habe, 
den ich leider nicht weg bekomme. Dies bedeutet, dass alle Befehle im 
RN4020 dauerhaft wiederholt werden. Das Problem konnte ich einkreisen, 
dass es an dem PIC liegen muss.

Ausgangssituation: An Hardware benutze ich einen externen Quarz mit 
14,7... MHz. die Übertragung der einzelnen Zeichen klappt auch ganz gut.

Ich hab den Code soweit gekürzt und diesen mit meinem Rechner 
mitgeschnitten. Aktuell möchte ich erstmal nur, dass er UART TX nicht 
dauerhaft sendet. Die dafür vorgesehenden Befehle SENDB (Send Break 
character Bit) konnte ich in meinem Code noch nicht optimal zum 
Unterbrechen einsetzen. Auch der Versuch TXEN (also Übertragung 
verbieten) brachte nicht wirklich was.

Hat jemand eine gute Idee dieses Problem zu lösen? Ist es evt. dafür 
erforderlich eine RX Schnittstelle implementiert zu haben?

Hier mein CODE:

/*
 * File:   main.c
 * Author: Rainer
 *
 * Created on 03. Juli 2015, 11:01
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <usart.h>
#include <pic18f4550.h>

#define _XTAL_FREQ   14745600 // This one is just for __delay_ms
#pragma config FOSC = HS
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit 
(Fail-Safe Clock Monitor disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum 
setting)
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT 
disabled (control is placed on the SWDTEN bit))
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot 
block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data 
EEPROM is not code-protected)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit 
(Single-Supply ICSP disabled)
#pragma config MCLRE = OFF        //Enable MCLR Enable
#pragma config IESO    = OFF            // Disable Oscillator Switchover 
mode
#pragma config PWRT    = OFF            // Disable Power-up timer
#pragma config ICPRT   = OFF            // Disable dedicated programming 
port (only on 44-pin devices)
#pragma config CP0     = OFF            // Disable Code Protection Bit


void uart_init(void);
void uart_send_string(char* string);
void uart_send_char(char c);



int main(int argc, char** argv) {
    ADCON1 |= 0x0F; //Configure AN pins as digital
    CMCON |= 0x07; //Disable Comparators
    OSCCON |= 0x08; //external OSCILLATOR

    //Initialize UART
    uart_init();

    //Data to send
    char test[]={"Test\n"};

    uart_send_string(test);
    return (EXIT_SUCCESS);
}


void uart_init(void) {

    RCSTAbits.SPEN = 1; //1 = Serial port enabled (configures RX/DT and 
TX/CK pins as serial port pins)
    RCSTAbits.CREN = 1; //Asynchronous mode:1 = Enables receiver
    TXSTAbits.TXEN = 1; //enable transmission
    SPBRG = 7;          //115200kbits
    TXSTAbits.TX9 = 0;  //Selects 8-bit transmission
    TXSTAbits.TX9D = 1; //9th bit of Transmit Data. Can be address/data 
bit or a parity bit.
    TXSTAbits.SYNC = 0; //0 = Asynchronous mode
    TXSTAbits.BRGH = 1; //Asynchronous mode: 1 = High speed
    BAUDCONbits.BRG16 = 0; //0 = 8-bit Baud Rate Generator ? SPBRG only 
(Compatible mode), SPBRGH value ignored


    //Pin HW HIGH
    TRISDbits.TRISD1 = 0; //HW Pin activate
    LATDbits.LATD1 = 1; //WH Pin OUTPUT

    //Pin SW HIGH
    TRISDbits.TRISD3 = 0; //SW Pin activate
    LATDbits.LATD3 = 1; //SW Pin OUTPUT

    //Pin CMD LOW
    TRISDbits.TRISD2 = 0; //CMD Pin LOW
    LATDbits.LATD2 = 0; //CMD Pin LOW

}

/*
 * Send a command.
 */
void uart_send_string(char* string) {
    char* command = string;
    while (*command != '\n') {
        if (TXSTAbits.TRMT) {
            uart_send_char(*command++);
        }
    }

    uart_send_char('\n');
    TXSTAbits.SENDB = 1;
    TXSTAbits.TXEN=0;
}

/*
 * Send a single character.
 */
void uart_send_char(char c) {
    TXREG = c;
    while (PIR1bits.TXIF == 0);
}

von Max H. (hartl192)


Lesenswert?

Rainer schrieb:
> return (EXIT_SUCCESS);
Ersetzt das man durch
1
while(1);

> char* command = string;
Das kannst du dir sparen und direkt mit "string" arbeiten.

> while (*command != '\n') {
Das würde ich zur Sicherheit so machen
1
while (*command != '\n' && *command)
oder das
> *command != '\n'
komplett durch
1
*command
ersetzen, dann brauchst du das
> uart_send_char('\n');
auch nicht mehr.


P.S. Für C-Code bitte die Formatierung verwenden:
1
[c]C-Code[/c]

: Bearbeitet durch User
von Little B. (lil-b)


Lesenswert?

Rainer schrieb:
> TXSTAbits.SENDB = 1;

warum? das benötigt das protokoll zum rn4020 doch gar nicht? was 
erhoffst du dir damit?

Rainer schrieb:
> TXSTAbits.TXEN=0;

warum? tx-buffer ist doch sowieso leer? es wird nichts mehr gesendet?

Max H. schrieb:
> Rainer schrieb:
>> return (EXIT_SUCCESS);
> Ersetzt das man durch
> while(1);

naja, "ersetzt" vieleicht nicht.
es wird davor gesetzt, damit "return (EXIT_SUCCESS)" nie erreicht wird.
das wird hier wohl dein fehler sein, denn vermutlich wird dann ein reset 
ausgeführt und von vorne begonnen.

von Max H. (hartl192)


Lesenswert?

Little B. schrieb:
> return (EXIT_SUCCESS)
Wozu braucht die main() auf einem µC überhaupt einen return-Wert, argc 
und argv? Ich schreibe da immer
1
void main(void)

: Bearbeitet durch User
von Rainer (Gast)


Lesenswert?

Vielen Dank @Max H und @Little Basdart.

Ich hab die Änderungen vorgenommen und siehe da er schreibt es nur noch 
einmal.

Little B. schrieb:
> warum? das benötigt das protokoll zum rn4020 doch gar nicht? was
> erhoffst du dir damit?

Little B. schrieb:
> warum? tx-buffer ist doch sowieso leer? es wird nichts mehr gesendet?


Hiermit habe ich mir erhofft, dass ich TX Signal unterbrechen und 
beenden kann. Hab schon einige Forenbeiträge gelesen, sowie das 
Datenblatt. Ab und an haben diese Befehle in Kombinationen auch schöne 
Quereffekte ausgelöst.

Werde jetzt versuchen die Änderungen an die Befehle des RN4020 
einzubauen.

Danke erstmal!
Gruß Rainer

von Rainer (Gast)


Lesenswert?

Hallo Zusammen,
ich brauche nochmal eure Hilfe.
Hier im Forum wurde das Lesen mit den folgenden Codeschnipsel 
vorgeschlagen.
Ich hab jetzt 3 Tagen versucht diesen Code zusammen mit den 
Bluetoothchip zum laufen zu bekommen. Mit der Verbindung zum PC klappt 
das gut. Ich konnte den String simulieren, nur leider, wenn der RN4020 
angeschlossen war klappte es nicht. Der Rückweg vom RN4020 zum PIC hab 
ich geprüft und die Zeichen sind auf der RX Leitung vom Pic lesbar.  Die 
Funktion compare_text vergleicht einfach nur zwei Strings miteinander 
über eine bestimmte Länge. Die ist in Codeblocks mit Testwerten komplett 
erfolgreich getestet worden. Den Rest des Codes steht ja oben genommen 
werden. Hat jemand eine Idee woran es liegen könnte? Hat jemand nen 
kleinen anderen Codeschnipsel die Daten vom RN4020 zu lesen? Ist evt. 
der Line Feed von RN4020 der Grund?
1
void main(void) {
2
    ADCON1 |= 0x0F; //Configure AN pins as digital
3
    CMCON |= 0x07; //Disable Comparators
4
    OSCCON |= 0x08; //external OSCILLATOR
5
6
7
    //Initialize UART
8
    uart_init();
9
    char text[100];
10
    unsigned int length = 12;
11
    unsigned int length2 = 12;
12
    int e = 2;
13
    int f = 2;
14
    do {
15
        if (uart_data_ready()) {
16
            uart_read_text(&text, length);
17
            e = compare_text(text, "TT,0000,1234.", length);
18
            if (e == 0) {
19
                LATBbits.LATB5 = 1;
20
            }
21
            f = compare_text(text, "TT,0000,123567.", length2);
22
            if (f == 0) {
23
                LATBbits.LATB5 = 0;
24
            }
25
        }
26
    } while (1);
27
}
28
29
void uart_init(void) {
30
    RCSTAbits.SPEN = 1; //1 = Serial port enabled (configures RX/DT and TX/CK pins as serial port pins)
31
32
    RCSTAbits.CREN = 1; //Asynchronous mode:1 = Enables receiver
33
    TXSTAbits.TXEN = 1; //enable transmission
34
35
    TXSTAbits.TX9 = 0; //Selects 8-bit transmission
36
    RCSTAbits.RX9 = 0; //Selects 8-bit transmission
37
38
    TXSTAbits.TX9D = 1; //9th bit of Transmit Data. Can be address/data bit or a parity bit.
39
    RCSTAbits.RX9D = 1; //Selects 8-bit transmission
40
41
    TXSTAbits.SYNC = 0; //0 = Asynchronous mode
42
    TXSTAbits.BRGH = 1; //Asynchronous mode: 1 = High speed
43
    BAUDCONbits.BRG16 = 0; //0 = 8-bit Baud Rate Generator ? SPBRG only (Compatible mode), SPBRGH value ignored
44
    SPBRG = 7;      //115200kbits
45
}
46
47
char uart_read() {
48
    while (!RCIF);
49
    return RCREG;
50
}
51
52
void uart_read_text(char *output, unsigned int length) {
53
    for (int i = 0; i < length; i++){
54
        output[i] = uart_read();
55
        //send_string(output[i]);
56
    }
57
}
58
59
char uart_data_ready(){
60
    return RCIF;
61
}

von Max H. (hartl192)


Lesenswert?

Du könntest mal versuchen "text" zurückzusenden oder mit einem Debugger, 
falls vorhanden, nachschauen ob der String richtig empfangen wird.

Rainer schrieb:
> for (int i = 0; i < length; i++){
>         output[i] = uart_read();
>         //send_string(output[i]);
>     }
Wenn die Länge der Nachricht kleiner als length ist, dann hast du hier 
eine Endlosschleife.

Ich würde das ganze in etwas so lösen:
1
//Untested
2
3
#define RX_BUFFER_SIZE 100
4
#define DELIMITER '\n'
5
6
7
char text[RX_BUFFER_SIZE];
8
uint8_t rx_counter = 0;
9
10
//Main Loop
11
while(1)
12
{
13
  if(uart_data_ready())
14
  {
15
    text[rx_counter] = RCREG;
16
    if(text[rx_counter] == DELIMITER)
17
    {
18
      text[++rx_counter] = '\0';
19
      // Do something with the String
20
    }
21
    else if(++rx_counter >= RX_BUFFER_SIZE - 1) // Buffer overflow 
22
      rx_counter = 0;
23
  }
24
25
  // Do some other stuff
26
27
}

: Bearbeitet durch User
von Rainer (Gast)


Angehängte Dateien:

Lesenswert?

Heyho Max,

ja das Problem sieht wie folgt aus. Ich hab mit nem Debugger mal den 
Text (String) mit geschnitten, was am PIC ankommt und es ist 
erschreckend. :(

In Text steht nach dem ersten Durchlauf nur Müll drin. Nach dem zweiten 
Durchlauf, nachdem ich den RN4020 String drauf los geschossen hab, sind 
da nur noch "M" drin.

Ich hab deinen Code in meinem zu Testzwecken eingebettet.
1
main{
2
3
    unsigned int counter = 0;
4
5
    char text[100];
6
    unsigned int length = 12;
7
    unsigned int length2 = 12;
8
    int e = 2;
9
    int f = 2;
10
    do {
11
        text[counter] = RCREG;
12
        if (text[counter] == '\r') {
13
            text[++counter] = '\0';
14
        } else if (++counter >= 100 - 1) // Buffer overflow 
15
        {
16
            counter = 0;
17
        }
18
         e = compare_text(text, "TT,0000,1234.", length);
19
            if (e == 0) {
20
                LATBbits.LATB5 = 1;
21
            }
22
            f = compare_text(text, "TT,0000,123567.", length2);
23
            if (f == 0) {
24
                LATBbits.LATB5 = 0;
25
            }
26
    } while (1);
27
}

von Rainer (Gast)


Lesenswert?

Bei meinem vorherigen Code Beispiel hängt sich der Debugger in dem 
Codefragment auf.
1
char uart_read() {
2
    while (!RCIF);
3
    return RCREG;
4
}

von Max H. (hartl192)


Lesenswert?

Rainer schrieb:
> Ich hab deinen Code in meinem zu Testzwecken eingebettet
und das
1
if(uart_data_ready())
vergessen. Ohne wird bei jedem Schleifendurchlauf irgendwas in text[] 
geschrieben.

Zudem würde ich nicht bei jedem durchlauf den String vergleichen. 
Erstens weil er erst nachdem der DELIMITER empfangen wurde 
nullterminiert ist und zweitens wird sinnlos Rechenzeit verschwendet.

Das könnte dann ungefähr so aussehen:
1
//Untested
2
3
#define RX_BUFFER_SIZE 100
4
#define DELIMITER '\r'
5
#define LENGTH 12
6
#define LENGTH2 12
7
8
9
void main(void)
10
{
11
  // Insert Init
12
  
13
  char text[RX_BUFFER_SIZE];
14
  uint8_t rx_counter = 0;
15
  
16
  while(1)
17
  {
18
    if(uart_data_ready())  // If we received a char
19
    {
20
      text[rx_counter] = RCREG;
21
      if(text[rx_counter] == DELIMITER)  // If we received the delimiter
22
      {
23
        text[++rx_counter] = '\0';  // Zero terminate the string
24
       
25
        // Compare the string
26
        if(compare_text(text, "TT,0000,1234.", LENGTH) == 0) 
27
          LATBbits.LATB5 = 1;
28
29
        if(compare_text(text, "TT,0000,123567.", LENGTH2) == 0) 
30
          LATBbits.LATB5 = 0;
31
32
      }
33
      else if(++rx_counter >= RX_BUFFER_SIZE - 1) // Buffer overflow 
34
        rx_counter = 0;
35
    }
36
37
    // Do some other stuff if necessary
38
39
  }
40
}


Rainer schrieb:
> Bei meinem vorherigen Code Beispiel hängt sich der Debugger in dem
> Codefragment auf.
> char uart_read() {
>     while (!RCIF);
>     return RCREG;
> }
Hast du die 12 Zeichen, auf die er wartet auch wirklich gesendet?

: Bearbeitet durch User
von Rainer (Gast)


Lesenswert?

Das Problem ist dass ich bei beiden Ansätzen leider nicht in das 
Textfeld mit dem Debugger rein komme. Mit dem chip kann ich leider keine 
Endlosschleife feuern. :( ich tapp echt im dunkeln. Hab deine Vorschlage 
wie du es beschrieben hast umgesetzt. Noch andere Ideen?

von W.S. (Gast)


Lesenswert?

Rainer schrieb:
> Noch andere Ideen?

Ja.
1. lies das Manual zu deinem Chip und versuche, es zu verstehen.
2. organisiere dir die seriellen Ein- und Ausgaben gepuffert und per 
Interrupt
3. probiere die E/A erstmal mit deinem PC als Partner zum µC aus, bis du 
dir sicher sein kannst, daß du sowas wie eine Kommandozeile tatsächlich 
in deinen µC hereinholen kannst und auch Echos, Texte und so weiter 
ordentlich gesendet werden
4. lerne programmieren. Nee, ich meine nicht "Lerne C" oder ne andere 
Sprache, sondern lerne, wie man sich Algorithmen zum Lösen eines 
anstehenden Problems erdenkt. Das hat mit konkreten Programmiersprachen 
noch nix zu tun.

W.S.

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.