I am attempting to send data from an MPU6050 connected to an arduino uno to another uno via CAN bus, however i don't think this is a CAN bus specific issue.
In short, i am sending two packets of 8 bytes in the following formats
Packet 1 - (uint32_t/ int16_t/ int16_t)
Packet 2 - (int16_t/ int16_t/ int16_t/ int16_t)
all converted into bytes in this sort of fashion;
int16_t byte2Int(int16_t output, int pos, uint8_t data[2]){
for (int i = 0; i < 2; i++)
{
output += ((int16_t)data[i + pos]) << (i * 8);
}
return output;
}
where everything should make sense apart from the "int pos" part which is just where in the buffer i want to start putting the data as packet 1 and 2 are different structures.
My issue is that with just one packet, i can print the values just fine, with the second packet added in i get the following on the serial monitor;
AccX AccY AccZ GyX GyY GyZ
16832 -816 928 -440 16832 -816
16984 -940 992 -449 16984 -940
16896 -804 988 -462 16896 -804
209 55 0 0 209 55
16900 -852 1080 -471 16900 -852
16900 -852 1080 -471 16900 -852
16984 -760 948 -481 16984 -760
16880 -824 896 -459 16880 -824
230 102 0 0 230 102
16928 -860 996 -422 16928 -860
16928 -860 996 -422 16928 -860
17004 -856 864 -466 17004 -856
17004 -856 864 -466 17004 -856
214 105 0 0 214 105
16964 -828 944 -446 16964 -828
16964 -828 944 -446 16964 -828
As you can see i get some coherent messages, then some scrambled which don't make sense, then coherent again and the cycle continues. Not sure of relevance, but when i first start the serial monitor this doesn't happen, then after varying time, but around 5 seconds or so, it starts going amiss.
I believe this is down to my programming, and me not being able to code in a reliable way to wait for the first message to complete, then send the next one and them being read correctly. Below is my embarrassing attempt at sending an ACK message to the sender to say that the message has been received and to progress to the next message. I am not a programmer by nature and i am putting up this shoddy code that i've spent days trying to sort in the hope someone can point me in the right direction.
Apologies in advance.
// CAN Send Example
//
#include <mcp_can.h>
#include <SPI.h>
#include <Wire.h>
const int MPU_addr = 0x68; // I2C address of the MPU-6050
uint32_t TimeMicro;
int16_t AccX, AccY, AccZ, Tmp, GyX, GyY, GyZ;
int8_t data1[8], data2[8], rxBuf[8];
int Switch = 7;
long unsigned int rxId;
unsigned char len = 0;
#define CAN0_INT 2 // Set INT to pin 2
MCP_CAN CAN0(10); // Set CS to pin 10
void setup()
{
Serial.begin(115200);
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
else Serial.println("Error Initializing MCP2515...");
CAN0.setMode(MCP_NORMAL); // Change to normal mode to allow messages to be transmitted
pinMode(Switch, OUTPUT);
digitalWrite(Switch, HIGH);
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
}
void loop()
{
TimeMicro = millis();
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers
AccX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
AccY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
AccZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
Tmp = Wire.read() << 8 | Wire.read();
GyX = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
GyY = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
GyZ = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
double2Byte(TimeMicro, 0, data1);
int2Byte(AccX, 4, data1);
int2Byte(AccY, 6, data1);
int2Byte(AccZ, 0, data2);
int2Byte(GyX, 2, data2);
int2Byte(GyY, 4, data2);
int2Byte(GyZ, 6, data2);
// send data: ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
byte sndStat = CAN0.sendMsgBuf(0x100, 0, 8, data1);
if(!digitalRead(CAN0_INT)) // If CAN0_INT pin is low, read receive buffer
{
CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
while(rxBuf[0] != 0x0A)
{
continue;
}
}
delay(10);
byte sndStat2 = CAN0.sendMsgBuf(0x100, 0, 8, data2);
while(rxBuf[0] != 0x0A)
{
continue;
}
for(int i = 0; i < 8; i++)
{
data1[i] = 0;
data2[i] = 0;
}
}
//===================================================================================
// FUNCTIONS
//===================================================================================
uint8_t int2Byte(int16_t input, int pos, uint8_t data[2]){
for (int i = 0; i < 2; i++)
{
data[i+ pos] = ((input >> (i * 8)) & 0xff);
}
return data[2];
}
uint8_t double2Byte(uint32_t input, int pos, uint8_t data[4]){
for (int i = 0; i < 4; i++)
{
data[i+ pos] = ((input >> (i * 8)) & 0xff);
}
return data[4];
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/
Receiver
// CAN Receive Example
//
#include <mcp_can.h>
#include <SPI.h>
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf1[8];
unsigned char rxBuf2[8];
unsigned char txBuf[8];
char msgString[128]; // Array to store serial string
uint32_t TimeMicro;
int16_t AccX, AccY, AccZ, GyX, GyY, GyZ;
#define CAN0_INT 2 // Set INT to pin 2
MCP_CAN CAN0(10); // Set CS to pin 10
void setup()
{
Serial.begin(115200);
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK)
Serial.println("MCP2515 Initialized Successfully!");
else
Serial.println("Error Initializing MCP2515...");
CAN0.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.
pinMode(CAN0_INT, INPUT); // Configuring pin for /INT input
Serial.println("MCP2515 Library Receive Example...");
}
void loop()
{
if(!digitalRead(CAN0_INT)) // If CAN0_INT pin is low, read receive buffer
{
CAN0.readMsgBuf(&rxId, &len, rxBuf1); // Read data: len = data length, buf = data byte(s)
}
for(int i; i < 8; i++){
txBuf[i] = 0x0A;
}
byte sndStat = CAN0.sendMsgBuf(0x101, 0, 8, txBuf);
if(!digitalRead(CAN0_INT)) // If CAN0_INT pin is low, read receive buffer
{
CAN0.readMsgBuf(&rxId, &len, rxBuf1); // Read data: len = data length, buf = data byte(s)
}
byte sndStat2 = CAN0.sendMsgBuf(0x101, 0, 8, txBuf);
TimeMicro = byte2Double(TimeMicro, 0, rxBuf1);
AccX = byte2Int(AccX, 4, rxBuf1);
AccY = byte2Int(AccY, 6, rxBuf1);
AccZ = byte2Int(AccZ, 0, rxBuf2);
GyX = byte2Int(GyX, 2, rxBuf2);
GyY = byte2Int(GyY, 4, rxBuf2);
GyZ = byte2Int(GyZ, 6, rxBuf2);
Serial.print(TimeMicro);
Serial.print("\t");
Serial.print(AccX);
Serial.print("\t");
Serial.print(AccY);
Serial.print("\t");
Serial.print(AccZ);
Serial.print("\t");
Serial.print(GyX);
Serial.print("\t");
Serial.print(GyY);
Serial.print("\t");
Serial.println(GyZ);
TimeMicro = 0;
AccX = 0;
AccY = 0;
AccZ = 0;
GyX = 0;
GyY = 0;
GyZ = 0;
}
//===================================================================================
// FUNCTIONS
//===================================================================================
uint32_t byte2Double(uint32_t output, int pos, uint8_t data[4]){
for (int i = 0; i < 4; i++)
{
output += ((uint32_t)rxBuf1[i + pos]) << (i * 8);
}
return output;
}
int16_t byte2Int(int16_t output, int pos, uint8_t data[2]){
for (int i = 0; i < 2; i++)
{
output += ((int16_t)rxBuf1[i + pos]) << (i * 8);
}
return output;
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/
I've tried debugging this by the following;
- check that the MPU is sending correctly (Fine)
- check if it happens with just one packet (no problems)
- check if the packets are assembled correctly on the sender ( got the data, broke it into bytes and reassembled and printed that result. did what i expected)
- removed time from being sent incase that was causing an issue (same problem as illustrated above)
- removed all serial prints and just did one value (still an issue)
So i believe that it is down to a terrible and non working attempt at sending an acknowledgment message. I have tried researching but i couldn't find an example for CAN bus, and all the others were using protocol specific interrupt routines which i tried to implement but didn't work. obviously.
Thankyou for your patience