Forum: Mikrocontroller und Digitale Elektronik TX und RX Kommunikation PIC16F688


von Stefan H. (stefan_h68)


Lesenswert?

Guten Morgen,
ich habe wieder mal eine Frage, und zwar habe ich ein kleines Programm 
geschrieben, um die serielle Kommunikation meiner beiden PIC16F688 zu 
testen. Hier mein C-Programm:

Sender:
1
#include <htc.h>              //include header file
2
#include <pic16f688.h>            //include PIC header
3
#ifndef _XTAL_FREQ  
4
#define _XTAL_FREQ 4000000
5
#define FOSC_INTOSCIO        0xFFFC      //set internal oscillator I/O function on RA4/OSC2/CLKOUT and RA5/OSC1/CLKIN
6
#define WDTE_OFF             0xFFF7      //disable Watchdog Timer
7
#define MCLRE_OFF            0xFFDF      //MCLR pin function is digital input, MCLR internally tied to VDD
8
#endif
9
10
void main (void)
11
{
12
  char byte;
13
14
  ANSEL = 0b00000000;            //All I/O pins are configured as digital 
15
  CMCON0 = 0b00000111;          //Comperators turned OFF
16
  PORTC = 0b00000000;          
17
    TRISC = 0b00000000;            
18
  SPBRG = 32;               
19
    BRG16 = 0;               
20
  TXEN = 1;
21
  SYNC = 0;
22
  SPEN = 1;
23
  TXSTA = 0b00100000;
24
  RCSTA = 0b10000000;
25
26
  while(1) {
27
    byte = 0xAF;
28
    TXREG = byte;
29
  }
30
}


Empfänger:
1
#include <htc.h>              //include header file
2
#include <pic16f688.h>            //include PIC header
3
#ifndef _XTAL_FREQ  
4
#define _XTAL_FREQ 4000000
5
#define FOSC_INTOSCIO        0xFFFC      //set internal oscillator I/O function on RA4/OSC2/CLKOUT and RA5/OSC1/CLKIN
6
#define WDTE_OFF             0xFFF7      //disable Watchdog Timer
7
#define MCLRE_OFF            0xFFDF      //MCLR pin function is digital input, MCLR internally tied to VDD
8
#endif
9
10
11
void main (void)
12
{
13
  ANSEL = 0b00000000;            //All I/O pins are configured as digital 
14
  CMCON0 = 0b00000111;          //Comperators turned OFF
15
  PORTC = 0b00000000;          
16
    TRISC = 0b00000000;            
17
  SPBRG = 32;               
18
    BRG16 = 0;                 //8 bit generator.
19
  CREN = 1;
20
  SYNC = 0;
21
  SPEN = 1;
22
  TXSTA = 0b00100000;
23
  RCSTA = 0b10010000;
24
25
  while(1) {
26
    if ( RCREG == 0xAF ) {
27
      PORTC == 0b00000001;
28
    }
29
30
    
31
  }
32
}


Leider funktioniert das Programm nicht und ich kann meine Fehlerquelle 
nicht finden. Ich hoffe ihr könnt mir helfen.
Mein Ziel ist es, am Senderpic ein Signal auszugeben, das der 
Empfängerpic erkennt und dann einen Port High schaltet.

Vielen Dank im vorraus.
MfG Stefan

von Martin (Gast)


Lesenswert?

Auf den ersten Blick ist mir folgendes aufgefallen:

PORTC == 0b00000001;

Mit == wird der Port verglichen und nicht gesetzt. Zum setzen des Ports 
= verwenden.

von Stefan H. (stefan_h68)


Lesenswert?

Martin schrieb:
> Mit == wird der Port verglichen und nicht gesetzt. Zum setzen des Ports
> = verwenden.

Danke, es schleichen sich halt immer wieder kleine Fehler ein :D
Nur habe ich jetzt das Problem, dass der Port nicht Konstant auf High 
geschaltet. Wie kann ich das den bewerkstelligen?

von Karl H. (kbuchegg)


Lesenswert?

Stefan H. schrieb:
> Martin schrieb:
>> Mit == wird der Port verglichen und nicht gesetzt. Zum setzen des Ports
>> = verwenden.
>
> Danke, es schleichen sich halt immer wieder kleine Fehler ein :D
> Nur habe ich jetzt das Problem, dass der Port nicht Konstant auf High
> geschaltet. Wie kann ich das den bewerkstelligen?

