its my first question here and I hope I'm not stepping on anyone's tows :-)
Currently I'm working on a modular battery management system for my electric scooter, based on a ATtiny85 as a master and multiple ATtiny85 as slaves. Each slave is monitoring one cell (or a array of multiple cells in parallel) and also using this cell to power itself up. For safety it reads the voltage of the battery and reads a temperature sensor of this cell. It sends these two information via a isolated I2C bus to the master, which will analyze it and will send eventual a response if this cell should activate balancing or not.
Therefor I'm using the digispark bootloader and flashing the software using USB. The software itself I'm programming using Arduino IDE.
So far I managed to establish a good connection between the slaves using TinyWireS and the Master using TinyWireM. I'm successfully sending data from multiple slaves to the master and vise versa.
But when I remove one or more slaves from the bus somehow the reading routine will fill the not received data with the previous received data and will not write a empty line or zero.
Here is the relevant routine, where I poll through the slaves addresses and individually ask each slave for a payload of 4 bytes. The slave will separate the measured voltage and the temperature in two bytes each and will send the resulting 4 bytes separately over the I2C bus.
The master will receive the 4 separate bytes and combine them again to voltage and temperature and write them in an array at the position matching its cell-number.
for (int cell_num = 1; cell_num <= CELL_COUNT; cell_num++) //poll data from all cells, start with cell 1 to max
{
int slave_add = 0x3F+cell_num; //connect to cell, adress offset 0x3F, first cell is 0x40
v_data[cell_num] = 0;
t_data[cell_num] = 0;
TinyWireM.requestFrom(slave_add, 4); //request from selected cell 4 bytes
while(TinyWireM.available())
{
v_low = TinyWireM.receive(); //read first byte as low byte of voltage
v_high = TinyWireM.receive(); //read second byte as hight byte of voltage
t_low = TinyWireM.receive(); //read third byte as low byte of temp
t_high = TinyWireM.receive(); //read fourth byte as hight byte of temp
v_data[cell_num] = 0;
t_data[cell_num] = 0;
v_data[cell_num] = (v_high<<8) | v_low; //shift high byte of voltage and combine with low byte
t_data[cell_num] = (t_high<<8) | t_low; //shift high byte of temp and combine with low Byte
v_high = 0;
v_low = 0;
t_high = 0;
t_low = 0;
}
A little example to demonstrate the error: On the bus are supposed to be 14 slaves (CELL_COUNT = 14) one or more slaves (lets say number 5 & 6) is having an error and is not transmitting the 4 bytes. So the master is displaying all the data of the slave on a little OLED Display. Instead of showing a 0 at the line number 5 and 6 the master displays the same value of number 4.
The first half of the display will look something like this:
4125
4035
4156
4137
4137
4137
4089
In addition you can find the full code below:
//1MHz Speed!!!!
#include <TinyWireM.h>
#include "SSD1306_minimal.h"
#define CELL_COUNT 14 //from 1 to cell amout, number of cells on bus
SSD1306_Mini oled;
uint16_t v_data[CELL_COUNT];
uint16_t v_data_max = 0;
uint16_t t_data[CELL_COUNT];
uint16_t t_data_max = 0;
char cast1[8] = {};
char cast2[8] = {};
uint8_t v_low;
uint8_t v_high;
uint8_t t_low;
uint8_t t_high;
void setup()
{
pinMode(1, OUTPUT); //led pinset digispark
digitalWrite(1, LOW); //disable led
oled.init(0x3c); //init oled adress 0x3c
oled.clear(); //clear oled display
oled.startScreen(); //start oled routine to write
TinyWireM.begin(); //start i2c lib for com
}
void loop()
{
v_data_max = 0;
t_data_max = 0;
//read received data
for (int cell_num = 1; cell_num <= CELL_COUNT; cell_num++) //poll data from all cells, start with cell 1 to max
{
int slave_add = 0x3F+cell_num; //connect to cell, adress offset 0x3F, first cell is 0x40
v_data[cell_num] = 0;
t_data[cell_num] = 0;
TinyWireM.requestFrom(slave_add, 4); //request from selected cell 4 bytes
while(TinyWireM.available())
{
v_low = TinyWireM.receive(); //read first byte as low byte of voltage
v_high = TinyWireM.receive(); //read second byte as hight byte of voltage
t_low = TinyWireM.receive(); //read third byte as low byte of temp
t_high = TinyWireM.receive(); //read fourth byte as hight byte of temp
v_data[cell_num] = 0;
t_data[cell_num] = 0;
v_data[cell_num] = (v_high<<8) | v_low; //shift high byte of voltage and combine with low byte
t_data[cell_num] = (t_high<<8) | t_low; //shift high byte of temp and combine with low Byte
v_high = 0;
v_low = 0;
t_high = 0;
t_low = 0;
}
}
for (int cell_num = 1; cell_num <= CELL_COUNT; cell_num++) //pring voltage and temp data to oled
{
oled.startScreen(); //start oled routine to write
if (cell_num<=7) //check if first half of cells (cell number = 14) or second half
{
oled.cursorTo(0,cell_num-1); //jump to right line for cell
}
else
{
oled.cursorTo(66,cell_num-8); //jump to right line for cell
}
oled.printString(itoa(v_data[cell_num], cast1, 10)); //change data from int to str and print on oled
oled.startScreen();
if (cell_num<=7)
{
oled.cursorTo(30,cell_num-1); //jump to right line for cell
}
else
{
oled.cursorTo(96,cell_num-8); //jump to right line for cell
}
oled.printString(itoa(t_data[cell_num], cast2, 10)); //change data from int to str and print on oled
}
delay(5000);
oled.cursorTo(0,0);
oled.clear();
}
I hope someone can point me in the right direction to fix this problem...