Hi ! :)
Ich verwende den PIC18f14k22. Dieser ist mit dem Bluetooth-Modul (RN42)
verbunden (RX "RN42" --> TX "µC"). Ich möchte über einen Bluetooth
Terminal per Smartphone z.B.: "A" senden .... dieses soll eine LED
aktivieren. Leider schaff ich es nur die "RCIF-flag" zu setzen ... der
decimal Wert bleibt aber immer 48 (A ist 41). Kann mir jemand helfen das
Problem zu lösen??
mfg Peb
Du könntest das RCIE auf '1' setzten und das Interrupt damit aktivieren.
Die ISR musst du nicht in der main aufgerufen, sie wird automatisch
ausgeführt wenn das entsprechende Ereignis auftritt.
Um Daten vom BT-Modul an den uC zu senden musst du Tx des BT-Molduls mit
Rx des uCs verbinden.
Tx: Transmit
Rx: Receive
Peb schrieb:> (RX "RN42" --> TX "µC")
Hier hab ich mich verschrieben .. :/
Max H. schrieb:> Du könntest das RCIE auf '1'
Sobald ich RCIE auf "1" setz... kann die RCIF flag nicht mehr gesetzt
werden
Ich hab das Programm überarbeitet .. es bleibt dieses mal im RCREG
hängen.
"RCONbits.IPEN = 1;
IPR1bits.RCIP = 0,
PIE1bits.RCIE = 1;
INTCONbits.GIEL = 1;
INTCONbits.GIEH = 1;
"
Interrupts sind enabled, aber wo ist die Interruptroutine dafür??
> PIE1bits.RCIE
Welcher Compiler?
Du müsst dich aber entscheiden, ob du die Funktion uart_rec(void) in der
main oder als ISR aufrufen willst und wenn Zweiteres das
while(!PIR1bits.RCIF); rausschmeißen und durch eine
1
if(PIR1bits.RCIF&&PIE1bits.RCIE)
2
{
3
...
4
}
ersetzen und das return RCREG; auch rausschmeißen.
Peb schrieb:> Sobald ich RCIE auf "1" setz... kann die RCIF flag nicht mehr gesetzt> werden
Das muss auch nicht gesetzt werden, das mach die Hardware automatisch
wenn ein Zeichen ankommt (und sie richtig konfiguriert ist).
Peb schrieb:> Max H. schrieb:>> Welcher Compiler?>> Ich verwende den C18 compiler.
Dann müsste das mit dem Interrupt so passen.
Peb schrieb:> Im Datenblatt steht doch, dass man nach dem RCIF das RCREG lesen soll.
Eine ISR hat aber keinen return Wert, wohim sollte die auch etwas
returnen? Nimm dafür eine globale volatile Variable.
Peb schrieb:> return x;
Eine ISR hat immer noch keinen return Wert, wohin sollte die auch etwas
returnen?
Peb schrieb:> Wie mach ich das in der Hauptfunktion --> Endlosscheife??
Wenn du sonst nichts zu tun hast, dann ja. Dann könnte man auf das
Interrupt aber auch komplett verzichten und in der main pollen.
Ich möchte dann das gesendete "A" in der Endlosschleife
"verarbeiten".... also:
if(data == 'A')
{
LATC=0x01; //Led ein
}
Aber ich muss doch irgendwas vor "if" schreiben oder??
Peb schrieb:> void uart_rec()> {> volatile unsigned char x;
x ist so eine lokale variable.
Peb schrieb:> Ich möchte dann das gesendete "A" in der Endlosschleife> "verarbeiten"....> Aber ich muss doch irgendwas vor "if" schreiben oder??
Ich würde es in eine while(1) setzen:
1
while(1)
2
{
3
if(data=='A')
4
{
5
LATC=0x01;//Led ein
6
}
7
}
Peb schrieb:> Soll ich das return x weg lassen?
genau
Das funktioniert so nicht :/
Mittels der Watch-Funktion in MPLAB sehe ich, dass der Decimal Wert "48"
ist... Laut ASCII-Tabelle ist "A" --> 41
Ebenso bleib ich in der Endlosschleife hängen (Interrupt wird nicht
ausgelöst)
Das löst das Problem mit dem nicht ausgelösten Interrupt zwar nicht,
aber data und x sind beides lokale Variablen die nix voneinander wissen.
data hat also keine Chance irgendwie an den Inhalt von RCREG zu kommen.
Peb schrieb:> Ich hab jetzt "volatile unsigned char x;" außerhalb der "Hauptfunktion"> geschrieben.
Und hoffentlich das x auch in die if-Abfrage.
Peb schrieb:> BAUDCONbits.WUE = 1; // Wake-up Enable bit
Zitat Datenblatt:
> WUE: Wake-up Enable bit> Asynchronous mode:> 1 = Receiver is waiting for a falling edge. No character will be> received but RCIF will be set on the falling edge. WUE will> automatically clear on the rising edge.> 0 = Receiver is operating normally
Max H. schrieb:> Und hoffentlich das x auch in die if-Abfrage.
ja hab ich.
Max H. schrieb:> Zitat Datenblatt:>> WUE: Wake-up Enable bit>> Asynchronous mode:>> 1 = Receiver is waiting for a falling edge. No character will be>> received but RCIF will be set on the falling edge. WUE will>> automatically clear on the rising edge.>> 0 = Receiver is operating normally
Ich hab das Bit auf 0 gesetzt.
Peb schrieb:> Oder soll ich in der vor der If-Abfrage auf das RCIF warten> "while(!PIR1bits.RCIF); ?
Das wird eine Endlosschleife, sobald das bit 1 wird springt der µC in
die ISR und dort wird es wieder gelöscht, es ist also immer aus 0
während das while ausgeführt wird.
Hast du mal überprüft ob die Siganle auch beim Rx-Pin ankommen.
Das wären mir viel zu viele Baustellen auf einmal:
Mach es doch erst mal ohne Interrupt in der main schleife
Dann kannst du besser eingrenzen wo der Fehler her kommt.
Aber auch da alles Schritt für Schritt
Also prüfen:
1. ob ein Zeichen empfangen wurde
2. ob das richtige empfangen wurde
3. ob das nächste auch empfangen wird
Anschließend ob das ganze auch mit dem Interrupt funzt
Deinen Compiler kenne ich nicht aber
der PIC18 hat in der Regel mehrerer U(S)ARTS
Woher weiß der Compiler welcher gemeint ist?
So auf die schnelle sehe ich auch nicht wo der Peripherial Interrupt
Enabled (PEIE) wird?
Max H. schrieb:> Hast du mal überprüft ob die Siganle auch beim Rx-Pin ankommen.
Ich hab mich mit einem Oszi + Tastkopf auf RX gehängt und hab das Signal
gesehen.
Der Rächer der Transistomorde schrieb:> der PIC18 hat in der Regel mehrerer U(S)ARTS
Dieser nicht.
> So auf die schnelle sehe ich auch nicht wo der Peripherial Interrupt> Enabled (PEIE) wird?
Das ist wenn man priorisierte Interrupts aktiviert hat nicht nötig.
Der Rächer der Transistomorde schrieb:> So auf die schnelle sehe ich auch nicht wo der Peripherial Interrupt> Enabled (PEIE) wird?
PEIE ist laut Datenblatt das gleiche wie, GIEL.
"PEIE/GIEL: Periperial Interrupt
When IPEN = 0:
1 = Enables all unmasked peripheral interrupts
0 = Disable all peripheral interrupts
When IPEN = 1;
1= Enables all low priority interrupts
0 = Disables all low priority interrupts"
Der Rächer der Transistomorde schrieb:> der PIC18 hat in der Regel mehrerer U(S)ARTS
Wie meinst du das?
Max H. schrieb:> Das ist wenn man priorisierte Interrupts aktiviert hat nicht nötig.
Beim Pic 18 hast ist das Interruptmodel einfach in Low und high
gespiegelt. Da musst du PEIE setzen egal auf welchen du deinen Interrupt
routest.
Das Bild hab ich von
http://www.foxytronics.com/learn/microcontrollers/pic18/pic18-interrupts/interrupt-priorityPeb schrieb:> Ich finde im Datenblatt nur "USART".
Dann hat er auch nur einen
> PEIE ist laut Datenblatt das gleiche wie, GIEL.
Dann ist das auch ok,
Aber ohne Interrupt kannst du den Fehler einfacher eingrenzen.
Der Rächer der Transistomorde schrieb:> Beim Pic 18 hast ist das Interruptmodel einfach in Low und high> gespiegelt. Da musst du PEIE setzen egal auf welchen du deinen Interrupt> routest.
Ich hab "INTCONbits.PEIE = 1;" hinzugefügt.
Wie lös ich den Fehler mit der Hauptfunktion, das diese nicht den
Interrupt auslöst bzw. die Daten vom RCREG ausliest?
Peb schrieb:> Ich hab mich mit einem Oszi + Tastkopf auf RX gehängt und hab das Signal> gesehen.
Hast du eigentlich geprüft welche Funktionen noch auf dem Port liegen?
Würde ich bei Pics immer machen weil einige Funktionen vorrang haben
Z.b. AD Eingänge bei RX liegt laut Datenblatt ADC11 mit drauf.
Ist der deaktiviert?
Peb schrieb:> Wie lös ich den Fehler mit der Hauptfunktion, das diese nicht den> Interrupt auslöst bzw. die Daten vom RCREG ausliest?
Welchen Fehler? Das ist eigentlich normal, dass das Interrupt von der
Hardware ausgelöst wird und das RCREG in der ISR ausgelesen wird (wenn
man mit Interrupts arbeitet).
Der Rächer der Transistomorde schrieb:> AD Eingänge bei RX liegt laut Datenblatt ADC11 mit drauf.>> Ist der deaktiviert?Peb schrieb:> ANSELHbits.ANS11=0; // RB5 IO
Max H. schrieb:> Welchen Fehler? Das ist eigentlich normal, dass das Interrupt von der> Hardware ausgelöst wird und das RCREG in der ISR ausgelesen wird (wenn> man mit Interrupts arbeitet).
Ja aber ich kann ich schaffe es ja nicht den Interrupt auszulösen
Der Rächer der Transistomorde schrieb:> Ist der deaktiviert?
ADCON0 = 0b00101100; // Der ADC sollte jetzt deaktiviert sein
Peb schrieb:> Wie lös ich den Fehler mit der Hauptfunktion, das diese nicht den> Interrupt auslöst bzw. die Daten vom RCREG ausliest?
Du fragst einfach das receiver interrupt flag ab.
Wenn gesetzt machst du irgendwas z.B. n Port toggeln und löscht es
danach wieder.
Dann siehst du auf deinem Oszi gleich ob das ganze ankommt.
Von der PIC Philosophie her wird der Interrupt nicht von der
Hauptroutine ausgelöst sondern es ist ein Software Interrupt den der
Receiver setzt.
Dann wird der aktuelle Maschinenbefehl abgearbeitet, der Programmzähler
und n paar Register gerettet und einfach an der Interrupt Adress weiter
gemacht.
Mehr ist das gar nicht alles andere musst du selbst machen.
Beim RTI ist es einfach umgedreht.
Peb schrieb:> ADCON0 = 0b00101100; // Der ADC sollte jetzt deaktiviert sein
und nu gehts?
Peb schrieb:> Laut Oszi kommt was an :O
Dann liegt der Fehler dazwischen (den eigenen Ohren) ;-)
Macht das nochmal komplett neu und RTFM!
Da steht dann z.B.:
15.1.2.9 Asynchronous Reception Set-up:
1. Initialize the SPBRGH:SPBRG register pair and
the BRGH and BRG16 bits to achieve the
desired baud rate (see Section 15.3 “EUSART
Baud Rate Generator (BRG)”).
2. Enable the serial port by setting the SPEN bit
and the RX/DT pin TRIS bit. The SYNC bit must
be clear for asynchronous operation.
3. If interrupts are desired, set the RCIE interrupt
enable bit and set the GIE and PEIE bits of the
INTCON register.
4. If 9-bit reception is desired, set the RX9 bit.
5. Set the DTRXP if inverted receive polarity is
desired.
6. Enable reception by setting the CREN bit.
7. The RCIF interrupt flag bit will be set when a
character is transferred from the RSR to the
receive buffer. An interrupt will be generated if
the RCIE interrupt enable bit was also set.
8. Read the RCSTA register to get the error flags
and, if 9-bit data reception is enabled, the ninth
data bit.
9. Get the received 8 Least Significant data bits
from the receive buffer by reading the RCREG
register.
10. If an overrun occurred, clear the OERR flag by
clearing the CREN receiver enable bit.
Hast du das alles gemacht?
Sag mal wie funzt das eigentlich beim C18
Wenn du dem wie oben in der Interrupt routine ezählst er soll auf den
Anfang einer von dir erstellten hüpfen, woher weiß er dann wann er aus
dem Interrupt zurück soll?
>> Sag mal wie funzt das eigentlich beim C18>> Wenn du dem wie oben in der Interrupt routine ezählst er soll auf den> Anfang einer von dir erstellten hüpfen, woher weiß er dann wann er aus> dem Interrupt zurück soll?
Durch "#pragma interrupt uart_rec" weiss der Compiler das es sich bei
der Funktion "uart_rec" um eine Interruptroutine handelt und fügt am
Ende automatisch ein RETFIE 0 oder RETFIE 1 ein.
Daher funkteoniert auch ein "return()" u.ä. nicht weil damit der
Interrupt nicht wieder freigeschaltet wird und auch diverse, automatisch
beim Interrupeintritt gesicherte Register, nicht wiederhergestellt
werden (zum. wenn mit Shadow-Register gearbeitet wurde.....).
btw. vielleicht verwirft der Compiler ein "return" in einer ISR
automatisch!?!?...ist schon länger her das ich den C18 verwendet habe da
ohnehin nicht mehr "supported".