Forum: Mikrocontroller und Digitale Elektronik Interupt vom RFM12


von P. F. (pfuhsy)


Lesenswert?

Hallo zusammen,

ich programmiere schon seit einigen Wochen 2 Platinen mit dem RFM12. Ein 
als Sender und ein als Empfänger. Der Sender sendet alle paar ms Daten 
an den Empfänger. Der Empfänger hat folgenden Code womit es auch 
tadellos funktioniert:
1
int main(void) //Hauptprogramm
2
{
3
  initPorts();    //AVR-Ports initialisieren
4
  initUART();      //zu Testzwecken
5
  initInterrupt();  //Interrups initialisieren  
6
  
7
  Power_On();      //Powern On Prozedur  
8
    
9
  RFM_ON();      //RFM einschalten //TODO RFM muss auf Dauer+  
10
  _delay_ms(200);    //Etwas Zeit verbummeln bis das Modul bereit ist  
11
  initRFM_Ports();  //MOSI / MISO Ports initialisieren  
12
  initRFM();      //RFM Grundkonfiguration  
13
  RFM_EMPF_EIN();    //Empfang einschalten
14
15
  while(true) //Hauptschleife
16
  {  
17
    RFM_EMPF_EIN();    //Empfang einschalten
18
    DATEN_EMPFANGEN();  //Daten empfangen
19
    _delay_ms(3000);
20
  }
21
}
22
ISR(INT0_vect)  //Interruptvektor für RFM12
23
{  
24
  TEST_ON();
25
  TEST_OFF();
26
}

..aus Header:
1
//Daten empfangen
2
3
void initRFM()
4
{
5
  //Grundkonfiguration
6
  RFM_CMD_EMPF(0x80D7);//EL,EF,11.5pF
7
  //Frequenzeinstellung
8
  RFM_CMD_EMPF(0xA640);//434MHz
9
  //Bitrate
10
  RFM_CMD_EMPF(0xC647);//4.8kbps
11
  //Empfängersteuerung
12
  RFM_CMD_EMPF(0x94A0);//VDI,FAST,134kHz,0dBm,-103dBm
13
  //Empfangsdatenrekonstruktion
14
  RFM_CMD_EMPF(0xC2AC);//AL,!ml,DIG,DQD4
15
  //Empfangsdatenrekonstruktion
16
  RFM_CMD_EMPF(0xCA81);//FIFO8,SYNC,!ff,DR
17
  RFM_CMD_EMPF(0xC483);//@PWR,NO RSTRIC,!st,!fi,OE,EN
18
  //Senderkonfiguration
19
  RFM_CMD_EMPF(0x9850);//!mp,9810=30kHz,MAX OUT
20
  //Zeitgeber für Wake-Up
21
  RFM_CMD_EMPF(0xE000);//NOT USE
22
  //Automatisch zyklischer Empfänger (Low Duty-Cycle)
23
  RFM_CMD_EMPF(0xC800);//NOT USE
24
  //Automatische Frequenznachregelung
25
  RFM_CMD_EMPF(0xC400);//1.66MHz,2.2V
26
  
27
}
28
29
void DATEN_EMPFANGEN()
30
{
31
  unsigned char i;
32
  unsigned char ChkSum;
33
34
  RFM_CMD_EMPF(0xCA83);  //FIFO einstellen und einschalten
35
  ChkSum=0;
36
37
  //Receive payload data
38
  for(i=0;i<6;i++)
39
  {
40
    ChkSum+=RFM_RECV();
41
    //RFM_RECV();
42
  }
43
44
  //Empfangene Checksumme
45
  i=RFM_RECV();
46
47
  RFM_CMD_EMPF(0xCA81);  //FIFO zurücksetzten und ausschalten
48
49
  //Checksumme prüfen
50
  if(ChkSum==i)
51
  {                
52
    putString("Chk Ok.\n");
53
    LED_ROT_ON();
54
    _delay_ms(10);
55
    LED_ROT_OFF();
56
  }
57
  else
58
  {
59
    putString("Chk NOk.\n");
60
  }
61
62
}
63
//FIFO - Ausleseprozedur
64
unsigned char RFM_RECV(void)
65
{
66
  unsigned int FIFO_data;
67
  
68
  //while(PIND&(1<<RFM_IRQ));  //wartet bis RFM_IRQ auf LOW ist
69
70
  RFM_CMD_EMPF(0x0000);    //Status lesen irqs zurückstellen
71
  FIFO_data=RFM_CMD_EMPF(0xB000);
72
73
  //Daten in globalen Variable abspeichern
74
  if (_laufvar < 6)
75
  {    
76
    _data[_laufvar] = FIFO_data;
77
    _laufvar++;
78
  }
79
  else
80
  {
81
    _data[6] = "\0";
82
    _laufvar = 0;
83
  }  
84
  
85
  return(FIFO_data&0x00FF);
86
}