Wenn der mit DEM Programm nicht dauerhaft auf High-schaltet, dann gibt 
es dazu eigentlich nur eine Möglichkeit: dein µC stürzt laufend ab. Denn 
innerhalb der while-Schleife gibt es keine Möglichkeit, wie der Port 
jemals wieder von 0x01 auf irgendwas anderes geschaltet werden könnte.
Nach einem Absturz allerdings wird der Port, weil ja das Programm wieder 
von vorne erneut losläuft, tatsächlich auf 0 geschaltet.

von Stefan H. (stefan_h68)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Denn
> innerhalb der while-Schleife gibt es keine Möglichkeit, wie der Port
> jemals wieder von 0x01 auf irgendwas anderes geschaltet werden könnte.

Das habe ich mir auch schon gedacht, nur warum stürzt er denn ab? An was 
kann das liegen und wie kann ich das verhindern?

Edit: Oszi zeigt, dass die Zustandsänderungen nicht regelmäßig sind, 
schließt das dann ein Abstürzen des PICs denn nicht aus?

von Karl H. (kbuchegg)


Lesenswert?

Stefan H. schrieb:
> Karl Heinz Buchegger schrieb:
>> Denn
>> innerhalb der while-Schleife gibt es keine Möglichkeit, wie der Port
>> jemals wieder von 0x01 auf irgendwas anderes geschaltet werden könnte.
>
> Das habe ich mir auch schon gedacht, nur warum stürzt er denn ab? An was
> kann das liegen und wie kann ich das verhindern?

Das weiß ich nicht. Ich such mir jetzt nicht auch noch die PIC 
Datenblätter zusammen um zu identifizieren, was deine Binärzahlen 
eigentlich so alles freischalten. Einen Interrupt vielleicht, der nicht 
behandelt wird?

> Edit: Oszi zeigt, dass die Zustandsänderungen nicht regelmäßig sind,
> schließt das dann ein Abstürzen des PICs denn nicht aus?

Dein Sendecode ist ja auch alles andere als regelmässig. Einfach Bytes 
nach gutdünken willkürlich in die Register stopfen während die USART 
noch beschäftigt ist .... ich kenn eigentlich keine Architektur, auf der 
man das so machen kann. Aber gut, ich kenn auch nicht alle.

Mach halt folgendes:
Nimm einen Pin .. kabel eine LED drann und im main() ehe es in die while 
Schleife reingeht schaltest du die LED für 1 Sekunde ein und wieder aus. 
Wenn dann im laufenden Betrieb die LED mal aufleuchtet, dann weißt du, 
dass es einen Reset gab.

von Chris B. (dekatz)


Lesenswert?

Die UART-Initialierung ist eigentlich OK, aber wie schon angesprochen - 
das permanente "Befeuern" von TXREG mit Werten ohne auf den Sendestatus 
zu achten ist nicht die "normale" Art...
TXSTA.TRMT testen (Transmit Shift Register Status bit:0 = full, 1 = 
empty)

von Stefan H. (stefan_h68)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Dein Sendecode ist ja auch alles andere als regelmässig. Einfach Bytes
> nach gutdünken willkürlich in die Register stopfen während die USART
> noch beschäftigt ist .... ich kenn eigentlich keine Architektur, auf der
> man das so machen kann. Aber gut, ich kenn auch nicht alle.

Ich kann es leider noch nicht anders, da ich noch nicht allzulange in C 
programmiere.

Karl Heinz Buchegger schrieb:
> ch such mir jetzt nicht auch noch die PIC
> Datenblätter zusammen

Das erwarte ich auch nicht von dir :)

Chris B. schrieb:
> TXSTA.TRMT testen (Transmit Shift Register Status bit:0 = full, 1 =
> empty)

Was genau meinst du damit?
Wäre nett, wenn ihr mir vielleicht einen kleinen Beispielcode geben 
könntet, an dem ich mich "entlanghangeln" kann, um zu lernen.

Vielen Dank

von Chris B. (dekatz)


Lesenswert?

