View Single Post
Old 04-19-2014, 01:15 AM   #42 (permalink)
mechman600
Master EcoModder
 
mechman600's Avatar
 
Join Date: Jul 2008
Location: Langley, BC
Posts: 1,228

Fusion - '16 Ford Fusion Hybrid SE
Thanks: 190
Thanked 275 Times in 168 Posts
I have been testing different types of Arduino to Arduino communication in an attempt to find the best way to use multiple boards for BMS and sending the voltage measurements to a master board. Once we can get a bunch of accurate voltages (18 in TurnNBurn's case) to the Master board, it isn't difficult to switch a charger relay off or set off DEFCON 1 low voltage warnings while driving.

Methods:
1. PWM/duty cycle two way communication (inquire & read/respond & send)
2. Two way serial communication (inquire & read/respond & send)
3. One way serial communication (read & decipher/broadcast)

Side note: I am testing with four analog inputs - two 5K pots and two LM34 temperature sensors. I was having trouble with erratic ADC readings with multiple inputs. Example: when adjusting one of the pots up and down, one of the temperature readings would always go wonky.

What I discovered is that the MCU really has only one ADC and it is mulitplexed to 8 inputs. Since the ADC is not digital it can get residual data left on it that is then picked up by the next read, throwing it off. All I had to do to fix this is do two analog reads and chuck the first one, similar to burning a card in Texas Hold Em:

Quote:
analogRead(potPin1);
int raw_adc1 = analogRead(potPin1);
1. PWM/Duty Cycle Communication

The master sends a PWM instruction (inquiry), waits and then reads:

Quote:
analogWrite(ComToSlave, 100); //send PWM inquiry to Slave
delay(30); //wait a moment
int adc1_COM = pulseIn(ComToMaster, HIGH); //measure returned PWM data

analogWrite(ComToSlave, 150);
delay(30);
int adc2_COM = pulseIn(ComToMaster, HIGH);

analogWrite(ComToSlave, 200);
delay(30);
int adc3_COM = pulseIn(ComToMaster, HIGH);

analogWrite(ComToSlave, 250);
delay(30);
int adc4_COM = pulseIn(ComToMaster, HIGH);
The slave reads instructions and writes PWM values to the master accordingly:

Quote:
int instru = pulseIn(ComToSlave, HIGH); //measure PWM inquiry
if(instru > 600 && instru < 1000) { //if inquiry is in this range....
analogWrite(ComToMaster, adc1_COM); //...write PWM value of adc1_COM

} else if (instru > 1000 && instru < 1400) {
analogWrite(ComToMaster, adc2_COM);

} else if (instru > 1400 && instru < 1800) {
analogWrite(ComToMaster, adc3_COM);

} else if (instru > 1800 && instru < 2200) {
analogWrite(ComToMaster, adc4_COM);

} else {
digitalWrite(ComToMaster, LOW); //inquiry failure failsafe
}
Pros: data is always allocated to the proper address.
Cons: data is reduced to 8-bit PWM (256 steps); erratic and jittery.
Conclusion: FAIL.

2. Two Way Serial Communication

The master sends a serial instruction (inquiry), waits and then reads serial data:

Quote:
while(Serial.available() > 0) {

Serial.println(1); //send value of 1 to Slave
delay(1); //wait a moment
adc1 = Serial.parseInt() / 204.8; //read serial data and call it adc1
Serial.read(); //clear the serial buffer

Serial.println(2);
delay(1);
adc2 = Serial.parseInt() / 204.8;
Serial.read();

Serial.println(3);
delay(1);
adc3 = Serial.parseInt() / 2.05;
Serial.read();

Serial.println(4);
delay(1);
adc4 = Serial.parseInt() / 2.05;
Serial.read();
The slave reads the serial instructino and writes ADC values to serial bus accordingly:

Quote:
while(Serial.available() > 0) {
command = Serial.parseInt(); //inquiry sent by Master
Serial.read(); //clear the serial buffer
}
if(command == 1) { //if Master says "1", print adc1 value
Serial.println(adc1);
}
if(command == 2) {
Serial.println(adc2);
}
if(command == 3) {
Serial.println(adc3);
}
if(command == 4) {
Serial.println(adc4);
}
Pros: data is very accurate, no jittering.
Cons: data rarely arrives at the correct address. Ex..data is usually shuffled to the incorrect address on the Master. Unplugging both boards and restarting sometimes corrects this. Sometimes.
Conclusion: FAIL.

3. One way serial communication

The Slave throws all ADC data onto the serial bus with a letter preceding it to give it an address that the slave can understand:

Quote:
// Slave Sender

// Data Buffering Parameters
const byte sampleRate = 10; // number of samples
const byte buffer = 25; // buffer delay() time

int raw_adc[5];
int adc[5];

void setup() {
pinMode(0, INPUT); // set up input pins
pinMode(1, INPUT);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
Serial.begin(1200);
}
void loop() {
int raw_sample[] = {0, 0, 0, 0, 0};
for(int x = 0; x < 5; x++) {
analogRead(x); // read ADC + burn the first one
raw_adc[x] = analogRead(x); // read ADC a second time & keep it
}
for(int i = 0; i < sampleRate; i++) { // Data buffering/averaging loop
raw_sample[0] = raw_sample[0] + raw_adc[0];
raw_sample[1] = raw_sample[1] + raw_adc[1];
raw_sample[2] = raw_sample[2] + raw_adc[2];
raw_sample[3] = raw_sample[3] + raw_adc[3];
raw_sample[4] = raw_sample[4] + raw_adc[4];
delay(buffer);
}
for(int i = 0; i < 5; i++) {
adc[i] = raw_sample[i] / sampleRate; // Data average from above loop
char address = 'a' + i; // Create broadcast character address
Serial.write(address); // Broadcast address...
Serial.write(lowByte(adc[i])); // ...followed by corresponding data low..
Serial.write(highByte(adc[i])); // ...and data high
}
The Master reads the serial bus and deciphers the data, allocating it to the correct address:

Quote:
while(Serial.available() > 2) { // wait for first 2 bytes
comm_in = Serial.read();
if(comm_in == 'a') { // if address broadcast is 'a', the data must be adc[0]
adc[0] = Serial.read(); // read low byte
adc[0] += Serial.read()<<8; //read high byte
}
if(comm_in == 'b') {
adc[1] = Serial.read();
adc[1] += Serial.read()<<8;
}
if(comm_in == 'c') {
adc[2] = Serial.read();
adc[2] += Serial.read()<<8;
}
if(comm_in == 'd') {
adc[3] = Serial.read();
adc[3] += Serial.read()<<8;
}
if(comm_in == 'e') {
adc[4] = Serial.read();
adc[4] += Serial.read()<<8;
}
Pros: data is quick and accurate with no jitter. Data is always allocated to the proper address.
Cons: none. Less control over data flow?
Conclusion: SUCCESS.

Last edited by mechman600; 04-20-2014 at 10:44 PM..
  Reply With Quote