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
voidmain(void)
11
{
12
charbyte;
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
voidmain(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
Auf den ersten Blick ist mir folgendes aufgefallen:
PORTC == 0b00000001;
Mit == wird der Port verglichen und nicht gesetzt. Zum setzen des Ports
= verwenden.
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?
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.
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?
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.
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)
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
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!
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?
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!
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?
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
voidInit(void){
12
RCSTA=0b10010000;
13
TXSTA=0b00100110;
14
SPBRG=25;
15
RCREG=0;
16
RCIE=1;
17
}
18
19
voidPutChar(unsignedcharinput){
20
while(!TXIF){
21
continue;
22
}
23
24
if(RC0==1){
25
TXREG=input;
26
}
27
while(!TRMT){
28
continue;
29
}
30
}
31
32
voidmain(){
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
voidInit(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
voidmain(){
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?
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.