while( !TXSTA.TRMT);
wartet bis TXSTA.TRMT auf "1" ist - also der Senderegister leer ist.
Ein Beschreiben von TXREG überschreibt das Senderegister und startet 
eine neue Übertragung.
Wie jetzt TXSTA, TXREG und das "Transmit shift register" genau verknüpft 
sind und sich gegenseitig enablen/disablen ....siehe Datenblatt!

von Stefan H. (stefan_h68)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Mach halt folgendes:
> Nimm einen Pin .. kabel eine LED drann und im main() ehe es in die while
> Schleife reingeht schaltest du die LED für 1 Sekunde ein und wieder aus.
> Wenn dann im laufenden Betrieb die LED mal aufleuchtet, dann weißt du,
> dass es einen Reset gab.

Hab ich jetzt mal probiert und ja, mein Programm bleibt einfach nicht in 
der while(1){}
aber warum das? Hab jetzt schon den ganzen morgen sämtliche 
Einstellungen am PIC ausprobiert, aber er bleibt einfach nicht in der 
Loop. Könnt Ihr mir helfen?

von Chris B. (dekatz)


Lesenswert?

Möglich das der Controller dauern Resetet (Watchdog).
Ich glaube nämlich nicht, das der Controller damit Configuriert wird:
.....
#define FOSC_INTOSCIO        0xFFFC
#define WDTE_OFF             0xFFF7
#define MCLRE_OFF            0xFFDF
.....

Beim HTC-C sieht das so aus (nur Beispiel):
#include <htc.h>
__CONFIG(WDTDIS & HS & UNPROTECT);
usw....

Oder du machst es aus der ID (MPLAB) heraus mit "config -> Configuration 
bits"...

Denn am Simulator laufen die beiden Beispiele - zumindest in Bezug auf 
Abarbeitung der while-Konstruktion!

von Stefan H. (stefan_h68)


Lesenswert?

Chris B. schrieb:
> Ich glaube nämlich nicht, das der Controller damit Configuriert wird:

Ja, du hattest recht, danke. Habe es mit configuration bits probiert und 
siehe da, er bleibt in der while(1){}.

Chris B. schrieb:
> Denn am Simulator laufen die beiden Beispiele - zumindest in Bezug auf
> Abarbeitung der while-Konstruktion!

Wo gibt es denn einen solchen Simulator? Könnte mir echt helfen in 
zukunft, so muss ich es immer aufbauen und ausprobieren. Was an sich ja 
nicht schlimm ist.

Noch eine Idee, wie ich es mit der UART besser hinbekomme?

von Chris B. (dekatz)


Lesenswert?

Der Simulator ist in der IDE (MPLAB bzw. MPLABX) von MICROCHIP 
integriert.
Und der HIGHTECH Compiler wird von MPLAB(X) auch unterstützt.

von Stefan H. (stefan_h68)


Lesenswert?

Hi, ich habe jetzt mal meinen Code angepasst und habe nun folgendes:
1
#include <htc.h>              
2
#include <pic16f688.h>            
3
#ifndef _XTAL_FREQ  
4
#define _XTAL_FREQ 4000000
5
#endif
6
7
/* Transmitter */
8
9
        
