ATtiny пишет массивы с неправильными значениями | Arduino IDE | TinyWireM

Это мой первый вопрос, и я надеюсь, что я не наступлю ни на кого:-)

В настоящее время я работаю над модульной системой управления батареями для моего электрического скутера, основанной на ATtiny85 в качестве мастера и нескольких ATtiny85 в качестве рабов. Каждый ведомый контролирует одну ячейку (или множество параллельных ячеек), а также использует эту ячейку для включения питания. В целях безопасности он считывает напряжение батареи и считывает датчик температуры этого элемента. Он отправляет эти две информации через изолированную шину I2C ведущему устройству, которое проанализирует его и в конечном итоге отправит ответ, если эта ячейка должна активировать балансировку или нет.

Для этого я использую загрузчик digispark и перепрошиваю ПО через USB. Само программное обеспечение я программирую, используя Arduino IDE.

До сих пор мне удалось установить хорошую связь между подчиненными, использующими TinyWireS, и Master, использующими TinyWireM. Я успешно отправляю данные от нескольких ведомых устройств к ведущему и наоборот.

Но когда я удаляю одного или нескольких ведомых из шины, программа чтения каким-то образом заполнит не полученные данные предыдущими полученными данными и не запишет пустую строку или ноль.

Вот соответствующая процедура, где я опрашиваю адреса подчиненных устройств и индивидуально запрашиваю у каждого ведомого полезную нагрузку в 4 байта. Подчиненное устройство будет разделять измеренное напряжение и температуру по два байта каждый и отправлять полученные 4 байта отдельно по шине I2C.

Мастер получит 4 отдельных байта и снова объединит их с напряжением и температурой и запишет их в массив в позиции, соответствующей номеру ячейки.

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;
    }

Небольшой пример, демонстрирующий ошибку: на шине должно быть 14 ведомых (CELL_COUNT = 14), один или несколько ведомых (скажем, 5 и 6) имеют ошибку и не передают 4 байта. Таким образом, мастер отображает все данные ведомого на маленьком OLED-дисплее. Вместо отображения 0 в строках с номерами 5 и 6 мастер отображает то же значение числа 4.

Первая половина дисплея будет выглядеть примерно так:

4125
4035
4156
4137
4137
4137
4089

Кроме того, вы можете найти полный код ниже:

//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();
}

Я надеюсь, что кто-то может указать мне правильное направление, чтобы решить эту проблему...

2 ответа

Решение

Я обнаружил небольшое неудобство в lib TinyWireM. Если вы получите некоторые данные, библиотека сохранит их в буфере. Если вы прочитаете буфер, он покажет содержимое. Если новых данных не получено, буфер останется как есть, и вы будете читать те же самые данные, если будете снова читать буфер.

Для этого я изменил TinyWireM.ccp, чтобы буфер был удален, если он будет прочитан один раз.

Теперь он покажет 0, если вы снова прочитаете буфер без новых полученных данных.

Я немного сузил его... В следующем коде функция TinyWireM записывает данные из цикла перед переменными v_high, v_low, T_high и t_low, если новые данные не получены. Но утомленная вещь в том, что они не все равны, все они имеют одинаковое значение из цикла перед. Итак, v_high (старый) = v_high (новый) и так далее.

Как это может быть, если все они установлены с использованием одной и той же функции, которая должна выполняться 4 раза, то есть один раз для каждой переменной?

Вот соответствующая часть:

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
Другие вопросы по тегам