In der Beschreibung aus Robotik-Hardware 
http://robotikhardware.de/download/RN-MikroFunk_1.7.pdf steht, dass der 
RFM12 einen Interrupt auslöst, sobald das Synchronisationsmuster 
(0x2DD4) erkannt wird. In der Interrupt-Routune lasse ich nur ein Port 
togglen, den ich mit dem Ossi messen kann. So sehe ob der Interrupt 
auslöst. Und das ist der Fall.

Der Code ist aber nicht besonders elegant, da der µC in der Zeile
1
while(PIND&(1<<RFM_IRQ))
solange wartet, bis der RFM_IRQ auf low springt. Deswegen wollte ich mit 
der Interrupt-Routine die Daten erst dann auswerten, sobald das 
Synchronisationsmuster empfangen wird. Doch sobald ich zu Testzwecken 
die Zeile
1
while(PIND&(1<<RFM_IRQ))
auskommentiere, müsste er RFM12 meiner Meinung nach, ständig Interrupts 
auslösen, doch passiert gar nichts. Er löst kein Interrupt aus. Aber 
warum nicht ??? Die rote LED blinkt und zeigt, dass die Checksumme ok 
ist, aber warum kein Interupt ???

Ich halte mich so zielmlich an die Beschreibung, was genaue diese 
Funktion ab S. 65 beschreibt.

Wo ist mein Denkfehler ???

Gruss

von Michael M. (eos400dman)


Lesenswert?

So auf die Schnelle: Wo ist der sei() Aufruf in deinem Code?

Gruß Michael

von P. F. (pfuhsy)


Lesenswert?

Wird damit wahrscheinlich nichts zutun haben aber hier:
1
void initInterrupt()  //Port Interrupt initialisieren
2
{
3
  MCUCR |= (1<<ISC01) | (0<<ISC00);   //fallende Flanke am INT0 Pin als Auslöser
4
  GIMSK |= (1<<INT0);          //externen Interrupt 0 einschalten
5
6
  sei();                //alle Interrups einschalten
7
}

von (prx) A. K. (prx)


Lesenswert?

Peter F. schrieb:
> Der Empfänger hat folgenden Code womit es auch
> tadellos funktioniert:

Das finde ich insoweit interessant, als dem Datasheet gemäss der 
Receiver eigentlich erst eingeschaltet werden müsste. Siehe Power 
Management Command = 0x82xx.

von (prx) A. K. (prx)


Lesenswert?

Peter F. schrieb:
> In der Beschreibung aus Robotik-Hardware [...] steht, dass der
> RFM12 einen Interrupt auslöst, sobald das Synchronisationsmuster
> (0x2DD4) erkannt wird.

Wo genau? Kann ich da auf die Schnelle nicht finden. Im Datasheet stehen 
zwar ein paar Gründe für Interrupts, aber dieser gehört nicht dazu. Da 
die Synchronisation selbst nicht im FIFO auftaucht kommt der Interrupt 
vielmehr erst, nachdem genug Nutzdatenbits empfangen wurden.

: Bearbeitet durch User
von Stefan B. (sibbl) Benutzerseite


Lesenswert?

MCUCR |= (0<<ISC01) | (0<<ISC00);

Hast du's so schonmal probiert?

Ich habe nen Interrupt beim Senden (Wakeup) und einen beim Empfang. Bei 
mir sind ISC01 und ISC00 beide auf 0.

Guckst Du hier: http://bralug.de/wiki/RFM12-Funkbr%C3%BCcke

: Bearbeitet durch User
von P. F. (pfuhsy)


Lesenswert?

A. K. schrieb:
> Das finde ich insoweit interessant, als dem Datasheet gemäss der
> Receiver eigentlich erst eingeschaltet werden müsste. Siehe Power
> Management Command = 0x82xx.

Mach ich doch mit:
1
RFM_EMPF_EIN();    //Empfang einschalten

A. K. schrieb:
> Da
> die Synchronisation selbst nicht im FIFO auftaucht kommt der Interrupt
> vielmehr erst, nachdem genug Nutzdatenbits empfangen wurden.

