I'm working on a little project to get data from Acuity Battery Monitoring System from Curtis. I'm receiving all the data that I need correctly and converting the values to show the actual battery voltage, current and temperature. I want to mock this code on an Uno because the unit is on site and I need to work from home on it, So the idea is to make a mock up unit so I can carry on working on the project at home as I need to add or stuff and send this data to a server.
Master unit will be an EPS32 and slave ( Acuity mock).
My aim is to send the exact same data format that I get form the Acuity Battery Monitoring from the uno through canbus to the master, My thoughts/idea is where I can adjust the decimal value the convert it back into the exact data format.
So the 2 first bytes 0XB6 and 0XB0 once converted reads 29.98, I want to adjust the 29 and convert it back to HEX format before sending it back out onto the canbus.
The code below is a working sample data coming in with known values where I convert it to a readable format.
uint32_t identifier = 426; //olny get data from this address
uint16_t voltage = 0;
byte rx_frame[8] = {0XB6, 0X0B, 0XC5, 0X01, 0XC5, 0X0B, 0XB1, 0X00};//incoming data from Acuity Battery Monitoring Systembattery monitor
int16_t current = 0, temperature = 0;
float voltagefloat = 0, currentfloat = 0, temperaturefloat = 0;
void setup() {
// start Serial communication
Serial.begin(9600);
voltage = (rx_frame[1] << 8) + rx_frame[0]; //convert to decimal
current = (rx_frame[3] << 8) + rx_frame[2]; //convert to decimal
temperature = (rx_frame[5] << 8) + rx_frame[4];//convert to decimal
voltagefloat = voltage * 0.01; // value to times by
currentfloat = current * 0.01; // value to times by
temperaturefloat = temperature * 0.01; // value to times by
Serial.print("Voltage = ");
Serial.print(voltagefloat);
Serial.print(" , Current = ");
Serial.print(currentfloat);
Serial.print(" , temperature = ");
Serial.println(temperaturefloat);
}
void loop() {
}
So the question is how do I convert the flaot back to HEX format like this
Looks like the data is sent as 16-bit integers, little endian, with the integers representing the value in hundredths. What are the last two bytes used for?
Hi sorry I forgot to attach a picture of the data format.
byte 1&2 are battery voltage,byte 3&4 are battery current,byte 5&6 are temperature byte 7 not used and byte 8 is the state of discharge(SoC).
Yes tehy are 16 bit integer.
I've looked at tried your code, And just working on the voltage side of things first and this is what I get from the serial port.
Voltage = 29.98 , Current = 4.53 , temperature = 30.13
, LOW BYTE HEX = B6
, HIGH BYTE HEX = B
, LOW BYTE INT = 182
, HIGH BYTE INT = 11
latest code:
uint32_t identifier = 426; //olny get data from this address
uint16_t voltage = 0;
byte rx_frame[8] = {0XB6, 0X0B, 0XC5, 0X01, 0XC5, 0X0B, 0XB1, 0X00};//incoming data from battery monitor
int16_t current = 0, temperature = 0;
float voltagefloat = 0, currentfloat = 0, temperaturefloat = 0;
void setup() {
// start Serial communication
Serial.begin(9600);
voltage = (rx_frame[1] << 8) + rx_frame[0]; //convert to decimal
current = (rx_frame[3] << 8) + rx_frame[2]; //convert to decimal
temperature = (rx_frame[5] << 8) + rx_frame[4];//convert to decimal
voltagefloat = voltage * 0.01; // value to times by
currentfloat = current * 0.01; // value to times by
temperaturefloat = temperature * 0.01; // value to times by
Serial.print("Voltage = ");
Serial.print(voltagefloat);
Serial.print(" , Current = ");
Serial.print(currentfloat);
Serial.print(" , temperature = ");
Serial.println(temperaturefloat);
uint16_t value = voltagefloat *100;
uint8_t lowb= value ;
uint8_t highb = value >>8;
Serial.print(" , LOW BYTE HEX = ");
Serial.println(lowb,HEX);
Serial.print(" , HIGH BYTE HEX = ");
Serial.println(highb,HEX);
Serial.print(" , LOW BYTE INT = ");
Serial.println(lowb);
Serial.print(" , HIGH BYTE INT = ");
Serial.println(highb);
}
void loop() {
}
So that looks correct bu how can I add those to a char to send out the correct format like 0XB6 and 0X0B so that I can get to then send it over Canbus lines
Since the data is in a nice binary format that is compatible with the UNO, I would not mess with converting the individual bytes. Define a struct that matches the data structure, manipulate the values in that, and send the struct to the CAN bus.
byte rx_frame[8] = {0XB6, 0X0B, 0XC5, 0X01, 0XC5, 0X0B, 0XB1, 0X00};//incoming data from battery monitor
struct {
uint16_t voltage;
int16_t current;
int16_t temperature;
uint8_t unused;
uint8_t stateOfCharge;
} pdo1;
void setup() {
// start Serial communication
Serial.begin(9600);
memcpy(&pdo1, rx_frame, sizeof(pdo1));
Serial.print("Voltage = ");
Serial.print(pdo1.voltage / 100.0);
Serial.print(" , Current = ");
Serial.print(pdo1.current / 100.0);
Serial.print(" , temperature = ");
Serial.print(pdo1.temperature / 100.0);
Serial.print(" , state of charge = ");
Serial.print(pdo1.stateOfCharge);
Serial.println('%');
//print hex values
uint8_t* ptr = (uint8_t*)&pdo1;
for (size_t i = 0; i < sizeof(pdo1); i++) {
if (*ptr < 0x10) Serial.print('0');
Serial.print(*ptr, HEX);
Serial.print(' ');
ptr++;
}
Serial.println();
//change values
pdo1.voltage = 30.01 * 100.0;
pdo1.current = 7.91 * 100.0;
pdo1.temperature = 25.62 * 100.0;
Serial.print("Voltage = ");
Serial.print(pdo1.voltage / 100.0);
Serial.print(" , Current = ");
Serial.print(pdo1.current / 100.0);
Serial.print(" , temperature = ");
Serial.print(pdo1.temperature / 100.0);
Serial.print(" , state of charge = ");
Serial.print(pdo1.stateOfCharge);
Serial.println('%');
//print hex values
ptr = (uint8_t*)&pdo1;
for (size_t i = 0; i < sizeof(pdo1); i++) {
if (*ptr < 0x10) Serial.print('0');
Serial.print(*ptr, HEX);
Serial.print(' ');
ptr++;
}
Serial.println();
//probable way to send data to the can bus
//CAN.write((uint8_t*)&pdo1, sizeof(pdo1));
}
void loop() {
}