Hey guys,
I could need some advice with my project mentioned in the subject.
I know, I could just use an already known serial communication protocol like I2C, but this is not my goal.
I would like to build up a communication between different microcontrollers without any already provided function
and understand which difficulties one could experience when trying to develop something like that.
Some ideas for the communication protocol are based on I2C and before posting code,
I would like to explain the basic idea. There are 2 arduinos (1x transceiver and 1x receiver) connected to each other through 4 cables. The receiver is an Arduino Mega 2560 from Elegoo and the transceiver is an Arduino Uno with Atmega328P-PU.
Two cables represent SCL and SDA. One is connecting ground of both of them and another one is just for debugging purposes and acts like a status pin. The status pin tells the transceiver, when it has to send a new message.
These cables are directly connected to arduinos.
I would like to change this in the future by using pullup resistors with an external voltage source but not yet.
So, let's have a look at how my messages are constructed at the moment (attachment "signal_message_BITS.PNG"):
As you can see, a new message always starts by a falling edge. Before that SCL and SDA were HIGH.
Afterwards SCL is always changing whenever a new bit should be read. A message has a size of 8 bits.
Now let's have a look on the whole code for the receiver part.
The transceiver is just sending signals in the above described pattern. Therefore I have not considered to post this code, too.
But, if this would be interesting for you, just let me know and I will post it afterwards immediately.
I don't want to exaggerate the topic already at the beginning.
The receiver code:
bool recvSDA;
bool recvSCL;
unsigned long numMsg = 0;
unsigned long errorCounter = 0;
bool recvMsg = false;
byte counter = 0;
bool lastSCL;
bool isMsgReceived = false;
byte recvBits;
byte lastBits;
void setup() {
Serial.begin(2000000);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Set status pin to zero at startup:
DDRG |= B00100000;
PORTG &= ~B00100000;
}
void loop() {
if (recvMsg == false) {
// If ready for a new message, set status pin to one:
PORTG |= B00100000;
// Since we are waiting for a new message, start a while loop for signal detection:
while (1) {
// Read out SCL and SDA with register manipulation:
recvSDA = PINE & 1 << 3;
recvSCL = PINH & 1 << 3;
// As soon as a new message is recognized and incoming, prepare all required variables:
if (recvSDA == HIGH && recvSCL == LOW && recvMsg == false) {
counter = 0;
++numMsg;
recvBits = 0;
recvMsg = true;
// The status pin can be set to low:
PORTG &= ~B00100000;
continue;
}
// This section is detecting all HIGH bits and saving them:
if (recvMsg == true && counter <= 7 && (recvSCL - lastSCL) != 0) {
lastSCL = recvSCL;
if (recvSDA == HIGH) {
recvBits = recvBits | 1 << (7 - counter);
}
++counter;
}
// As soon as 8 bits were received, start the end procedure for the message:
if (recvMsg == true && counter > 7) {
if (recvSCL == HIGH && recvSDA == HIGH) {
if (isMsgReceived == false) {
lastBits = recvBits;
isMsgReceived = true;
}
// For debugging purposes we are sending the exact same message all the time.
// Therefore changes between several messages should be zero.
// If not, we are going to detect this by the following pattern:
errorCounter += (lastBits != recvBits);
recvMsg = false;
lastBits = recvBits;
// After a predefined number of messages, print out the status.
// If you are doing it every cycle, the datarate will decrease a lot!
if (numMsg % 10000 == 0) {
Serial.print(numMsg); Serial.print(", "); Serial.print(errorCounter); Serial.print(", "); Serial.println(recvBits, BIN);
}
break;
}
}
}
}
}
I hope, it is readable for you. Just let me know, if you have advices for better readability.
As you can see, at the beginning of every loop(..) I'm setting the status pin to HIGH, so the transceiver should start sending a new message. Afterwards I'm starting an infinite while loop which is looping all the time to receive any transmitted signal.
I used the while loop instead of the loop(..) function of arduino to make sure, I'm not losing to much time between every new loop.
With the loop(..) function I have experienced that there is sometimes a big delay between two loops which are not always constant and disturbed the receiving procedure and led to loosing some bits. Therefore my decision to execute the signal detection with a while loop.
Though I have a feeling that using a while loop and trying to detect an incoming message with this pattern is probably not the best approach.
I have read about interrupts and their different detection possibilities, but I don't know if this is the fastest way to detect messages.
Is their any way to improve the speed of detecting new incoming messages? Are interrupts the fastest way of detection or is a while loop constructed like described above also a possible and fast way detecting new messages?
Let me know, if you have any advice for me!
I'm especially interested on hints which are explaining me some new aspects I have not considered till now.
Thank you for your time! I know, all of you are doing this in your freetime, therefore: every help is much appreciated.
Best regards,
Kerby
PS: I also uploaded the output in serial monitor (see "serialMonitor_output.PNG").
At the moment the communication works well, but I'm working on to improve the data rate of the system.