10
11
void Init(void)  {
12
  RCSTA  = 0b10010000;
13
  TXSTA  = 0b00100110;  
14
  SPBRG  = 25;      
15
  RCREG  = 0;        
16
  RCIE  = 1;        
17
}
18
19
void PutChar(unsigned char input)  {
20
  while( !TXIF )  {
21
    continue;
22
  }
23
  
24
  if ( RC0 == 1 ) {
25
  TXREG = input;
26
  }
27
  while( !TRMT )  {
28
    continue;
29
  }
30
}
31
32
void main()  {
33
  
34
  ANSEL = 0x00;         
35
  CMCON0 = 0b00000111;                    
36
  PORTA = 0x00;
37
  PORTC = 0x00;
38
    TRISC = 0x00;          
39
  TRISA = 0x00;
40
  RA0 = 1;
41
  _delay( 100000 );            
42
  RA0 = 0;            
43
  _delay( 100000 );
44
45
46
  while (1) {
47
    Init();
48
    PutChar(0xAF);
49
  }
50
}
1
#include <htc.h>            
2
#include <pic16f688.h>            
3
#ifndef _XTAL_FREQ  
4
#define _XTAL_FREQ 4000000
5
#endif
6
7
/* Reciever */
8
9
void Init(void) {  
10
  BRGH = 1;
11
  SPBRG = 25;  
12
  SPEN = 1;
13
  SYNC = 0;
14
  CREN = 1;
15
  SPEN = 1;
16
  RCREG = 0;
17
  RCIE = 1;
18
  RCSTA  = 0b10010000;
19
  TXSTA  = 0b00100110;
20
  OERR = 0;
21
}
22
23
24
void main()  {
25
  ANSEL = 0x00;            
26
  CMCON0 = 0b00000111;          
27
  PORTC = 0x00;
28
  PORTA = 0x00;          
29
    TRISC = 0x00;
30
  TRISA = 0x00;            
31
        
32
  _delay( 1000000 );          
33
  RA0 = 1;          
34
  _delay( 100000 );          
35
  RA0 = 0;            
36
  _delay( 100000 );          
37
  while (1) {
38
    Init();  
39
    while ( RCREG == 0xAF ) {    
40
      RC0 = 1; 
41
    }
42
    RC0 = 0;
43
  }
44
}

Die Übertragung und das Auslesen des RCREG des Recievers funktioniert 
Problemlos, also mein RC0 am Reciever schaltet auf High.
Mein Problem ist nun, dass er nicht mehr auf Low schaltet, sobald der 
Transmitter das Signal nicht mehr sendet.
Meine Überlegung war nun, dass das RCREG nicht Resettet wird, und er 
somit in der while ( RCREG.... feststeckt. Was kann ich da tun? Wenn ich 
innerhalb der while(RCREG... die Init nocheinmal aufrufe, oder CREN = 0; 
schreibe, funktioniert das auch nicht.

An was kann das sonst noch liegen? Oder hab ich irgendetwas falsch 
gemacht?

von Karl H. (kbuchegg)


Lesenswert?

Ich hätte ja gesagt, dass du das Prinzip einer UART überhaupt nicht 
verstanden hast.
So etwas beruht nicht darauf, dass der Empfänger aufs Geratewohl das 
zuletzt empfangene Byte auswertet und der Sender auf 'Dauerfeuer' gehen 
muss.

Sondern der Sender sendet 1(!) Byte, welches der Empfänger empfängt und 
darauf hin etwas macht. Will der Sender etwas anderes veranlassen, dann 
sendet er ein anderes Byte und der Empfänger empfängt es, wertet es aus 
und macht dann was anderes.

So eine UART-Verbdindung ist kein Takttrommler auf einer Gallere, in der 
die Ruderer nur dann rudern, wenn der Trommler trommelt, sondern wie ein 
U-Boot: Der Captain kriegt einen Befehl und den führt er solange aus, 
bis ein neuer Befehl eintrifft oder der Befehl eben 
erledigt/abgearbeitet ist.
Das man darüber dann natürlich noch eine Zeitsteuerung in FOrm eines 
Timeouts legen kann - sprich: wenn der Capatin 5 Tage lang von seinem 
Hauptquartier nichts gehört hat, kehrt er eigenständig in den 
Marinestützpunkt zurück - ist eine andere Geschichte, die so erst mal 
nichts mit der UART an sich zu tun hat, sondern damit wie die UART im 
Programm eingebettet wurde.


Es muss auch im PIC in irgendeinem Register ein Flag geben, welchem du 
entnehmen kannst, ob ein Zeichen auf der UART eingetroffen ist. Das ist 
zuallererst mal das Signal für dein Programm, dass im RCREG ein sinnvoll 
auszuwertendes Byte vorliegt. Und nur dann, wenn dieses Flag aussagt, 
dass ein Byte vorliegt, nur dann macht es überhaupt Sinn auf RCREG 
zuzugreifen und mit dem Byte etwas zu machen. Ob sich durch dieses 
Auslesen das Flag automatisch wieder zurücksetzt oder ob du das händisch 
tun musst, kannst du dem Datenblatt zu deinem Prozessor entnehmen. Aber 
in irgendeiner Form gibt es dieses Flag mit Sicherheit.

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.