Ok ich glaube ich vertue mich an der Stelle. Dann löst er halt ein 
Interrupt aus, sobald er Nutzdaten hat. Tut er aber nicht sobald ich die 
besagte Zeile auskommentiere. Die Nutzdaten werden aber trotzdem 
gesendet, warum dann kein Interrupt ? Das einzige was ich im Code ändere 
ist nur die Zeile:
1
while(PIND&(1<<RFM_IRQ))


Stefan B. schrieb:
> MCUCR |= (0<<ISC01) | (0<<ISC00);
>
> Hast du's so schonmal probiert?

Ja. Das macht kein Unterschied. Der nIRQ vom RFM12 steht bei nicht 
auskommentierter Zeile, immer auf High und springt kurz auf Low. Ob ich 
jetzt die Flanke nutze oder den Pegel ändert nichts.

von Stefan B. (sibbl) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hab Dir mal ein Beispiel angehängt.
Empfänger sowie Sender haben einen Atmega328p mit internen 8Mhz. 
Empfänger läuft mit 5v (mit Spannungsteiler für den RFM12B), Sender mit 
3,3V.
Sind 868Mhz-Teile, aber das macht keinen Unterschied. Dieses Prog funzt 
auch bei 433Mhz.
Sender sendet mit Wake-Up-Timer im Abstand von 1.5 mins. Beispiel für 6 
sowie 60 Sekunden auch dabei.

Empfang funzt mit INT0 Interrupt.

Habs Programm kurz reduziert, so dass man leichter durchblickt. Die 
Einrückungen sind mein Stil, ich finds besser so.

Ist von der o.g. Bralug-Seite.

Musst Dir nur die Mühe machen, das Ding mal runter zu laden, entpacken 
und anschauen. Es ist alles darin gut beschrieben.

Hier: http://kanal35.npage.de/funkmodul.html gibts nen echt gut 
gemachten RFM-Calculator.

Gruss und nen guten Rutsch

: Bearbeitet durch User
von P. F. (pfuhsy)


Lesenswert?

Super ich werde mich da mal durchkämpfen, schon mal danke.

Frohes Neues.

von c-hater (Gast)


Lesenswert?

Peter F. schrieb:

> Der nIRQ vom RFM12 steht bei nicht
> auskommentierter Zeile, immer auf High und springt kurz auf Low. Ob ich
> jetzt die Flanke nutze oder den Pegel ändert nichts.

Das ist Unsinn. Bei Interuptsteuerung MUSS ein pegelgetriggerter 
Interrupt verwendet werden, sonst besteht die höchst reale Gefahr von 
Deadlocks durch RFM-seitig aktive, aber vom AVR nicht mehr erkennbare 
Interrupts.

Das ist doch logisch, wenn man bedenkt, daß es mehrere Interruptquellen 
des RFM gibt und die Behandlung der Interrupts mindestens einen (relativ 
länglichen) Lesevorgang des Statusregisters erfordert, bei vielen 
Interrupts aber sogar noch weitere, noch länglichere Operationen. 
Während dieser ganzen Zeiten können weitere Interrupts des RFM 
auftreten, die dann keinen weiteren Pegelwechsel bei nIRQ mehr 
verursachen, weil der vorige Interrupt ja aus RFM-Sicht noch nicht 
behandelt und damit der nIRQ-Ausgang noch aktiv (also Low) war.

Natürlich muß aber auf AVR-Seite die Interruptbehandlung auch korrekt an 
die Levelsteuerung angepaßt sein. Das Schema muß also ungefähr so 
aussehen:

IRQ!
 -deaktiviere Interrupt
 -lies RFM-Statusregister
 -behandle alle im Statuswort erkennbaren aktiven RFM-Interrupts,
  insbesondere auch die, die eine über das Auslesen das Statuswortes
  hinausgehende Behandlung erfordern. Das sind natürlich insbesondere 
die,
  die ein Einlesen oder Ausgeben von Daten erfordern.
 -aktiviere Interrupt wieder

Nun können zwei Fälle auftreten. Entweder sind damit alle "pending" 
Interrupts des RFM korrekt behandelt. Dann ist die Sache hiermit bis zum 
nächsten Interrupt abgeschlossen, weil dann (und NUR dann!) der RFM 
nIRQ auf High gelegt hat.

Oder es sind eben doch zwischenzeitlich weitere Interrupts im RFM 
ausgelöst worden, dann landet man nach der Reaktivierung des Interrupts 
umittelbar wieder bei "IRQ!", weil der nIRQ-Ausgang des RFM12 nach wie 
vor auf Low liegt.

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.