Forum: Mikrocontroller und Digitale Elektronik RFM12B Modul - Senden/Empfangen funktioniert nicht


von Florian S. (kingeldarion)


Angehängte Dateien:

Lesenswert?

Guten Tag,

Ich bin aktuell an einem Punkt wo ich nicht weiterkomme und hoffe ihr 
könnt mir helfen.

Folgende Ausgangssituation: Ich möchte in Zukunft ein paar Projekte 
umsetzen in denen ich Daten über Funk senden möchte. Daher habe ich mich 
in den letzten Wochen damit auseinandergesetzt und habe mir vor ca einem 
Monat RFM12B Module gekauft 
(https://www.amazon.de/gp/product/B00BTCUMP6/ref=ppx_yo_dt_b_asin_title_o09_s00?ie=UTF8&psc=1). 
Genau genommen die 868 Mhz Version.
Dazu folgende Antenne, da die Module keine eigene haben, wenn ich das 
richtig festgestellt habe?! Vielleicht könnte mich jemand bei diesem 
Punkt noch bestätigen oder widerlegen? 
(https://www.amazon.de/gp/product/B07DLR2BN2/ref=ppx_yo_dt_b_asin_title_o02_s03?ie=UTF8&psc=1)

Als Mikrocontroller dient mir momentan ein Elegoo Uno R3 und ich 
programmiere zum testen aktuell mittels Arduino IDE.

Jetzt bin ich seit ca 2,5 Wochen daran die Module dazu zu bringen Daten 
zu übertragen. Ich habe beide aktuell an den selben Mikrocontroller 
angeschlossen und nutze keine Hardware SPI.

Angeschlossen habe ich sie wie hier 
(https://lowpowerlab.com/2012/12/28/rfm12b-arduino-library/) im zweiten 
Schema zu sehen, also die Version mit den 4.7k Widerständen. In meinem 
Fall benutze ich jedoch 5.1k da ich nichts näheres hier hatte. Die 10k 
Widerstände sind bei mir auch 10k.

Generell habe ich versucht so viele Beispiele zu finden wie ich konnte 
und habe mich bisher auch glaube ich ganz gut daran heranarbeiten 
können.
Jetzt bin ich jedoch seit einigen Tagen an einem Punkt angekommen an dem 
ich keine Fortschritte mehr mache.

Nach dem was ich als Feedback (IRQ und SDO) bekomme, denke ich auch dass 
ich soweit fast alles richtig gemacht habe.
Der Sender scheint im Sendemodus zu sein. IRQ geht auf low sobald ich 
die Nachricht geschickt habe auf senden zu schalten und bleibt dort.
Der Receiver hat IRQ durchgehend auf HIGH.

Nun versuche ich mittels 0xB8 Befehl Daten zu senden. Mit einigen 0xAA 
zu Beginn oder ohne. Dann das Synchronisationsbyte 0xD4, auch mit einem 
0x2D davor, wie ich es ab und zu gesehen habe, dann ein paar zufällige 
Bytes als Nachricht und dann mit oder ohne ein Dummy Byte 0x00.

Zum einen geht während dessen der IRQ vom sender niemals auf HIGH. Nach 
meiner Recherche sollte er auf HIGH gehen während er sendet und wieder 
auf LOW sobald er bereit ist neue Daten zu senden, richtig?

Der Receiver ist ebenfalls unberührt von der ganzen Sache. IRQ bleibt 
bei ihm HIGH und wenn ich einfach versuche Datena us dem FIFO zu lesen, 
kommt dann halt auch nur immer 0 bei rum.


Die Status words der beiden bringen mich auch nicht weiter. Hier meine 
Referenz 
(https://www.mikrocontroller.net/articles/RFM12#Status_lesen_.28Status_Read_0000.29).
Der Sender hat das Flag 15 RGIT gesetzt, sowie 13 RGUR. Was ja im 
Endeffekt bedeutet dass ich Daten nachschieben kann bzw. soll.
Zudem ist Flag 8 ATS gesetzt. Hier werde ich nicht schlau raus?! Klingt 
für mich aber eher positiv?

Beim Receiver siehts folgendermaßen aus:
Bit 9 FFEM, bedeutet FIFO Empty, also keine empfangen Daten?!
Bit 8 RSSI, beduetet die Signalstärke ist über dem eingstellten Limit.
Klingt ja grundsätzlich nicht so toll. Ich habe versucht bei der 
Initialisierung des Empfängers mit dem Code 9xxx zu spielen. Und mal auf 
0x90 85 gestellt. Hat aber nichts genützt. Generell kann ich hierzu auch 
leider keine weiteren Infos finden.
Bit 7 DQD, bedeutet data quality detector. Keine Ahnung ob das gut oder 
schlecht ist?
Bit 6 CRL, bedeutet clock recovery locked. Auch hier keine Ahnung ob das 
gut oder schlecht ist!?


Generell sollte noch gesagt sein: Ich bin leider kein Elektrotechniker 
oder ähnliches. Mein Wissen ist eine Mischung aus Physik in der 
Mittelstufe und Hobbymäßig mit Mikrocontrollern basteln. Also bitte 
lyncht mich nicht wenn ich möglicherweise ziemlich simple Dinge nicht 
verstehe oder übersehe.
Ich bin aber gerne bereit neues zu lernen, darum mach ich das ja!
Also falls möglich bitte immer lieber die Variante für Dummies ;)

Hier mein Code:
1
const int PIN_OUT_SS = 12;
2
const int PIN_OUT_MOSI = 10;
3
const int PIN_OUT_MISO = 9;
4
const int PIN_OUT_SCK = 11;
5
const int PIN_OUT_IRQ = 8;
6
7
const int PIN_IN_SS = 2;
8
const int PIN_IN_MOSI = 4;
9
const int PIN_IN_MISO = 5;
10
const int PIN_IN_SCK = 3;
11
const int PIN_IN_IRQ = 6;
12
13
int abc = 0;
14
15
void irqchange(){
16
17
  abc ++;
18
}
19
20
void setup() {
21
  // put your setup code here, to run once:
22
  Serial.begin(9600);
23
  
24
  if(digitalRead(PIN_OUT_IRQ) == 1){
25
26
    Serial.write("OUTIRQ\n");
27
  }
28
29
  if(digitalRead(PIN_IN_IRQ) == 1) {
30
31
    Serial.write("INIRQ\n");
32
  }
33
  
34
  pinMode(PIN_OUT_SS, OUTPUT);
35
  pinMode(PIN_OUT_MOSI, OUTPUT);
36
  pinMode(PIN_OUT_MISO, INPUT);
37
  pinMode(PIN_OUT_SCK, OUTPUT);
38
  pinMode(PIN_OUT_IRQ, INPUT);
39
40
  pinMode(PIN_IN_SS, OUTPUT);
41
  pinMode(PIN_IN_MOSI, OUTPUT);
42
  pinMode(PIN_IN_MISO, INPUT);
43
  pinMode(PIN_IN_SCK, OUTPUT);
44
  pinMode(PIN_IN_IRQ, INPUT);
45
  
46
  //attachInterrupt(digitalPinToInterrupt(PIN_OUT_IRQ), irqchange, CHANGE);
47
  //attachInterrupt(digitalPinToInterrupt(PIN_IN_IRQ), irqchange, CHANGE);
48
  
49
  digitalWrite(PIN_OUT_SS, HIGH);
50
  digitalWrite(PIN_IN_SS, HIGH);
51
52
  delay(5000);
53
54
  SendByte(0, 0x00, 0x00);
55
  SendByte(1, 0x00, 0x00);
56
  
57
  Serial.write("Begin Init\n");
58
59
  //Initialization
60
  //Sender
61
  SendByte(0, 0x80, 0xE8); //Set 868Mhz
62
  SendByte(0, 0xA6, 0x40); //Use the standart 868 Mhz Band
63
  SendByte(0, 0xC6, 0x23); //Bitrate
64
  SendByte(0, 0x90, 0x80); //?
65
  SendByte(0, 0xC2, 0x2C); //Empfangsdatenrekonstruktion
66
  SendByte(0, 0xCA, 0x81); //FIFO Empfängersteuerung -> Fifo leeren und sperren
67
  SendByte(0, 0xCA, 0xF3); //FIFO freigeben | evtl F3 oder 83?
68
  SendByte(0, 0xCE, 0xD4); //Wert der als Synchronisations-Byte verwendet werden soll. (Frei nach Schnauze einstellbar?)
69
  SendByte(0, 0xC4, 0x00); //AFC => Ist wohl unbrauchbar, daher abschalten
70
  SendByte(0, 0x98, 0x00); //Senderkonfiguration -> Möglicherweise 0x50 testen (Library)
71
  SendByte(0, 0xCC, 0x77); //Taktgenerator einstellungen
72
  SendByte(0, 0xE0, 0x00); //Disable Wakeup stuff
73
  SendByte(0, 0xC8, 0x00); //Wakeup stuff -> disbaled
74
  SendByte(0, 0xC0, 0x00); //Unterspannungsdetektor und Taktungsteiler?
75
76
  SendByte(0, 0x82, 0x28); //Enable Sender
77
  delayMicroseconds(4);
78
  SendByte(0, 0x82, 0x38);
79
80
  Serial.write("Initialized Sender\n");
81
  Serial.write("Initializing Receiver\n");
82
83
  //Receiver
84
  SendByte(1, 0x80, 0xE8); //Set 868Mhz
85
  SendByte(1, 0xA6, 0x40); //Use the standart 868 Mhz Band
86
  SendByte(1, 0xC6, 0x23); //Bitrate
87
  SendByte(1, 0x90, 0x80); //?
88
  SendByte(1, 0xC2, 0x2C); //Empfangsdatenrekonstruktion
89
  SendByte(1, 0xCA, 0x81); //FIFO Empfängersteuerung -> Fifo leeren und sperren
90
  SendByte(1, 0xCA, 0xF3); //FIFO freigeben | evtl F3 oder 83?
91
  SendByte(1, 0xCE, 0xD4); //Wert der als Synchronisations-Byte verwendet werden soll. (Frei nach Schnauze einstellbar?)
92
  SendByte(1, 0xC4, 0x00); //AFC => Ist wohl unbrauchbar, daher abschalten
93
  SendByte(1, 0x98, 0x00); //Senderkonfiguration -> Möglicherweise 0x50 testen (Library)
94
  SendByte(1, 0xCC, 0x77); //Taktgenerator einstellungen
95
  SendByte(1, 0xE0, 0x00); //Disable Wakeup stuff
96
  SendByte(1, 0xC8, 0x00); //Wakeup stuff -> disbaled
97
  SendByte(1, 0xC0, 0x00); //Unterspannungsdetektor und Taktungsteiler?
98
99
  //SendByte(1, 0x82, 0x3D); //Enable Sender
100
  SendByte(1, 0x82, 0xDD); //Enable Receiver
101
102
  Serial.write("Finished Init\n");
103
}
104
105
void loop() {
106
  // put your main code here, to run repeatedly:
107
108
  Serial.write("\n\n\n");
109
  
110
  //Serial.print("Interrupts: ");
111
  //Serial.print(abc);
112
  //Serial.write("\n");
113
  
114
  if(digitalRead(PIN_OUT_IRQ) == 1){
115
116
    Serial.write("OUTIRQ\n");
117
  }
118
  
119
  if(digitalRead(PIN_IN_IRQ) == 1) {
120
121
    Serial.write("INIRQ\n");
122
  }
123
  
124
  Serial.write("Status Sender: ");
125
  SendByte(0, 0x00, 0x00);
126
  SendByte(0, 0x00, 0x00);
127
  SendByte(0, 0x00, 0x00);
128
  
129
  Serial.write("Sending: ");
130
  SendByte(0, 0xB8, 0xAA);
131
  SendByte(0, 0xB8, 0xAA);
132
  SendByte(0, 0xB8, 0xAA);
133
  SendByte(0, 0xB8, 0xAA);
134
  SendByte(0, 0xB8, 0x2D);
135
  SendByte(0, 0xB8, 0xD4);
136
  SendByte(0, 0xB8, 0xAA);
137
  SendByte(0, 0xB8, 0xAA);
138
  SendByte(0, 0xB8, 0xAA);
139
  SendByte(0, 0xB8, 0xAA);
140
  SendByte(0, 0xB8, 0x00);
141
  
142
  delay(1);
143
  /*
144
  Serial.write("Receiving: ");
145
  SendByte(1, 0xB0, 0x00);
146
147
  Serial.write("Status Receiver: ");
148
  SendByte(1, 0x00, 0x00);
149
  SendByte(1, 0x00, 0x00);
150
  SendByte(1, 0x00, 0x00);*/
151
}
152
153
unsigned short SendByte(int _id, byte _cmd, byte _val) {
154
155
  int PIN_SS;
156
  int PIN_MOSI;
157
  int PIN_SCK;
158
  int PIN_MISO;
159
  int PIN_IRQ;
160
161
  if (_id == 0) {
162
163
    PIN_SS = PIN_OUT_SS;
164
    PIN_MOSI = PIN_OUT_MOSI;
165
    PIN_SCK = PIN_OUT_SCK;
166
    PIN_MISO = PIN_OUT_MISO;
167
    PIN_IRQ = PIN_OUT_IRQ;
168
  }
169
  else {
170
171
    PIN_SS = PIN_IN_SS;
172
    PIN_MOSI = PIN_IN_MOSI;
173
    PIN_SCK = PIN_IN_SCK;
174
    PIN_MISO = PIN_IN_MISO;
175
    PIN_IRQ = PIN_IN_IRQ;
176
  }
177
  
178
  digitalWrite(PIN_SCK, LOW);
179
  
180
  unsigned short read = 0;
181
  unsigned short value = _cmd;
182
  value = (value << 8) | _val;
183
184
  //delay a bit, just to be sure
185
  delayMicroseconds(10);
186
187
  //Start a command
188
  digitalWrite(PIN_SS, LOW);
189
  delayMicroseconds(1);
190
  for (int i = 0; i < 16; i ++) {
191
192
    //Write the bit
193
    digitalWrite(PIN_MOSI, (value >> 15 - i) & 0x0001);
194
195
    delayMicroseconds(10);
196
    
197
    //Clock high -> Read!
198
    digitalWrite(PIN_SCK, HIGH);
199
200
    read = (read << 1) | digitalRead(PIN_MISO);
201
202
    delayMicroseconds(10);
203
204
    //Clock low -> Write next bit or end (SS low)
205
    digitalWrite(PIN_SCK, LOW);
206
  }
207
  delayMicroseconds(1);
208
  digitalWrite(PIN_SS, HIGH);
209
  delayMicroseconds(10);
210
211
  Serial.write("Read: ");
212
  Serial.print(read);
213
  Serial.write("\n");
214
215
  return read;
216
}

Folgenden Output kann ich im Serial beobachten:

Setup Funktion:
1
INIRQ
2
OUTIRQ (Nur wenn nicht von vorheriger Session initialisiert)
3
Read: 41216
4
Read: 832
5
Begin Init
6
Read: 65535
7
Read: 65535
8
Read: 65535
9
Read: 65535
10
Read: 65535
11
Read: 65535
12
Read: 65535
13
Read: 65535
14
Read: 65535
15
Read: 65535
16
Read: 65535
17
Read: 65535
18
Read: 65535
19
Read: 65535
20
Read: 65535
21
Read: 65535
22
Initialized Sender
23
Initializing Receiver
24
Read: 0
25
Read: 0
26
Read: 0
27
Read: 0
28
Read: 0
29
Read: 0
30
Read: 0
31
Read: 0
32
Read: 0
33
Read: 0
34
Read: 0
35
Read: 0
36
Read: 0
37
Read: 0
38
Read: 0
39
Finished Init


Bei allen loops kommt folgender output:
1
INIRQ
2
Status Sender: Read: 41216
3
Read: 41216
4
Read: 41216
5
Sending: Read: 65534
6
Read: 65534
7
Read: 65534
8
Read: 65534
9
Read: 65534
10
Read: 65534
11
Read: 65534
12
Read: 65534
13
Read: 65534
14
Read: 65534
15
Read: 65534
16
Receiving: Read: 0
17
Status Receiver: Read: 960
18
Read: 960
19
Read: 960


Ich hoffe ich habe keine Information ausgelassen. Falls doch, versuche 
ich schnellstmöglich nachzuliefern.

Mit freundlichen Grüßen
Florian

: Verschoben durch Moderator
von Florian S. (kingeldarion)


Lesenswert?

Niemand der mir helfen kann?

von Stephan (Gast)


Lesenswert?

falsches Unterforum.

von John B. (Gast)


Lesenswert?

Versuchs doch mal mit Jeelib

https://jeelabs.net/projects/jeelib/wiki

von c-hater (Gast)


Lesenswert?

Florian S. schrieb:

> Dazu folgende Antenne, da die Module keine eigene haben, wenn ich das
> richtig festgestellt habe?! Vielleicht könnte mich jemand bei diesem
> Punkt noch bestätigen oder widerlegen?

Kann ich einerseits bestätigen (die Module haben keine eigene Antenne), 
andererseits: man braucht auch echt keine kaufen. Ein paar Zentimeter 
stinknormaler Schaltdraht sind Antenne genug. Damit kann man Reichweiten 
von 100m und mehr erzielen...

> Als Mikrocontroller dient mir momentan ein Elegoo Uno R3 und ich
> programmiere zum testen aktuell mittels Arduino IDE.

Das ist der primäre Fehler.

> Jetzt bin ich seit ca 2,5 Wochen daran die Module dazu zu bringen Daten
> zu übertragen.

Du hättest die Zeit besser genutzt, indem du erstmal eine zuverlässige 
Kommunikation zwischen µC und RFM etabliert hättest.

> Nach dem was ich als Feedback (IRQ und SDO) bekomme, denke ich auch dass
> ich soweit fast alles richtig gemacht habe.

Nö, mit an Sicherheit grenzender Wahrscheinlichkeit nicht.

> Zum einen geht während dessen der IRQ vom sender niemals auf HIGH.

OMG. Einmal, wirklich nur einmal: DB lesen hätte dir diese Peinlichkeit 
von Aussage erspart...

Um dir das mal in einfachen Worten klarzumachen: der IRQ der RFM ist 
erstens Low-aktiv und zweitens ein "Level-IRQ". D.h.: dein RFM ist 
dauerhaft unzufrieden mit seiner Ansteuerung. Du hast auf irgendeine 
IRQ-Anforderung (der RFM hat MEHRERE, aber nur einen IRQ-Ausgang) 
nicht korrekt reagiert. Deswegen geht der Pegel niemals wieder auf High 
(also in den INAKTIVEN Zustand). Und deswegen kannst du auf weitere 
Änderungen seines Zustands garnicht mehr reagieren, weil er schon nicht 
mehr in der Lage ist, sie dir überhaupt zu signalisieren, denn sein 
Interrupt-Ausgang ist ja schon lange LOW also AKTIV, bloß du 
Dumpfbacke hast das bisher nicht korrekt behandelt...

Fazit: Typischer Arduidiot, der niemals ein Datenblatt auch nur zum 
Arschabwischen benutzt, geschweige denn, dass er es lesen würde...

von Michael U. (amiga)


Lesenswert?

Hallo,

c-hater schrieb:
> azit: Typischer Arduidiot, der niemals ein Datenblatt auch nur zum
> Arschabwischen benutzt, geschweige denn, dass er es lesen würde...

ein typischer Trottel, der unbedingt schlau sein will und sich mal 
wieder nicht benehmen kann oder was???

Man kann den RFM12 problemlos komplett ohne Interrupt per Polling 
bedienen.
Bitbanging ist für die Ansteuerung auch durchaus sinnvoll, ich weiß zwar 
nicht, ob die aktuellen RFM12B sich besser benehmen, die alten 
RFM01/02/12 machten damals mit Hardware-SPI gern seltsame Probleme.

Ich habe aus alten Zeiten nur noch eine Empangsroutine rumliegen, die 
ich mal in die ArduinoIDE getragen hatte:
Die RFM12.c
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/pgmspace.h>
4
#include "global.h"
5
#include "RFM12.h"
6
7
void RFM12_send_cmd(unsigned int command)
8
  {
9
  unsigned char i;
10
  RFM12_PORT &= ~(1<<RFM12_CS);        // CS auf L
11
12
  for (i=0; i<16; i++)
13
    {
14
      if (command & 0x8000)
15
        {
16
          RFM12_PORT |= (1<<RFM12_SDI);    // DATA auf H
17
        }
18
      else
19
        {
20
          RFM12_PORT &= ~(1<<RFM12_SDI);    // DATA auf L
21
        }
22
      asm("nop");
23
        RFM12_PORT |= (1<<RFM12_SCK);      // CLK auf H
24
      asm("nop");
25
      asm("nop");
26
        RFM12_PORT &= ~(1<<RFM12_SCK);      // CLK auf L
27
      command = (command << 1);        // nächstes Bit nach oben
28
    }
29
  RFM12_PORT |= (1<<RFM12_CS);          // CS auf H
30
  }
31
32
void RFM12_init(void)
33
  {
34
    RFM12_PORT = (1<<RFM12_CS);          // PullUp ein / Ausgang H  
35
    RFM12_DDR  = (1<<RFM12_SDI) | (1<<RFM12_SCK) | (1<<RFM12_CS);  // Ausgänge
36
37
    RFM12_send_cmd(0x0000);            // Status read
38
39
    RFM12_send_cmd(0xC080);            // CLK-Frequenz / Batterie-Level
40
41
    RFM12_send_cmd(0x80D7);            // FIFO ein, C = 11,5pF
42
43
    RFM12_send_cmd(0xC2AB);            // Thresold, Filter
44
45
    RFM12_send_cmd(0xCA81);            // FIFO-Level, 
46
47
    RFM12_send_cmd(0xE000);            // WakeUp aus 
48
49
    RFM12_send_cmd(0xC800);            // Low Duty Cycle aus, 
50
51
    RFM12_send_cmd(0xC4F3);            // AFC
52
53
    RFM12_send_cmd(0xA620);            // Frequenz
54
55
    RFM12_send_cmd(0x948C);            // Bandbreite
56
57
    RFM12_send_cmd(0xC610);            // Baudrate 19200
58
  }
59
60
void RFM12_read_fifo(char *data_buf, char len)
61
  {
62
63
    unsigned char byte = 0, i, j;
64
65
    RFM12_send_cmd(0x82C8);            // Empfänger ein
66
67
    RFM12_send_cmd(0xCA81);            // set FIFO mode
68
69
    RFM12_send_cmd(0xCA83);            // enable FIFO
70
71
      RFM12_PORT &= ~(1<<RFM12_SCK);        // CLK auf L
72
      RFM12_PORT &= ~(1<<RFM12_SDI);        // DATA auf L
73
74
    for (i=0; i<len; i++)
75
      {
76
        RFM12_PORT &= ~(1<<RFM12_CS);      // CS auf L
77
        asm("nop");
78
        asm("nop");
79
      while (!(RFM12_PIN & (1<<RFM12_SDO)))  // warten bis SDO 1 -> FFIL 
80
        {
81
        }
82
                
83
      byte = 0xB0;              // Receive FIFO
84
85
      for (j=0; j<8; j++)
86
        { 
87
        if (byte & 0x80)
88
            {
89
            RFM12_PORT |= (1<<RFM12_SDI);  // DATA auf H
90
            }
91
        else
92
            {
93
            RFM12_PORT &= ~(1<<RFM12_SDI);  // DATA auf L
94
            }
95
        asm("nop");
96
        asm("nop");
97
        asm("nop");
98
          RFM12_PORT |= (1<<RFM12_SCK);    // CLK auf H
99
        asm("nop");
100
        asm("nop");
101
        asm("nop");
102
        asm("nop");
103
          RFM12_PORT &= ~(1<<RFM12_SCK);    // CLK auf L
104
        byte = (byte << 1);          // nächstes Bit nach oben
105
        }
106
107
      byte = 0;
108
109
      for (j=0; j<8; j++)
110
        {     
111
        byte = (byte << 1);          // eins höher schieben
112
        if ((RFM12_PIN & (1<<RFM12_SDO)) == (1<<RFM12_SDO))  // Bit 1?
113
            {
114
            byte = (byte | 0x01);        // ja
115
            }
116
        asm("nop");
117
          RFM12_PORT |= (1<<RFM12_SCK);    // CLK auf H
118
        asm("nop");
119
        asm("nop");
120
          RFM12_PORT &= ~(1<<RFM12_SCK);    // CLK auf L
121
        }
122
      *data_buf++ = byte;
123
      RFM12_PORT |= (1<<RFM12_CS);      // CS auf H
124
    }
125
126
    RFM12_send_cmd(0x8208);            // Empfänger aus
127
128
  }
129
130
//------------------------------------------------------------------
131
132
uint16_t RFM12_read_status(void)
133
{
134
  uint16_t statusword = 0;
135
  unsigned char i = 0;
136
137
  RFM12_PORT &= ~(1<<RFM12_SCK);                 // CLK auf L
138
  RFM12_PORT &= ~(1<<RFM12_SDI);                 // DATA auf L
139
140
  RFM12_PORT &= ~(1<<RFM12_CS);                  // CS auf L
141
142
  for (i = 0; i < 16; i++)
143
  {
144
    statusword = (statusword << 1);             // eins höher schieben
145
    if ((RFM12_PIN & (1<<RFM12_SDO)) == (1<<RFM12_SDO))            // Bit 1?
146
    {
147
      statusword = (statusword | 0x0001);       // ja
148
    }
149
    asm("nop");
150
    RFM12_PORT |= (1<<RFM12_SCK);   // CLK auf H
151
    asm("nop");
152
    asm("nop");
153
    RFM12_PORT &= ~(1<<RFM12_SCK);    // CLK auf L
154
  }
155
  RFM12_PORT |= (1<<RFM12_CS);      // CS auf H
156
157
  return statusword;
158
}
und RFM12.h dazu:
1
#ifdef __cplusplus
2
extern "C" {
3
#endif
4
5
#define  RFM12_PORT  PORTB
6
#define  RFM12_DDR  DDRB
7
#define  RFM12_PIN  PINB
8
9
#define RFM12_CS   PB2
10
#define  RFM12_SDI   PB3
11
#define RFM12_SDO  PB4
12
#define  RFM12_SCK   PB5
13
14
#define  RFM12_IRQ_PIN  PIND
15
#define  RFM12_IRQ_IN  PD2
16
17
// nFFS: 1-10k Pullup an Vcc !!!
18
19
void RFM12_send_cmd(unsigned int command);
20
void RFM12_init(void);
21
void RFM12_read_fifo(char *data_buf, char len);
22
uint16_t RFM12_read_status(void);
23
24
#ifdef __cplusplus
25
} // extern "C"
26
#endif

keine Ahnung, ob das weiterhilft, ist alles Jahre her und läuft hier so 
immernoch...

Gruß aus Berlin
Michael

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Michael U. schrieb:

> Man kann den RFM12 problemlos komplett ohne Interrupt per Polling
> bedienen.

Das kann man tatsächlich.

Nur hat es der TO halt nicht getan, wie jeder Nichtvollidiot anhand des 
OT sofort spielend leicht erkennen kann. Du hast es wohl nicht erkannt 
und bist damit vollkommen am Thema vorbei...

Das war nicht: wie mache ich das mit dümmlichen und 
resourcenverschwendendem Polling, sondern clever per Interrupt. Nunja: 
die Antwort ist (wie immer): mach' es einfach richtig. Und um es richtig 
machen zu können, muss man nunmal einfach wissen, wie sich das Teil 
verhält, was man da benutzen möchte, und dazu ist nunmal eine Lektüre 
des DB unverzichtbar, capisce?

von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,

die speziellen Eigenheiten des RFM12 sind mir momentan nicht mehr 
gegenwärtig. Vor Jahren habe ich mal eines dieser Beispiele 
durchexerziert und konnte damit Daten übertragen, wenn auch immer mal 
wieder etwas klemmte nach längerem Testen. Aber grundsätzlich 
funktioniert es. Sogar eine Fehlerkorrektur ist dabei. Wenn Du alles 
liest, findest Du eine ausgereifte Version und kannst dort den Ablauf 
abschauen.

Bei meinem Aufbau habe ich ebenfalls den AVR auf 5 V laufen und das 
RFM12 über 2,2 kOhm an SPI angeschlossen. Ging bei mir auch ohne die 10k 
sehr gut.

Beitrag "bidirektionale RS232 Funkbrücke mit RFM12"

mfG

von Michael U. (amiga)


Lesenswert?

Hallo,

c-hater schrieb:
> Nur hat es der TO halt nicht getan, wie jeder Nichtvollidiot anhand des
> OT sofort spielend leicht erkennen kann. Du hast es wohl nicht erkannt
> und bist damit vollkommen am Thema vorbei...

ok. Dann fange ich mal an: ich würde nicht freiwillg versuchen, 2 
RFM-Module als Empfänger/Sender an einen AVR zu packen, schon garnicht 
im Interrupt, wenn ich nicht genau weiß, was ich da mache.
Das weiß der TO wohl nicht, da stimme ich Dir zu.
Es ist 10 jahre her, daß ich mit mit den Teilen befasst habe, da waren 
die Unterlagen von HopeRF mehr als fragwürdig und die Verwandtschaft zu 
den SiLabs Si4xxx hatte sich noch nicht rumgesprochen.
Das Zeug läuft huer heute noch, es macht aber vermutlich wenig Sinn, ihm 
die alten AVR-ASM-Sourcen vorzuwerfen.

Christian S. schrieb:
> Bei meinem Aufbau habe ich ebenfalls den AVR auf 5 V laufen und das
> RFM12 über 2,2 kOhm an SPI angeschlossen. Ging bei mir auch ohne die 10k
> sehr gut.

Die alten waren bis 5V, die neueren B-Typen nur noch 3,6V max.
Bei den alten brauchte man garnichts zum 5V AVR.

Gruß aus Berlin
Michael

von c-hater (Gast)


Lesenswert?

Michael U. schrieb:

> ok. Dann fange ich mal an: ich würde nicht freiwillg versuchen, 2
> RFM-Module als Empfänger/Sender an einen AVR zu packen

Warum nicht? SPI ist ein Bus. Der funktioniert mit einem RFM12 genauso 
wie mit zweien. Natürlich braucht man (bei Interruptsteuerung) zwei Pins 
mehr für zwei. Einen SlaveSelect und einen IRQ. Ansonsten gibt es keinen 
Unterschied, ob man nun nur einen oder zwei verwendet. Entweder man 
weiss, was man tut, oder man weiss es halt nicht. Dagegen hilft nur 
eins: LERNEN. Und das fängt an mit der Lektüre des DB.

> Das weiß der TO wohl nicht, da stimme ich Dir zu.

Das ist sehr offensichtlich so. Genau das war meine Kritik.

von Florian S. (kingeldarion)


Lesenswert?

Hi,

danke für die Antworten. Ich habe es gerade eben endlich geschafft. Das 
Modul funktioniert wie ich es möchte, es werden alle bytes übertragen.

Am Ende war es dann vor allem dieser Beitrag 
(https://gobotronics.wordpress.com/2010/10/07/rfm12-programming/) der 
mir geholfen hat meine restlichen Fehler zu entdecken.

Problem war hauptsächlich das ich nicht verstanden hatte, dass ich den 
Transmitter für jedes Packet neu an und ausschalten musste.

Außerdem hat mir tatsächlich geholfen beide Module über einen seperaten 
Mikrocontroller anzusteuern.

Hier jetzt einmal mein Code mit dem ich erfolgreich war:
Sender:
1
const int PIN_SS = 12;
2
const int PIN_MOSI = 10;
3
const int PIN_MISO = 9;
4
const int PIN_SCK = 11;
5
const int PIN_IRQ = 8;
6
7
void irqchange(){
8
9
  Serial.write("IRQ: ");
10
  Serial.print(digitalRead(PIN_IRQ));
11
  Serial.write("\n");
12
}
13
14
void setup(){
15
16
  Serial.begin(9600);
17
  irqchange();
18
  attachInterrupt(digitalPinToInterrupt(PIN_IRQ), irqchange, CHANGE);
19
  
20
  pinMode(PIN_SS, OUTPUT);
21
  pinMode(PIN_MOSI, OUTPUT);
22
  pinMode(PIN_MISO, INPUT);
23
  pinMode(PIN_SCK, OUTPUT);
24
  pinMode(PIN_IRQ, INPUT);
25
26
  digitalWrite(PIN_SS, HIGH);
27
28
  delay(2000);
29
  PrintStatus();
30
  Serial.write("Begin Init\n");
31
  irqchange();
32
  //Sender
33
  SendByte(0x80, 0xE8); //Set 868Mhz
34
  PrintStatus();
35
  SendByte(0x82, 0x01); //Sleep Mode
36
  PrintStatus();
37
  SendByte(0xA6, 0x40); //Use the standart 868 Mhz Band
38
  PrintStatus();
39
  SendByte(0xC6, 0x23); //Bitrate
40
  PrintStatus();
41
  SendByte(0x90, 0x80); //?
42
  PrintStatus();
43
  SendByte(0xC2, 0x2C); //Empfangsdatenrekonstruktion
44
  PrintStatus();
45
  SendByte(0xCA, 0x81); //FIFO Empfängersteuerung -> Fifo leeren und sperren
46
  PrintStatus();
47
  SendByte(0xCA, 0xF3); //FIFO freigeben | evtl F3 oder 83?
48
  PrintStatus();
49
  SendByte(0xCE, 0xD4); //Wert der als Synchronisations-Byte verwendet werden soll. (Frei nach Schnauze einstellbar?)
50
  PrintStatus();
51
  SendByte(0xC4, 0x00); //AFC => Ist wohl unbrauchbar, daher abschalten
52
  PrintStatus();
53
  SendByte(0x98, 0x00); //Senderkonfiguration -> Möglicherweise 0x50 testen (Library)
54
  PrintStatus();
55
  SendByte(0xCC, 0x77); //Taktgenerator einstellungen
56
  PrintStatus();
57
  SendByte(0xE0, 0x00); //Disable Wakeup stuff
58
  PrintStatus();
59
  SendByte(0xC8, 0x00); //Wakeup stuff -> disbaled
60
  PrintStatus();
61
  SendByte(0xC0, 0x00); //Unterspannungsdetektor und Taktungsteiler?
62
63
  PrintStatus();
64
}
65
66
void SendMessage(){
67
68
  Serial.write("\n\nWrite Message:\n");
69
  
70
  SendByte(0xB8, 0xAA); //Fill FIFO with Preambel
71
  SendByte(0xB8, 0xAA); //Fill FIFO with Preambel
72
73
  PrintStatus(); //Status should be 0 now
74
  
75
  irqchange(); //IRQ should be 1 now
76
77
  int currentStep = 0;
78
  SendByte(0x82, 0x39); //Enter Transfer Mode
79
  //irqchange();
80
  //PrintStatus();
81
82
  while(currentStep < 12){
83
84
    if(digitalRead(PIN_IRQ) == 0){
85
      
86
      switch(currentStep){
87
88
        case 0:
89
          SendByte(0xB8, 0xAA);
90
          break;
91
        
92
        case 1:
93
          SendByte(0xB8, 0x2D);
94
          break;
95
96
        case 2:
97
          SendByte(0xB8, 0xD4);
98
          break;
99
100
        case 3:
101
          SendByte(0xB8, 0x1B);
102
          break;
103
104
        case 4:
105
          SendByte(0xB8, 0x12);
106
          break;
107
108
        case 5:
109
          SendByte(0xB8, 0x89);
110
          break;
111
112
        case 6:
113
          SendByte(0xB8, 0x4E);
114
          break;
115
116
        case 7:
117
          SendByte(0xB8, 0x4E);
118
          break;
119
120
        case 8:
121
          SendByte(0xB8, 0x4E);
122
          break;
123
124
        case 9:
125
          SendByte(0xB8, 0x00);
126
          break;
127
128
        case 10:
129
          SendByte(0xB8, 0x00);
130
          break;
131
132
        case 11:
133
          SendByte(0x82, 0x09);
134
          Serial.write("Aus\n");
135
          break;
136
      }
137
138
      currentStep ++;
139
      //PrintStatus();
140
    }
141
  }
142
143
  PrintStatus();
144
  irqchange();
145
}
146
147
void loop(){
148
149
  SendMessage();
150
151
  delay(1000);
152
}
153
154
void PrintStatus(){
155
156
  Serial.write("Status: ");
157
  Serial.print(SendByte(0x00, 0x00));
158
  Serial.write("\n");
159
}
160
161
unsigned short SendByte(byte _cmd, byte _val) {
162
  
163
  digitalWrite(PIN_SCK, LOW);
164
  
165
  unsigned short read = 0;
166
  unsigned short value = _cmd;
167
  value = (value << 8) | _val;
168
169
  //delay a bit, just to be sure
170
171
  //Start a command
172
  digitalWrite(PIN_SS, LOW);
173
  //delayMicroseconds(1);
174
  for (int i = 0; i < 16; i ++) {
175
176
    //Write the bit
177
    digitalWrite(PIN_MOSI, (value >> 15 - i) & 0x0001);
178
179
    //delayMicroseconds(1);
180
    
181
    //Clock high -> Read!
182
    digitalWrite(PIN_SCK, HIGH);
183
184
    read = (read << 1) | digitalRead(PIN_MISO);
185
186
    //delayMicroseconds(1);
187
188
    //Clock low -> Write next bit or end (SS low)
189
    digitalWrite(PIN_SCK, LOW);
190
  }
191
  //delayMicroseconds(1);
192
  digitalWrite(PIN_SS, HIGH);
193
194
  /*Serial.write("Read: ");
195
  Serial.print(read);
196
  Serial.write("\n");*/
197
198
  return read;
199
}


Empfänger
1
const int PIN_SS = 2;
2
const int PIN_MOSI = 4;
3
const int PIN_MISO = 5;
4
const int PIN_SCK = 3;
5
const int PIN_IRQ = 6;
6
7
void setup(){
8
9
  Serial.begin(9600);
10
11
  digitalWrite(PIN_SS, HIGH);
12
13
  delay(2000);
14
  PrintStatus();
15
  Serial.write("Begin Init\n");
16
  irqchange();
17
  pinMode(PIN_SS, OUTPUT);
18
  pinMode(PIN_MOSI, OUTPUT);
19
  pinMode(PIN_MISO, INPUT);
20
  pinMode(PIN_SCK, OUTPUT);
21
  pinMode(PIN_IRQ, INPUT);
22
  
23
  //Receiver
24
  SendByte(0x80, 0xE8); //Set 868Mhz
25
  SendByte(0x82, 0x01); //Sleep Mode
26
  SendByte(0xA6, 0x40); //Use the standart 868 Mhz Band
27
  SendByte(0xC6, 0x23); //Bitrate
28
  SendByte(0x90, 0x85); //?
29
  SendByte(0xC2, 0x2C); //Empfangsdatenrekonstruktion
30
  SendByte(0xCA, 0x81); //FIFO Empfängersteuerung -> Fifo leeren und sperren
31
  SendByte(0xCA, 0x83); //FIFO freigeben | nicht F3! Löst interrupt erst bei 2 vollen byte aus!
32
  SendByte(0xCE, 0xD4); //Wert der als Synchronisations-Byte verwendet werden soll. (Frei nach Schnauze einstellbar?)
33
  SendByte(0xC4, 0x00); //AFC => Ist wohl unbrauchbar, daher abschalten
34
  SendByte(0x98, 0x00); //Senderkonfiguration -> Möglicherweise 0x50 testen (Library)
35
  SendByte(0xCC, 0x77); //Taktgenerator einstellungen
36
  SendByte(0xE0, 0x00); //Disable Wakeup stuff
37
  SendByte(0xC8, 0x00); //Wakeup stuff -> disbaled
38
  SendByte(0xC0, 0x00); //Unterspannungsdetektor und Taktungsteiler?
39
40
  PrintStatus();
41
  irqchange();
42
  
43
  int i = 0;
44
  unsigned int* rec = new int[32];
45
  
46
  //SendByte(0xCA, 0x83);
47
  //SendByte(0xCA, 0x81);
48
  SendByte(0xCA, 0x81);
49
  SendByte(0xCA, 0x83); //Definitiv nicht F3  -> löst interrupt erst bei 2 vollen byte
50
  SendByte(0x82, 0xD9);
51
  
52
  //PrintStatus();
53
54
  //Serial.write("Starting read:\n");
55
  while(i < 6){
56
57
    if(digitalRead(PIN_IRQ) == 0){
58
      
59
      /*int rec = SendByte(0xB0, 0x00);
60
61
      if(rec == 0){
62
63
        Serial.print(rec);
64
        Serial.write("\n");
65
      }
66
      else{
67
68
        PrintStatus();
69
      }*/
70
      
71
      rec[i] = SendByte(0xB0, 0x00);
72
      i ++;
73
    }
74
75
    //Serial.write("A\n");
76
  }
77
78
  PrintStatus();
79
  
80
  for(int i = 0; i < 6; i ++){
81
82
    Serial.println(rec[i]);
83
  }
84
}
85
86
void loop(){
87
88
  
89
  Serial.write("Hallo\n");
90
  digitalWrite(7, HIGH);
91
  delay(1000);
92
  digitalWrite(7, LOW);
93
  delay(1000);
94
}
95
96
void irqchange(){
97
98
  Serial.write("IRQ: ");
99
  Serial.print(digitalRead(PIN_IRQ));
100
  Serial.write("\n");
101
}
102
103
void PrintStatus(){
104
105
  Serial.write("Status: ");
106
  Serial.print(SendByte(0x00, 0x00));
107
  Serial.write("\n");
108
}
109
110
unsigned short SendByte(byte _cmd, byte _val) {
111
  
112
  digitalWrite(PIN_SCK, LOW);
113
  
114
  unsigned short read = 0;
115
  unsigned short value = _cmd;
116
  value = (value << 8) | _val;
117
118
  //delay a bit, just to be sure
119
  delayMilliseconds();
120
121
  //Start a command
122
  digitalWrite(PIN_SS, LOW);
123
  //delayMilliseconds();
124
  for (int i = 0; i < 16; i ++) {
125
126
    //Write the bit
127
    digitalWrite(PIN_MOSI, (value >> 15 - i) & 0x0001);
128
129
    //delayMilliseconds();
130
    
131
    //Clock high -> Read!
132
    digitalWrite(PIN_SCK, HIGH);
133
134
    read = (read << 1) | digitalRead(PIN_MISO);
135
136
    //delayMilliseconds();
137
138
    //Clock low -> Write next bit or end (SS low)
139
    digitalWrite(PIN_SCK, LOW);
140
  }
141
  //delayMilliseconds();
142
  digitalWrite(PIN_SS, HIGH);
143
  //delayMilliseconds();
144
145
  /*Serial.write("Read: ");
146
  Serial.print(read);
147
  Serial.write("\n");*/
148
149
  return read;
150
}
151
152
void delayMilliseconds(){
153
154
  
155
}

Dann würde ich gerne noch was zu Herrn c-hater sagen:

Zum einen verstehe ich diese Abneigung gegenüber Arduino nicht. Klar ist 
das nicht das gleiche wie wenn man mit C oder Assembler programmiert und 
sehr stark vereinfacht. Aber genau dass ist ja das schöne jeder kann 
damit was machen, egal wie sehr er sich mit der Materie auskennt.

Wie ich auch geschrieben habe, benutze ich Arduino auch nur zum testen. 
Wenn ich dann final die Projekte umsetze entwickle ich meistens in C, 
bei kleinen Projekten spaßeshalber mit Assembler.

Das schöne an Arduino ist einfach dass man mit wenig Aufwand viel 
erreichen kann. Und vor allem zum testen und ausprobieren möchte ich 
nicht viel Aufwand betreiben.
Allein das ich mit einer Zeile meine Serial Monitor ansprechen kann und 
Text übertragen kann, ist hier schon große Hilfe.

Wer Arduino nicht mag schön und gut, aber bitte urteile nicht über 
andere die eine andere Meinung hierzu haben.

Zum Thema Datenblatt lesen. Wie ich bereits geschrieben hatte, bin ich 
halt kein Elektrotechniker oder ähnliches. Ich HABE die Datenblätter 
gelesen und dies nicht nur einmal, wie gesagt, habe ich jetzt fast einen 
Monat gebraucht um die Module zum laufen zu bekommen und ich habe fast 
20 Lesezeichen zum Thema im Firefox abgelegt.
Als "Laie" ist es für mich halt nicht immer so einfach alles zu 
verstehen und es ist oft viel kompakte Info die in den Datenblättern 
steht, ohne viel Kontextwissen.
Also wenn du aus dem Datenblatt direkt alles verstehst und es umsetzen 
kannst, freut mich das für dich. Aber ich kann es nicht.

Ich habe diesen Forenbeitrag auch nur eröffnet, weil ich eine Woche lang 
nicht mehr weitergekommen bin, OBWOHL ich weiter recherchiert habe und 
keine neuen Informationen entdeckt habe.

Und am Ende waren es jetzt keine großen Veränderungen mehr, also hatte 
ich es tatsächlich geschafft einiges richtig zu machen, ohne Hilfe von 
anderen sondern nur mittels Lektüre. Also sei ein wenig konstruktiver 
und stelle andere nicht in Frage sondern versuche ihnen zu helfen auf 
die richtige Spur zu kommen. Es haben halt nicht alle den gleichen 
Wissensstand wie du.

So wie in deinem erstem Beitrag der Part mit den einfachen Worten. Der 
hat mir tatsächlich geholfen. Ein wenig netter formuliert und ich wäre 
dir wirklich dankbar dafür gewesen.

Mit freundlichen Grüßen
Florian

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.