So, I've got two nRF24L01 modules communicating with each other. Was working fine, now the data transfer is out of synch. I'm looking for help to get an easily understandable way to ACK? the data transfer is correct and continue? Radio communication is not my forte. I have no idea if the way I'm currently transferring data is correct, but it was working last night. Unfortunately, now it's out of synch. Specifically, the Cycle Time data shows up in the first position of Tbit0.
TX
void setup() {
// memset (powerupPos0, 90, sizeof(powerupPos0));
Serial.begin(57600);
Serial.println("JMRI CMRI Arduino Mega Interface");
Wire.setClock(400000); //sets i2c speed to 100kHz
pwm0.begin();
pwm0.setPWMFreq(FREQUENCY);
pwm1.begin();
pwm1.setPWMFreq(FREQUENCY);
radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.setRetries(3, 5); // delay, count
radio.openWritingPipe(slaveAddress);
for (byte i = 0; i < 16; i++) {
pinMode(relayPin0[i], OUTPUT); //attaches 16 relays to relayPins array
digitalWrite(relayPin0[i], relayState0[i]); //sets relays to default state in relayState array
pinMode(relayPin1[i], OUTPUT); //attaches 16 relays to relayPins array
digitalWrite(relayPin1[i], relayState1[i]); //sets relays to default state in relayState array
}
for (int i = 0; i < 16; i++) { // set and remember initial positions using array
moveservo0(i, (powerupPos0[i] + hornOffset0[i]));
currentPos0[i] = powerupPos0[i]; // and remember it as current
moveservo1(i, (powerupPos1[i] + hornOffset1[i]));
currentPos1[i] = powerupPos1[i]; // and remember it as current
} // and remember it as current
}
void loop() {
Tbit0[4]=1;
cycleMillis = millis(); //store time to calculate cycle time at end of loop
txcurrentMillis = millis();
if (txcurrentMillis - txprevMillis >= txIntervalMillis) {
Serial.print("CMRI bits 1-16: ");
for (byte i = 0; i < 16; i++) {
Serial.print(Tbit0[i]); Serial.print(", ");
Serial.print(Tbit1[i]); Serial.print(", ");
}
Serial.println();
radio.write( &Tbit0[0], sizeof(Tbit0) );
radio.write( &Tbit1[0], sizeof(Tbit1) );
radio.write( &cycleTime, sizeof(cycleTime) );
txprevMillis = millis();
}
Ok, so I convert each group of 8 bits into a byte and store the new bytes in an array? before sending them in one transmission. Then decode the new bytes back into bits(or whatever I want) on the receiving side.
I can use a for loop and bitshift to create the new bytes or is there an easier way to accomplish this conversion to a new array?
I think I can wade through creating a struct and I know that they are basically a user-defined data-type that can contain data in different types (int, bool, float etc).
Fyi, I've pretty much got the basics down. Now the fun is trying to combine working examples into something that is actually useful to me.
If it will help, here is code that I wrote to send and receive a struct made up of LDR (Light Dependent Resistor) readings from one Uno to another using rf24 radios.
So, Cycle Time seems correct. The first two sets of data change when I haven't changed any of the data. There is probably an easier way to structure the packet. The Rx end doesn't need the data back in an array so if the Tx Serial.print data is good the Rx data will be too.
I think I've finally got it. This is the current TX code:
unsigned int cycleTime;
unsigned int together1 = 0;
unsigned int together2 = 0;
struct TbitValues
{
unsigned int Tbit_1; //Tbit0 16 elements
unsigned int Tbit_2; //Tbit1 16 elements
int Tbit_3; //Cycle Time
} TbitValues;
void loop() {
Tbit0[4] = 1; Tbit0[15] = 1; Tbit0[1] = 1; Tbit0[3] = 1; //test data
memset (Tbit1, 1, sizeof(Tbit1)); //test data
cycleMillis = millis(); //store time to calculate cycle time at end of loop
txcurrentMillis = millis();
if (txcurrentMillis - txprevMillis >= txIntervalMillis) {
for (int i = 0; i < 16; i++) {
bitWrite(together1, 15 - i, Tbit0[i]);
bitWrite(together2, 15 - i, Tbit1[i]);
}
TbitValues.Tbit_1 = together1;
TbitValues.Tbit_2 = together2;
TbitValues.Tbit_3 = cycleTime;
radio.write( &TbitValues, sizeof(TbitValues) );
Serial.print("Tbit 1 = ");
Serial.println(TbitValues.Tbit_1, BIN);
Serial.print("Tbit 2 = ");
Serial.println(TbitValues.Tbit_2, BIN);
Serial.print("Cycle Time: ");
Serial.print(TbitValues.Tbit_3);
Serial.println(" ms");
txprevMillis = millis();
}
//other code
}
And RX code including adding leading 0s:
// SimpleRx - the slave or the receiver
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define CE_PIN 9
#define CSN_PIN 10
const byte thisSlaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};
RF24 radio(CE_PIN, CSN_PIN);
unsigned int together1 = 0;
unsigned int together2 = 0;
unsigned int cycleTime = 0;
struct TbitValues
{
unsigned int Tbit_1; //Tbit0 16 elements
unsigned int Tbit_2; //Tbit1 16 elements
unsigned int Tbit_3; //Cycle Time
} TbitValues;
void prntBits(unsigned int b)
{
for(int i = 15; i >= 0; i--)
Serial.print(bitRead(b,i));
Serial.println();
}
//===========
void setup() {
Serial.begin(57600);
Serial.println("SimpleRx Starting");
radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.openReadingPipe(1, thisSlaveAddress);
radio.startListening();
}
//=============
void loop() {
if ( radio.available() ) {
radio.read( &TbitValues, sizeof(TbitValues) );
together1 = TbitValues.Tbit_1;
together2 = TbitValues.Tbit_2;
cycleTime = TbitValues.Tbit_3;
Serial.print("Tbit 1 = ");
prntBits(together1);
Serial.print("Tbit 2 = ");
prntBits(together2);
Serial.print("Cycle Time: ");
Serial.print(cycleTime);
Serial.println(" ms");
}
}
Thanks so much to Whandall for pointing me in the right direction and to groundFungus for providing a useful example. I can now happily read data off my Mega wirelessly!
In principle, on the transmitting side, the data is packed into a large struct and is sent in 32bit chunks in quick succession (but with a short pause between each) then, after a longer pause, the next batch of packets is sent and so on.
On the receiver side, on receiving the first packet in a batch, it starts a timer and loads that packet into the receiving struct. It then loads subsequent packets into the struct, at the appropriate position, until the last one of that batch has been received. Then the struct is processed. However, if, within a timeout period, not all of the expected number packets have been received, the current receive attempt is abandoned and it simply waits for the first packet in the next batch.
The timeout period is somewhat less than the pause between batches on the transmitting side.