Forum: Mikrocontroller und Digitale Elektronik PIC18 connected to RN42


von Peb (Gast)


Angehängte Dateien:

Lesenswert?

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

von Max H. (hartl192)


Lesenswert?

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

von Peb (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Chris B. (dekatz)


Lesenswert?

"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??

von Peb (Gast)


Lesenswert?

So?

#pragma code IntVectLow=0x18
void IntVectLow (void)
{
_asm GOTO uart_rec _endasm
}
#pragma  code
#pragma interrupt uart_rec

von Max H. (hartl192)


Lesenswert?

> 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).

von Peb (Gast)


Lesenswert?

Max H. schrieb:
> Welcher Compiler?

Ich verwende den C18 compiler.

von Peb (Gast)


Lesenswert?

Max H. schrieb:
> ersetzen und das return RCREG; auch rausschmeißen.

Im Datenblatt steht doch, dass man nach dem RCIF das RCREG lesen soll.

von Max H. (hartl192)


Lesenswert?

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.

von Peb (Gast)


Lesenswert?

#pragma code IntVectLow=0x18
void IntVectLow (void)
{
_asm GOTO uart_rec _endasm
}
#pragma  code
#pragma interrupt uart_rec


void uart_rec()
{
  volatile unsigned char x;

  if(PIR1bits.RCIF&&PIE1bits.RCIE)
    {
      if(RCSTAbits.FERR == 1)
      {
        RCSTAbits.CREN = 0;
        x = RCREG;
        RCSTAbits.CREN = 1;
      }
      if(RCSTAbits.OERR == 1)
      {
        RCSTAbits.CREN = 0;
        x = RCREG;
        RCSTAbits.CREN = 1;
      }
      x = RCREG;
      return x;
    }
  }
Wie mach ich das in der Hauptfunktion --> Endlosscheife??

von Max H. (hartl192)


Lesenswert?

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.

von Peb (Gast)


Lesenswert?

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??

von Peb (Gast)


Lesenswert?

Max H. schrieb:
> Eine ISR hat immer noch keinen return Wert, wohin sollte die auch etwas
> returnen?

Soll ich das return x weg lassen?

von Max H. (hartl192)


Lesenswert?

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

von Peb (Gast)


Lesenswert?

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)

von Max H. (hartl192)


Lesenswert?

Post mal den gesamten aktuellen Code.

von Peb (Gast)


Lesenswert?

1
C-Code#include <p18f14k22.h>
2
#include <usart.h>
3
4
#pragma config FOSC = IRC  
5
#pragma config IESO = OFF, PLLEN = OFF, FCMEN = OFF, PCLKEN = OFF  
6
#pragma config BOREN = SBORDIS, BORV = 19, PWRTEN = OFF, WDTEN = OFF  
7
#pragma config MCLRE = OFF, HFOFST = OFF, DEBUG = OFF, STVREN = ON  
8
#pragma config XINST = OFF, BBSIZ = OFF, LVP = OFF  
9
#pragma config CP0 = OFF, CP1 = OFF  
10
#pragma config CPD = OFF, CPB = OFF  
11
#pragma config WRT0 = OFF, WRT1 = OFF  
12
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF  
13
#pragma config EBTR0 = OFF, EBTR1 = OFF  
14
#pragma config EBTRB = OFF
15
16
void pic_init(void);
17
void uart_rec();
18
19
void main(void)
20
{  
21
  unsigned char data;
22
  pic_init();
23
24
  while(1)
25
  {
26
    
27
    if(data == 'A')
28
    {
29
    LATC = 0x01;
30
    }
31
    else if(data == 'b')
32
    {
33
    LATC = 0x00;
34
    }
35
  }
36
}
37
38
void pic_init(void)
39
{
40
  OSCCON = 0b01110000; //16 Mhz --> Internal OSCI --> 9600 Baud Rate
41
  TRISC = 0x00;  
42
  TRISBbits.TRISB5 = 1; //RB5 (RX --> INPUT)
43
  TRISBbits.TRISB7 = 0; //RB7 (TX --> OUTPUT)
44
  ANSELHbits.ANS11=0; // RB5 IO
45
46
  SPBRG = 103; //9600 Baud Rate for 16 MHz
47
48
    TXSTAbits.TX9 = 0;          // 8-bit transmission
49
  TXSTAbits.TXEN = 1;          // Disabled transmission
50
    TXSTAbits.SYNC = 0;       // Asynchronous mode
51
  TXSTAbits.BRGH = 1;
52
  /***************************/
53
  RCSTAbits.SPEN = 1;          // Enable serial port
54
  RCSTAbits.RX9 = 0;           // 8-bit reception
55
     RCSTAbits.CREN = 1;          // Enable reception
56
  /***************************/ 
57
  BAUDCONbits.BRG16 = 0;      // 8-bit Bau Rate Generator is used
58
  BAUDCONbits.WUE = 1;     // Wake-up Enable bit  
59
  /********************/
60
  RCONbits.IPEN = 1;
61
  IPR1bits.RCIP = 0,
62
  INTCONbits.GIEL = 1;
63
  INTCONbits.GIEH = 1;  
64
}
65
66
#pragma code IntVectLow=0x18
67
void IntVectLow (void)
68
{
69
_asm GOTO uart_rec _endasm
70
}
71
#pragma  code
72
#pragma interrupt uart_rec
73
74
75
void uart_rec()
76
{
77
  volatile unsigned char x;
78
79
  if(PIR1bits.RCIF&&PIE1bits.RCIE)
80
    {
81
      if(RCSTAbits.FERR == 1)
82
      {
83
        RCSTAbits.CREN = 0;
84
        x = RCREG;
85
        RCSTAbits.CREN = 1;
86
      }
87
      if(RCSTAbits.OERR == 1)
88
      {
89
        RCSTAbits.CREN = 0;
90
        x = RCREG;
91
        RCSTAbits.CREN = 1;
92
      }
93
      x = RCREG;    
94
    }
95
  }

von Max H. (hartl192)


Lesenswert?

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.

von Peb (Gast)


Lesenswert?

Ich hab jetzt "volatile unsigned char x;" außerhalb der "Hauptfunktion" 
geschrieben.

von Max H. (hartl192)


Lesenswert?

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

von Peb (Gast)


Lesenswert?

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.

von Peb (Gast)


Lesenswert?

Oder soll ich in der vor der If-Abfrage auf das RCIF warten 
"while(!PIR1bits.RCIF); ?

von Max H. (hartl192)


Lesenswert?

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.

von Der Rächer der Transistomorde (Gast)


Lesenswert?

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?

von Peb (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Max H. (hartl192)


Lesenswert?

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.

von Peb (Gast)


Lesenswert?

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?

von Peb (Gast)


Lesenswert?

Ich finde im Datenblatt nur "USART".

von Peb (Gast)


Lesenswert?

ein*

von Der Rächer der Transistomorde (Gast)


Angehängte Dateien:

Lesenswert?

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-priority

Peb 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.

von Peb (Gast)


Lesenswert?

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?

von Der Rächer der Transistomorde (Gast)


Lesenswert?

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?

von Max H. (hartl192)


Lesenswert?

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

von Peb (Gast)


Lesenswert?

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

von Peb (Gast)


Lesenswert?

Aber ich schaffe es ...*

Vlt muss man den ADC noch zusätzlich mit "ADCON0 = 0b00101100;" 
deaktivieren

von Der Rächer der Transistomorde (Gast)


Lesenswert?

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?

von Peb (Gast)


Lesenswert?

Der Rächer der Transistomorde schrieb:
> und nu gehts?

Nein :(

Wie soll ich in der main... das RCIF abfragen??

if(PIR1bits.RCIF == 1) ??

von Peb (Gast)


Lesenswert?

Seit ich das "Wake-Up-Bit" auf 0 gesetzt hab ... Kann ich die RCIF nicht 
mehr setzen.

von Max H. (hartl192)


Lesenswert?

Peb schrieb:
> Kann ich die RCIF nicht
> mehr setzen.
Das musst du auch nicht setzten, das macht die Hardware für dich sobald 
ein Byte ankommt.

von Peb (Gast)


Lesenswert?

Max H. schrieb:
> Das musst du auch nicht setzten, das macht die Hardware für dich sobald
> ein Byte ankommt.

Macht es aber nicht O.o ...

von PICler (Gast)


Lesenswert?

Peb schrieb:
>> Das musst du auch nicht setzten, das macht die Hardware für dich sobald
>> ein Byte ankommt.

Dann kommt einfach nichts an ;-)

von Peb (Gast)


Lesenswert?

PICler schrieb:
> Dann kommt einfach nichts an ;-)

Laut Oszi kommt was an :O

von Der Rächer der Transistomorde (Gast)


Lesenswert?

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?

von Der Rächer der Transistomorde (Gast)


Lesenswert?

Peb schrieb:
1
> #pragma code IntVectLow=0x18
2
> void IntVectLow (void)
3
> {
4
> _asm GOTO uart_rec _endasm
5
> }
6
> #pragma  code
7
> #pragma interrupt uart_rec
8
> 
9
> void uart_rec()
10
< .....

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?

von Chris B. (dekatz)


Lesenswert?

Der Rächer der Transistomorde schrieb:
> Peb schrieb:
>
1
>> #pragma code IntVectLow=0x18
2
>> void IntVectLow (void)
3
>> {
4
>> _asm GOTO uart_rec _endasm
5
>> }
6
>> #pragma  code
7
>> #pragma interrupt uart_rec
8
>>
9
>> void uart_rec()
10
> < .....
11
> 
12
>
>
> 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".

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.