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);
}
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:
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.
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
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
voidmain(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
chartext[100];
10
unsignedintlength=12;
11
unsignedintlength2=12;
12
inte=2;
13
intf=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
voiduart_init(void){
30
RCSTAbits.SPEN=1;//1 = Serial port enabled (configures RX/DT and TX/CK pins as serial port pins)
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:
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.
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
voidmain(void)
10
{
11
// Insert Init
12
13
chartext[RX_BUFFER_SIZE];
14
uint8_trx_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
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?
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?
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.