SmartRC-CC1101-Driver-Lib
SmartRC-CC1101-Driver-Lib copied to clipboard
Two-way communication with checksum verification
Hey, I'm trying to build a doorbell system using two cc1101 transceivers. It will look somewhat like this:
[Battery]--[Arduino]--[CC1101]-))))))))))) (((((((((((-[CC1101]--[Arduino]--[5v power]
| |
[Button] [speaker]
When the button is pressed the Arduino is supposed to send a 14 byte packet like this one:
{1,2,3,4,5,6,7,8 1, 11, 22, 33, 44, 123}
1,2,3,4,5,6,7,8
is to identify that it is my doorbell system,
the following 1
indicates the packet is sent from the device with the button,
11, 22, 33, 44
these 4 bytes can be different every time (they contain the capacity or voltage of the battery),
123
will also be different every time because it is a checksum generated from the first 13 bytes.
The other Arduino should then receive the packet and verify its integrity using the checksum.
If the packet is broken/invalid, it should be ignored, otherwise it should send the packet back to the first device, but replace the 9th byte (the 1
) with a 2
and generate the new checksum for this packet. (It should of course also play a doorbell sound through the speaker.)
If the first device then successfully receives that new packet then it can go to sleep and wait for another button press, otherwise it should send the original packet again.
I already have the code to generate the packets including a checksum and send them, but it seems very complicated to come up with a clean way of receiving the data because ELECHOUSE_cc1101.ReceiveData may contain way more data than my packet or only a small portion of it.
Any ideas how this could be accomplished in a clean way?
This is my code for the first device (the one with the button) so far:
#include <ELECHOUSE_CC1101_SRC_DRV.h>
#include <avr/sleep.h>
#include <avr/power.h>
typedef union { // makes converting the voltage float into 4 bytes easier
float asFloat;
byte asBytes[4];
} voltage;
const int WAKE_BUTTON_PIN = 2; // interrupt pin to wake the Arduino out of deep sleep
#ifdef ESP32
const int gdo0 = 2; // for esp32! GDO0 on GPIO pin 2.
#elif ESP8266
const int gdo0 = 5; // for esp8266! GDO0 on pin 5 = D1.
#else
const int gdo0 = 6; // for Arduino! GDO0 on pin 6.
#endif
const byte DOORBELL_ID[8] = {127,33,45,91,27,60,8,16};
const byte TRANSMITTER_ID[1] = {1};
const byte RECEIVER_ID[1] = {2};
bool goToSleep = true;
void setup() {
Serial.begin(9600);
Serial.println("Doorbell transmitter");
pinMode(WAKE_BUTTON_PIN, INPUT);
ELECHOUSE_cc1101.Init(); // must be set to initialize the cc1101!
ELECHOUSE_cc1101.setGDO(gdo0,0); // set lib internal gdo pins (gdo0,gdo2). Gdo2 not used for this example.
ELECHOUSE_cc1101.setCCMode(1); // set config for internal transmission mode.
ELECHOUSE_cc1101.setModulation(0); // set modulation mode. 0 = 2-FSK, 1 = GFSK, 2 = ASK/OOK, 3 = 4-FSK, 4 = MSK.
ELECHOUSE_cc1101.setMHZ(433.92); // Here you can set your basic frequency. The lib calculates the frequency automatically (default = 433.92).The cc1101 can: 300-348 MHZ, 387-464MHZ and 779-928MHZ. Read More info from datasheet.
// ELECHOUSE_cc1101.setPA(10); // set TxPower. The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max!
}
void loop() {
if (goToSleep == true) {
enterSleep();
}
}
// Read the voltage of the battery the Arduino is currently running on
float getVoltage(void) {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // For mega boards
const long InternalReferenceVoltage = 1115L; // Adjust this value to your boards specific internal BG voltage x1000
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else // For 168/328 boards
const long InternalReferenceVoltage = 1056L;
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif
delay(50); // Let mux settle a little to get a more stable A/D conversion
ADCSRA |= _BV( ADSC ); // Start a conversion
while( ( (ADCSRA & (1<<ADSC)) != 0 ) ); // Wait for it to complete
int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // Scale the value; calculates for straight line value
return (float)results/(float)100; // convert from centivolt to volt
}
// Create 1 byte crc checksum from a byte array
byte calculateCRC(byte ar[], byte s) {
byte rtn = 0;
for(byte i =0; i < s; i++) {
rtn ^= ar[i];
}
return rtn;
}
void pin2Interrupt(void) {
/* This will bring us back from sleep. */
/* We detach the interrupt to stop it from
* continuously firing while the interrupt pin
* is low.
*/
detachInterrupt(WAKE_BUTTON_PIN);
}
void enterSleep(void) {
goToSleep = false;
attachInterrupt(WAKE_BUTTON_PIN, pin2Interrupt, LOW);
delay(100);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
ringDoorbell();
goToSleep = true;
}
void ringDoorbell(void) {
voltage batteryVoltage;
batteryVoltage.asFloat = getVoltage();
byte data[13]; // we will write the packet data without the checksum into this array using memcpy
memcpy(data, DOORBELL_ID, sizeof(DOORBELL_ID));
memcpy(data+sizeof(DOORBELL_ID), TRANSMITTER_ID, sizeof(TRANSMITTER_ID));
memcpy(data+sizeof(DOORBELL_ID)+sizeof(TRANSMITTER_ID), batteryVoltage.asBytes, sizeof(batteryVoltage.asBytes));
// Create a cehcksum from the data byte array
byte checksum[1] = { calculateCRC(data, sizeof(data)) };
//Copy the data array and the checksum into the packet
byte packet[14];
memcpy(packet, data, sizeof(data));
memcpy(packet+sizeof(data), checksum, sizeof(checksum));
// Send the packet
ELECHOUSE_cc1101.SendData(packet, sizeof(packet));
// Now we need to wait for a packet from the other device
// Then we can set goToSleep = true; so that the Arduino goes into sleep mode again.
// If there packet has not been received after a a couple of milliseconds, it needs to be sent again.
}
Hi, interesting project. I can understand the general functionality based on a description. I should know how far it works. So at what point there are problems with receiving.
-
You press the button on the transmitter.
-
the transmitter sends the signal over and over again.
-
the receiver receives the signal correctly.
-
the receiver sends a confirmation signal back to the transmitter.
-
the transmitter receives the confirmation signal and goes to sleep.
Is it correct so far and at what point does it not work properly?
Regards
I'm sorry. I have not seen that the sketch is incomplete. I assumed he was done. I'll get back to you later. if I have time.
so there should be basically no problem to implement an automatic 2-way communication. i will finish writing the code and do an experimental setup. incidentally, the cc1101 has an internal crc test. I haven't built this in yet. I will take it into account in the next update.
I wonder why they don't try aif the traditional way. I mean simply repeat the signal a few times without sending anything back. the whole thing only makes sense for me with an emergency call system. may it be that you wrote something about it in a forum I know?
Regards
Thank you for taking your time! I didn't know about the internal crc test, that's nice.
The reason for 2-way communication instead of sending the same packet repeatedly is that it is that is is way more reliable. The interference of other devices in the area I live in is extremely high. Sening the packet 5 times in a row is often not enough. I could of course send the packet 100 times in a row to be relatively sure that it arrives, but that would drain the battery extremely quickly and still wouldn't guarantee that the packet arrived.
hello, unfortunately i haven't found the time to complete the sketch. because I worked on the 2.5.0 update. It is now possible to use the internal crc calculation of the cc1101. I also added a new method for receiving the data. with this you can do other things besides receiving data. there are many other settings available. if you can't do anything with the settings of the advanced examples, I recommend you to take a look at the new receive method minimal and transmit hello world minimal. Regards
@LSatan Thank you, that's very helpful. I added that to my code. This is the only way I could come up with to implement 2-way communication, but it is hard to read and probably very unreliable:
#include <ELECHOUSE_CC1101_SRC_DRV.h>
#include <avr/sleep.h>
#include <avr/power.h>
typedef union { // makes converting the voltage float into 4 bytes easier
float asFloat;
byte asBytes[4];
} voltage;
const int WAKE_BUTTON_PIN = 2; // interrupt pin to wake the Arduino out of deep sleep
#ifdef ESP32
const int gdo0 = 2; // for esp32! GDO0 on GPIO pin 2.
#elif ESP8266
const int gdo0 = 5; // for esp8266! GDO0 on pin 5 = D1.
#else
const int gdo0 = 6; // for Arduino! GDO0 on pin 6.
#endif
const byte DOORBELL_ID[8] = {127,33,45,91,27,60,8,16};
const byte TRANSMITTER_ID[1] = {1};
const byte RECEIVER_ID[1] = {2};
bool goToSleep = true;
bool waitForResponse = false;
unsigned long lastPkgSendTime = 0;
const unsigned long maxTimeToWait = 500;
const int maxRetries = 10;
int currentRetryCount = 0;
voltage batteryVoltage;
byte buffer[61] = {0};
void enterSleep(void);
void ringDoorbell(void);
void pin2Interrupt(void);
float getVoltage(void);
void setup() {
Serial.begin(9600);
Serial.println("Doorbell Transmitter");
pinMode(WAKE_BUTTON_PIN, INPUT_PULLUP);
ELECHOUSE_cc1101.Init(); // must be set to initialize the cc1101!
ELECHOUSE_cc1101.setGDO(gdo0,0); // set lib internal gdo pins (gdo0,gdo2). Gdo2 not used for this example.
ELECHOUSE_cc1101.setCCMode(1); // set config for internal transmission mode.
ELECHOUSE_cc1101.setModulation(0); // set modulation mode. 0 = 2-FSK, 1 = GFSK, 2 = ASK/OOK, 3 = 4-FSK, 4 = MSK.
ELECHOUSE_cc1101.setMHZ(433.92); // Here you can set your basic frequency. The lib calculates the frequency automatically (default = 433.92).The cc1101 can: 300-348 MHZ, 387-464MHZ and 779-928MHZ. Read More info from datasheet.
ELECHOUSE_cc1101.setSyncMode(2); // Combined sync-word qualifier mode. 0 = No preamble/sync. 1 = 16 sync word bits detected. 2 = 16/16 sync word bits detected. 3 = 30/32 sync word bits detected. 4 = No preamble/sync, carrier-sense above threshold. 5 = 15/16 + carrier-sense above threshold. 6 = 16/16 + carrier-sense above threshold. 7 = 30/32 + carrier-sense above threshold.
// ELECHOUSE_cc1101.setPA(10); // set TxPower. The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max!
ELECHOUSE_cc1101.setCrc(1); // 1 = CRC calculation in TX and CRC check in RX enabled. 0 = CRC disabled for TX and RX.
Serial.println("Doorbell Transmitter Is Ready");
}
void loop() {
if (goToSleep == true) {
goToSleep = false;
Serial.println("Going to sleep...");
enterSleep();
}
unsigned long now = millis();
if (!waitForResponse) {
Serial.println("Calling ringDoorbell...");
ringDoorbell();
lastPkgSendTime = now;
ELECHOUSE_cc1101.SetRx();
waitForResponse = true;
currentRetryCount = currentRetryCount+1;
} else if (now+maxTimeToWait < lastPkgSendTime) {
if (ELECHOUSE_cc1101.CheckRxFifo(100)) {
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
Serial.println((char *) buffer);
for (int i = 0; i<len; i++){
if (buffer[i] == DOORBELL_ID[0] &&
buffer[i+1] == DOORBELL_ID[1] &&
buffer[i+2] == DOORBELL_ID[2] &&
buffer[i+3] == DOORBELL_ID[3] &&
buffer[i+4] == DOORBELL_ID[4] &&
buffer[i+5] == DOORBELL_ID[5] &&
buffer[i+6] == DOORBELL_ID[6] &&
buffer[i+7] == DOORBELL_ID[7] &&
buffer[i+8] == RECEIVER_ID[1]
) {
Serial.println("New packet received!");
voltage receivedBatteryVoltage;
receivedBatteryVoltage.asBytes[0] = buffer[i+9];
receivedBatteryVoltage.asBytes[1] = buffer[i+10];
receivedBatteryVoltage.asBytes[2] = buffer[i+11];
receivedBatteryVoltage.asBytes[3] = buffer[i+12];
if (receivedBatteryVoltage.asFloat == batteryVoltage.asFloat) {
ELECHOUSE_cc1101.SetTx();
waitForResponse = false;
currentRetryCount = 0;
goToSleep = true;
}
}
}
}
} else if (currentRetryCount < maxRetries) {
Serial.println("Retry...");
ELECHOUSE_cc1101.SetTx();
waitForResponse = false;
} else {
Serial.println("Failed to contact Receiver! Going back to sleep...");
ELECHOUSE_cc1101.SetTx();
waitForResponse = false;
currentRetryCount = 0;
goToSleep = true;
}
}
// Read the voltage of the battery the Arduino is currently running on
float getVoltage(void) {
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // For mega boards
const long InternalReferenceVoltage = 1115L; // Adjust this value to your boards specific internal BG voltage x1000
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else // For 168/328 boards
const long InternalReferenceVoltage = 1056L;
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif
delay(50); // Let mux settle a little to get a more stable A/D conversion
ADCSRA |= _BV( ADSC ); // Start a conversion
while( ( (ADCSRA & (1<<ADSC)) != 0 ) ); // Wait for it to complete
int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // Scale the value; calculates for straight line value
return (float)results/(float)100; // convert from centivolt to volt
}
void onWakeUp(void) {
detachInterrupt(WAKE_BUTTON_PIN);
Serial.println("Button pressed! Waking up!");
}
void enterSleep(void) {
attachInterrupt(WAKE_BUTTON_PIN, onWakeUp, LOW);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
sleep_bod_disable();
sei();
sleep_cpu();
/* wake up here */
sleep_disable();
}
void ringDoorbell(void) {
batteryVoltage.asFloat = getVoltage();
byte packet[13]; // we will write the packet data into this array using memcpy
memcpy(packet, DOORBELL_ID, sizeof(DOORBELL_ID));
memcpy(packet+sizeof(DOORBELL_ID), TRANSMITTER_ID, sizeof(TRANSMITTER_ID));
memcpy(packet+sizeof(DOORBELL_ID)+sizeof(TRANSMITTER_ID), batteryVoltage.asBytes, sizeof(batteryVoltage.asBytes));
// Send the packet
ELECHOUSE_cc1101.SendData(packet, sizeof(packet));
}
Hi, I've got it going this far. I approached it a little differently. It definitely works fine for me. I divided the battery voltage into 2x 8bit. the receiver then puts it back together and outputs the voltage. I have reworked your sleep function a bit because he never went to sleep. I added a counter so that the receiver can recognize whether the signal is new or old. when the transmitter is pressed, the counter is 0 and is increased with each repetition. but it is best to try it yourself and then adjust it to your liking. give me feedback in any case. before I forget you have to update to v2.5.1 the v2.5.0 gets stuck when switching from rx to tx. As I said, I press the button, the receiver receives it and sends the signal back with 2, the transmitter goes into sleep.
addition: you have to set the input to pullup again. changed it because I switch high and not low. I would leave the interrupt on (interrupt, change). Then works at high or low.
Thank you so much! I just tried your code, but I can't get it to work. I set it to INPUT_PULLUP again and when I press the button it wakes up and sleeps again without transmitting anything. I have to press the button many times before anything is transmitted. Any ideas what is going wrong here?
My button is simply connected between Gnd and Pin 2 without any resistors.
that is very unusual. unfortunately I can only test later. since i'm still working. with me it starts sending immediately after waking up. I use arduino ide v 1.8.9. I will test again later with input pullup.
i used pin 3 for the button. with 10k pulldown resistance.
which arduino do you use? I tested with nano.
I'm using 1.8.5 because it's difficult to get the latest version on my OS. I'm testing with an Arduino UNO (it has an ATMEGA 328P chip).
ok uno and nano don't really differ. 1.8.5 shouldn't be the problem. i will carry out tests again afterwards and try to reproduce the error.
Thank you. :)
I checked everything again. and only changed a little bit. I'm fine with D2 and pullup too. Check all your connections again! Everything works fine for me.
after starting:
send button was pressed:
transmitter (receiver is off):
the transmitter:
#include <ELECHOUSE_CC1101_SRC_DRV.h>
#include <avr/sleep.h>
#include <avr/power.h>
const int WAKE_BUTTON_PIN = 2; // interrupt pin to wake the Arduino out of deep sleep
const int gdo0 = 6; // for Arduino! GDO0 on pin 6.
static int interruptPin = 0;
const byte DOORBELL_ID[8] = {127,33,45,91,27,60,8,16};
const byte TRANSMITTER_ID = 1;
const byte RECEIVER_ID = 2;
byte DOORBELL_COUNT = 0;
byte batteryVoltage[2];
bool goToSleep = true;
int Tx_interval = 1000;
static unsigned long Tx_lasttime;
void setup() {
Serial.begin(9600);
Serial.println("Doorbell Transmitter");
pinMode(WAKE_BUTTON_PIN, INPUT_PULLUP);
//pinMode(WAKE_BUTTON_PIN, INPUT);
interruptPin = digitalPinToInterrupt(WAKE_BUTTON_PIN);
ELECHOUSE_cc1101.Init(); // must be set to initialize the cc1101!
ELECHOUSE_cc1101.setGDO(gdo0,0); // set lib internal gdo pins (gdo0,gdo2). Gdo2 not used for this example.
ELECHOUSE_cc1101.setCCMode(1); // set config for internal transmission mode.
ELECHOUSE_cc1101.setModulation(0); // set modulation mode. 0 = 2-FSK, 1 = GFSK, 2 = ASK/OOK, 3 = 4-FSK, 4 = MSK.
ELECHOUSE_cc1101.setMHZ(433.92); // Here you can set your basic frequency. The lib calculates the frequency automatically (default = 433.92).The cc1101 can: 300-348 MHZ, 387-464MHZ and 779-928MHZ. Read More info from datasheet.
ELECHOUSE_cc1101.setSyncMode(2); // Combined sync-word qualifier mode. 0 = No preamble/sync. 1 = 16 sync word bits detected. 2 = 16/16 sync word bits detected. 3 = 30/32 sync word bits detected. 4 = No preamble/sync, carrier-sense above threshold. 5 = 15/16 + carrier-sense above threshold. 6 = 16/16 + carrier-sense above threshold. 7 = 30/32 + carrier-sense above threshold.
// ELECHOUSE_cc1101.setPA(10); // set TxPower. The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max!
ELECHOUSE_cc1101.setCrc(1); // 1 = CRC calculation in TX and CRC check in RX enabled. 0 = CRC disabled for TX and RX.
Serial.println("Doorbell Transmitter Is Ready");
}
void loop() {
enterSleep();
readButtonState();
get_power_level();
transmit_data();
receive_data();
//Serial.println("Test I am wake");// Test for Sleepmode work!
}
//////////////////////////////////////////////////////////
void transmit_data(){
if (goToSleep == false){
if (millis()-Tx_lasttime > Tx_interval){
byte Packet[12];
for (int i=0; i<8; i++)
{Packet[i]=DOORBELL_ID[i];}
Packet[8]=TRANSMITTER_ID;
Packet[9]=DOORBELL_COUNT;
Packet[10]=batteryVoltage[0];
Packet[11]=batteryVoltage[1];
DOORBELL_COUNT++;
ELECHOUSE_cc1101.SendData(Packet,12);
Serial.print("Transmit data ");
for (int i=0; i<12; i++){
Serial.print(Packet[i],DEC);
Serial.print(",");
}
Serial.println();
ELECHOUSE_cc1101.SetRx();
Tx_lasttime = millis();
}
}
}
//////////////////////////////////////////////////////////
void receive_data(){
if (goToSleep == false){
if (ELECHOUSE_cc1101.CheckRxFifo(50)){
if (ELECHOUSE_cc1101.CheckCRC()){
byte buffer[61] = {0};
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
for (int i=0; i<8; i++){
if (buffer[i]!=DOORBELL_ID[i]){return;}
}
if (buffer[8]!= RECEIVER_ID){return;}
Serial.print("Received data ");
for (int i=0; i<9; i++){
Serial.print(buffer[i]);
Serial.print(",");
}
Serial.println();
goToSleep = true;
}
}
}
}
//////////////////////////////////////////////////////////
void get_power_level(){
if (goToSleep == false){
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // For mega boards
const long InternalReferenceVoltage = 1115L; // Adjust this value to your boards specific internal BG voltage x1000
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#else // For 168/328 boards
const long InternalReferenceVoltage = 1056L;
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
#endif
delay(50); // Let mux settle a little to get a more stable A/D conversion
ADCSRA |= _BV( ADSC ); // Start a conversion
while( ( (ADCSRA & (1<<ADSC)) != 0 ) ); // Wait for it to complete
int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // Scale the value; calculates for straight line value
//Divide the battery voltage into 2x 8bit
batteryVoltage[0] = results>>8;
batteryVoltage[1] = results & 0xFF;
}
}
//////////////////////////////////////////////////////////
void onWakeUp(){
//detachInterrupt(interruptPin);// arduino freezes. but works fine without a detach!
}
//////////////////////////////////////////////////////////
void enterSleep(){
if (goToSleep == true){
Serial.println("go Sleep");
attachInterrupt(interruptPin, onWakeUp, CHANGE);
delay(100);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
DOORBELL_COUNT = 0;
goToSleep = false;
Serial.println("wake up");
}
}
//////////////////////////////////////////////////////////
void readButtonState(){
if (digitalRead(WAKE_BUTTON_PIN)==LOW){
DOORBELL_COUNT = 0;
}
}
the receiver:
#include <ELECHOUSE_CC1101_SRC_DRV.h>
const int gdo0 = 6; // for Arduino! GDO0 on pin 6.
const byte DOORBELL_ID[8] = {127,33,45,91,27,60,8,16};
const byte TRANSMITTER_ID = 1;
const byte RECEIVER_ID = 2;
byte DOORBELL_COUNT = 255;
float batteryVoltage;
int Doorbell_ringtime = 3000;
int Tx_interval = 200;
int Rx_timeout = 20000;
static unsigned long Tx_lasttime;
static unsigned long Rx_lasttime;
static unsigned long Doorbell_lasttime;
bool doorbell_activ = false;
bool transmitter_activ = false;
void setup() {
Serial.begin(9600);
Serial.println("Doorbell Receiver");
ELECHOUSE_cc1101.Init(); // must be set to initialize the cc1101!
ELECHOUSE_cc1101.setGDO(gdo0,0); // set lib internal gdo pins (gdo0,gdo2). Gdo2 not used for this example.
ELECHOUSE_cc1101.setCCMode(1); // set config for internal transmission mode.
ELECHOUSE_cc1101.setModulation(0); // set modulation mode. 0 = 2-FSK, 1 = GFSK, 2 = ASK/OOK, 3 = 4-FSK, 4 = MSK.
ELECHOUSE_cc1101.setMHZ(433.92); // Here you can set your basic frequency. The lib calculates the frequency automatically (default = 433.92).The cc1101 can: 300-348 MHZ, 387-464MHZ and 779-928MHZ. Read More info from datasheet.
ELECHOUSE_cc1101.setSyncMode(2); // Combined sync-word qualifier mode. 0 = No preamble/sync. 1 = 16 sync word bits detected. 2 = 16/16 sync word bits detected. 3 = 30/32 sync word bits detected. 4 = No preamble/sync, carrier-sense above threshold. 5 = 15/16 + carrier-sense above threshold. 6 = 16/16 + carrier-sense above threshold. 7 = 30/32 + carrier-sense above threshold.
// ELECHOUSE_cc1101.setPA(10); // set TxPower. The following settings are possible depending on the frequency band. (-30 -20 -15 -10 -6 0 5 7 10 11 12) Default is max!
ELECHOUSE_cc1101.setCrc(1); // 1 = CRC calculation in TX and CRC check in RX enabled. 0 = CRC disabled for TX and RX.
ELECHOUSE_cc1101.SetRx();
Serial.println("Doorbell Receiver Is Ready");
}
void loop() {
receive_data();
doorbell();
transmit_data();
}
//////////////////////////////////////////////////////////
void doorbell(){
if (doorbell_activ == true){
if (millis()-Doorbell_lasttime < Doorbell_ringtime){
Serial.println("Ring ring...");
}
}else{
doorbell_activ = false;
}
if (millis()-Rx_lasttime > Rx_timeout){
DOORBELL_COUNT = 255;
}
}
//////////////////////////////////////////////////////////
void transmit_data(){
if (transmitter_activ == true){
if (millis()-Tx_lasttime > Tx_interval){
byte Packet[9];
for (int i=0; i<8; i++)
{Packet[i]=DOORBELL_ID[i];}
Packet[8]=RECEIVER_ID;
ELECHOUSE_cc1101.SendData(Packet,9);
Serial.print("Transmit data ");
for (int i=0; i<9; i++){
Serial.print(Packet[i],DEC);
Serial.print(",");
}
Serial.println();
ELECHOUSE_cc1101.SetRx();
transmitter_activ = false;
DOORBELL_COUNT = 255;
}
}
//}
}
//////////////////////////////////////////////////////////
void receive_data(){
if (ELECHOUSE_cc1101.CheckRxFifo(50)){
if (ELECHOUSE_cc1101.CheckCRC()){
byte buffer[61] = {0};
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
for (int i=0; i<8; i++){
if (buffer[i]!=DOORBELL_ID[i]){return;}
}
if (buffer[8]!= TRANSMITTER_ID){return;}
Serial.println("Data Received: ");
Serial.println("Doorbell ID: ");
for (int i=0; i<8; i++){
Serial.print(buffer[i]);
Serial.print(",");
}
Serial.println();
int voltage = buffer[10]<<8;
voltage += buffer[11];
batteryVoltage = (float)voltage/100;
Serial.print("Battery Voltage: ");
Serial.print(batteryVoltage);
Serial.println(" Volt");
if (buffer[9]<= DOORBELL_COUNT){
DOORBELL_COUNT = buffer[9];
doorbell_activ = true;
Doorbell_lasttime = millis();
}
transmitter_activ = true;
Tx_lasttime = millis();
Rx_lasttime = millis();
}
}
}
I just tested it. the same result on uno!
I got the Transmitter code to work now, thank you! I'm having trouble with the receiver code though. I checked the wires multiple times and even switched to new wires. I also tried different USB cables.
As you can see the receiver doesn't seem to receive anything.
nice that it works. I would be interested in what it was. It is important that the transmitter and receiver are a little apart. they must not be directly next to each other. I say at least 1 meter distance.
I'm not sure what the problem with the transmitter was, but after using your last code, it just worked. So it must have been a software issue.
I didn't think about short distance being an issue. That's a good tip! I will try it tomorrow and tell you how it went.
Again, thank you so much for all your help, I'm really greatful. I'll definitely throw in a donation.
thank you very much for the donation. Donations help to further develop the library. Since I can invest it in new hardware. To make them compatible. With your request, you have also contributed to further improving the library. In any case, let me know if it works. Or if other problems arise. Thanks again on behalf of everyone who uses this library.
I made sure they are further apart than 1m now, but the result is the same as before. I also switched the devices with each other. So I uploaded the transmitter code to the Arduino that used to be the receiver and I uploaded the receiver code to the Arduino that used to be the receiver. Interestingly the transmitter code still seems to be working and the receiver code still doesn't seem to receive anything.
So it looks to me like a software problem with the receiver code. Or maybe the receiver works just fine and the transmitter doesn't send any data even though it is printing the data to the Serial console?
Btw: I also tried using the receive_minimal example with and without the crc check and nothing was received.
This is my wiring btw:
GDO0 -> 6
MISO -> 12
MOSI -> 11
GND -> GND
CSN -> 10
GDO2 -> -
SCK -> 13
VCC -> 3v
the wiring is correct. for me the codes work as they are. you don't happen to own an sdr receiver? please try the examples of rc-switch once send demo cc1101 and receive demo cc1101. you should definitely receive something. otherwise something is wrong with the hardware. you also have to connect gdo2 (for rc-switch), please do not swap gdo0 and gdo2. it would also be good to know which cc1101 module you have. please link to this. tell me if it works with rc-swicht. I think we can do it.
Unfortunately I don't have any sdr receivers. :/ I might buy one though because it seems like a useful thing to have. Any recommendations?
I'm using the D-Sun CC1101 Module:
Which pin do I have to use for gdo2? I can't find any calls to setGDO method in the demo examples.
That's right we have already talked about the dsun module.
this is the pin assignment:
RTL-SDR USB stick with R820T2.
this module is completely sufficient and it is inexpensive.
but try rc-switch first.
Thank you, I just tried the rc-switch examples. Unfortuantely the receiver didn't receive anything.
I have a 433mhz FS1000A transmitter and a XY-MK-5V receiver lying around somewhere. Maybe I can use these to test my cc1101 modules.
mmh that doesn't sound too good. you can both use the receiver to test whether the cc1101 is transmitting. the transmitter to test whether cc1101 is receiving. but all only with rc-switch examples(receiver/transmitter).
hello, could you test it yet? to check whether the spi connection of the cc1101 is working you can use the debug tool.
https://github.com/LSatan/CC1101-Debug-Service-Tool
add the marked spots to your sketch:
Settings must then be recognizable in the registers:
I tried all day to get this to work. No luck so far. I tried using the XY-MK-5V receiver using the original rc-switch library using the simple receive example, but I couldn't get it to receive anything. I even tried sending signals using a 433mhz remote for a remote controlled outlet. No luck. I think the module is broken.
I have now switched to a new computer with Arduino IDE 1.8.13 and still couldn't get your code to work (same exact issues as before). I couldn't get the XY-MK-5V to work with that PC either.
I have now switched to an Arduino Pro Mini (3.3v version with 8mhz) with completely new wires and still I can't get it to receive anything with the cc1101.
I also tried getting your debug library to work, but I just can't get it to compile no matter what I try. I tried using different Arduinos (Uno and Pro Mini), I tried different versions (the latest master and the latest release). No luck, it doesn't want to compile.
I'm sorry, I had to adapt it to v.2.5.1 first. with the "preliminary version" it works now.(debug library)
I finally made some progress. I replaced the cc1101 modules with new ones and also replaced the breadboards and now it seems to work! Well, at least kind of...
When I press the button, the transmitter wakes up and sends the packets. The receiver then receives them and it seems like it's trying to send one back, but the transmitter never gets it. The transmitter is just continuously sending the packets.
Transmitter:
Transmitter:
Receiver: