Запись и обработка номеров DS18b20 в его EEPROM

valiktom
Offline
Зарегистрирован: 19.12.2016
#include <OneWire.h>

#define NumPin 70 //колличество пинов на используемой плате ардуино (для примера - MEGA)(Uno=20)
#define NumConfigPin 69 //(A15)//выделенный пин для программирования номеров датчиков(Uno=19-(A5))
int NumSens;//колличество обнаруженых датчиков
boolean PinNumSens[NumPin - 3];//массив задействованных(true) или нет(false) пинов для датчиков(не включая пин 0 и 1 UART и выделенный пин)
unsigned long timeSens;//время события
int diftime = 0;//разница времени между двумя событиями
boolean ReadSens = false;//признак чтения\записи датчика

void setup() {
  Serial.begin(9600);
  Serial.println(F("Start Search for Sensors:"));
  SearchNumSens();
}

void loop() {

  if (Serial.available()) {
    String SerialRead = Serial.readString();
    if (SerialRead == "s") {//поиск числа датчиков и задействованных пинов
      SearchNumSens();
    }
    else {//запись номера датчика в его EEPROM на выделенном пине NumConfigPin
      int Num = SerialRead.toInt();
      Serial.print(F("Sensors Number Recording: #"));
      Serial.print(Num);
      if (Num < 1) {
        Serial.println(F(" Number Error"));
      }
      else if (NumConfigSens(Num)) {
        Serial.println(F(" OK"));
      }
      else {
        Serial.println(F(" Error"));
      }
    }
  }
  //что-бы не мешало переполнение millis
  if (timeSens > millis()) {
    diftime = int(4294967295 - timeSens + millis());
  }
  else {
    diftime = int(millis() - timeSens);
  }

  if (ReadSens == false) {
    for (byte i = 2; i < NumConfigPin; i++) {
      if (PinNumSens[i - 2] == true) {
        OneWire  ds(i);
        // обращение ко всем датчикам шины сразу:
        ds.reset();//сброс шины
        ds.write(0xCC);//Игнорировать адрес
        ds.write(0x44);//начать преобразование температуры(без паразитного питания)
      }
    }
    ReadSens = true;
    timeSens = millis();
  }
  else if (ReadSens == true && diftime >= 1000) {//1000ms(с запасом)-т.к. время преобразования =750ms для
    // default value of Config = 0x7F (user byte 3)

    int Sensor[NumSens][3];//значения опроса датчиков
    int N = 0;//число корректно ответивших датчиков
    for (byte n = 2; n < NumConfigPin; n++) {
      if (PinNumSens[n - 2] == true) {
        OneWire  ds(n);
        byte addr[8];
        while (N <= NumSens) {
          if ( !ds.search(addr)) {
            break;
          }
          for (byte c = 0; c < 2; c++) {
            byte present = ds.reset();//признак готовности датчика к ответу
            ds.select(addr);
            ds.write(0xBE);//Чтение памяти
            byte data[9];
            for (byte d = 0; d < 9; d++) {
              data[d] = ds.read();
            }
            byte CRC = OneWire::crc8(data, 8);
            if (CRC == data[8] && present == 1 && CRC != 0) {//ответ корректный
              if (N < NumSens) {
                Sensor[N][0] = data[0];
                Sensor[N][1] = data[1];
                Sensor[N][2] = data[3] * 10 + data[2];//номер датчика
              }
              N++;
              break;
            }
            else if (c == 0) {//датчик отсутсвует или мусор
              Serial.println(F("CRC!"));
              delay(100);
            }
            else {
              Serial.println(F("Sensors CRC Error"));
            }
          }
        }
        if (N > NumSens) {
          break;
        }
      }
    }
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // просто пример обработки показаний датчиков,
    // если их нумерация непрерывная с первого номера,
    // хотя не обязательно - тогда каждый отдельно,
    // а номера должны быть любые неповторяющиеся
    for (int SensorN = 1; SensorN <= NumSens; SensorN++) {
      int16_t DataT = DataSens(SensorN, Sensor);
      if (DataT == -1000) {
        Serial.print(F("Error"));
      }
      else {
        double SensT = (double)DataT / 16.0;//для библиотеки PID например
        Serial.print(SensT);
        Serial.print(F("*C"));
      }
      Serial.print(F(" Sensor #"));
      Serial.println(SensorN);
    }
    Serial.println();
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    if (N > NumSens) {
      Serial.println(F("Find New Sensor. Start Search:"));
      SearchNumSens();
    }
    ReadSens = false;
  }
}
//=========================================================
//поиск нужного значения температуры в массиве по номеру датчика
int16_t DataSens(int SensorN, int Sensor[][3]) {
  int16_t rawData = -1000;//любое нереальное значение
  for (byte i = 0; i < NumSens; i++) {
    if (Sensor[i][2] == SensorN) {
      rawData = (Sensor[i][1] << 8) | Sensor[i][0];
      break;
    }
  }
  return rawData;
}
//=========================================================
//запись номера датчика в его EEPROM
boolean NumConfigSens(int NumConfig) {
  byte v1 = NumConfig % 10;
  byte v2 = (NumConfig - v1) / 10;
  OneWire  ds(NumConfigPin);
  ds.reset();//сброс шины
  ds.write(0xCC);//Игнорировать адрес
  ds.write(0x4E);//разрешение записать конфиг //write scratchpad (starts at byte 2)
  ds.write(v1);//value of user byte 1
  ds.write(v2);//value of user byte 2
  ds.write(0x7F);//default value of Config = 0x7F (user byte 3)//точность преобразования
  ds.reset();//сброс шины - обязательно до задания следующей комманды копирования в EEPROM
  ds.write(0xCC);//Игнорировать адрес
  ds.write(0x48);// копируем три байта в EEPROM DS18B20, чтобы сохранить постоянно
  delay(20);//ждём, пока закончит запись
  ds.reset();//сброс шины - обязательно до задания следующей комманды копирования в ОЗУ
  ds.write(0xCC);//Игнорировать адрес
  ds.write(0xB8);//Данные перезагружены из EEPROM в ОЗУ
  ds.reset();//сброс шины - обязательно до задания следующей комманды чтения из ОЗУ
  ds.write(0xCC);//Игнорировать адрес
  ds.write(0xBE);//Чтение памяти - нам нужны только байт 2,3
  ds.read();//нам не нужен(0)
  ds.read();//нам не нужен(1)
  if (ds.read() == v1 && ds.read() == v2) {
    return true;
  }
  else {
    return false;
  }
}
//=========================================================
//поиск числа датчиков и задействованных пинов
void SearchNumSens() {
  NumSens = 0;
  byte addr[8];
  for (byte n = 2; n < NumConfigPin; n++) {
    PinNumSens[n - 2] = false;
    OneWire  ds(n);
    while (true) {
      if ( !ds.search(addr)) {
        break;
      }
      Serial.print(F("Pin #"));
      Serial.print(n);
      Serial.print(F(":\r\nROM = "));
      for (byte i = 0; i < 8; i++) {
        Serial.print(addr[i], HEX);
        Serial.print(' ');
      }
      if (OneWire::crc8(addr, 7) == addr[7]) {
        ds.reset();//сброс шины - обязательно до задания следующей комманды чтения из ОЗУ
        ds.select(addr);
        ds.write(0xBE);//Чтение памяти - нам нужны только байт 2,3
        ds.read();//нам не нужен(0)
        ds.read();//нам не нужен(1)
        Serial.print(F("Sensor #"));
        Serial.println(ds.read() + ds.read() * 10);
        NumSens++;
        PinNumSens[n - 2] = true;
      }
      else {
        Serial.println(F("Sensors ID Error!"));
      }
    }
  }
  Serial.print(F("\r\nNumber of Sensors = "));
  Serial.println(NumSens);
  Serial.println();
}

 

valiktom
Offline
Зарегистрирован: 19.12.2016

думаю хорошей идеей будет записать в Eeprom датчика его номер

и уже по нему обрабатывать его показания:

1.подключаем датчик к выделенному пину

2.программой записываем в датчик нужный номер

3.помечаем биркой его номер

4.забываем про ID датчиков

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

что вы думаете по этому поводу?

начинайте критиковать...

Logik
Offline
Зарегистрирован: 05.08.2014

А это что за плод сумрачных мыслей?

Зачем искать пины, к которым подключены ds18b20? Вы забыли куда их подключали - дак посмотрите. По хорошему, должна быть схема, где это видно невооруженным глазом, 

А чего спросить то хотели? 

Logik
Offline
Зарегистрирован: 05.08.2014

У датчика уже есть "врожденный" номер. Его адрес, зачем второй в него писать?

ПС. стр39-45 Это чё нафиг такое? Опять переполнение миллиса?! Да сколько ж можна то...

valiktom
Offline
Зарегистрирован: 19.12.2016

поеееехали..

представте себе наладчика.который подготовил датчики(ну сто, например) по номерам,

программу обработки, кабели на проэкте , воткнув их в любой пин...

что осталось? : подключить физически датчики по списку номеров совместив их с местом на проекте...

а поменять датчик? : вписал номер и всё...

а поменять местами, если ошибся?...

или по ID сверять?

а для дома с парой датчиков и городить нечего: записал на бумажке и в прорамму ID и всё...

valiktom
Offline
Зарегистрирован: 19.12.2016

а по поводу миллиса моооожно поподробней? только без обычных грубостей...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Logik пишет:

Опять переполнение миллиса?! Да сколько ж можна то...

А вдруг переполнится? Ужасть-же!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

valiktom пишет:

или по ID сверять?

А чем Ваш номер в епроме лучше его родного номера/адреса? Вот просто - какие выгоды Вы от этого получаете?

Вы собрались приклеивать бирки с номерами, так что мешает приклеивать бирки с адресами?

Logik
Offline
Зарегистрирован: 05.08.2014

valiktom пишет:

а по поводу миллиса моооожно поподробней? только без обычных грубостей...

Дак без грубостей первую полсотню раз было ))) Не помогает, поищите по форуму, оно пару раз в месяц всплывает с завидной регулярностью.

valiktom
Offline
Зарегистрирован: 19.12.2016

ЕвгенийП пишет:

Logik пишет:

Опять переполнение миллиса?! Да сколько ж можна то...

А вдруг переполнится? Ужасть-же!

 

да просто раз в 50 дней будет сбой верности чтения датчика, или я что-то не так понимаю?

а если не критично ,то можно и упростить...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

valiktom пишет:

да просто раз в 50 дней будет сбой верности чтения датчика, или я что-то не так понимаю?

Что-то не так понимаете.

valiktom
Offline
Зарегистрирован: 19.12.2016

ЕвгенийП пишет:

valiktom пишет:

или по ID сверять?

А чем Ваш номер в епроме лучше его родного номера/адреса? Вот просто - какие выгоды Вы от этого получаете?

Вы собрались приклеивать бирки с номерами, так что мешает приклеивать бирки с адресами?

можно теоретически и в бинарном виде номер дома обозначать, только почту перестанете получать...

номер как-то человечней для наладчика...

valiktom
Offline
Зарегистрирован: 19.12.2016

Logik пишет:

valiktom пишет:

а по поводу миллиса моооожно поподробней? только без обычных грубостей...

Дак без грубостей первую полсотню раз было ))) Не помогает, поищите по форуму, оно пару раз в месяц всплывает с завидной регулярностью.

учту,пороюсь...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

valiktom пишет:

номер как-то человечней для наладчика...

А адрес (число от 8 до 127) как-то бесчеловечно? :) Понял.

Предлагаю ещё более человечный вариант: футбольные карточки: на одном датчике Пеле, на другом Кака, на третьем Ахахауи. Ну, или, если наладчики - мужики, то можно фото порнозвёзд использовать. Всяко лучше, чем безликое число :))))

Logik
Offline
Зарегистрирован: 05.08.2014

Да. Колода порнокарт - просто идеально и картон крепкий и идентификаторы какие хочеш, хоть чирва девятка, хоть блондинка в раскаряку.

valiktom
Offline
Зарегистрирован: 19.12.2016

ЕвгенийП пишет:

valiktom пишет:

номер как-то человечней для наладчика...

А адрес (число от 8 до 127) как-то бесчеловечно? :) Понял.

Предлагаю ещё более человечный вариант: футбольные карточки: на одном датчике Пеле, на другом Кака, на третьем Ахахауи. Ну, или, если наладчики - мужики, то можно фото порнозвёзд использовать. Всяко лучше, чем безликое число :))))

а число действительно безликое. т,к ID произвольный, а номер - контролируемый...

и заодно сходите на проект...

и попросите наладчика найти датчик по ID...да даже в списке.

куда он пошлёт?

Logik
Offline
Зарегистрирован: 05.08.2014

Неважно куда пощлет, важно куда пойдет. Выдете ему датчик с порнокартой "блондинка в раскаряку" а в коде, лучше в отдельном файле ашнике, пишете

#define BLONDINKA_IN_RASCARYAKA (0x1f, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45)

с реальным адресом этого датчика. 

Когда вернется - скажет куда дел датчик, "на трубе весит" снова прямо в код. 

#define BLONDINKA_IN_RASCARYAKA_POSITION "На трубе"

Потом все такие дефайники собираете в массив структур из которого всегда можна узнать адрес датчика на трубе. Если надо  то и идентификатор бирки, можна хранить. А можна и в код глянуть когда надо узнать соответствие между биркой расположением и адресом.

valiktom
Offline
Зарегистрирован: 19.12.2016

вот нашёл объяснение:

UPD1:

Раз в коментариях возник вопрос, попробую объяснить "почему тут не будет переполнения".

Оно будет. Но будет "два раза". После того как millis() перепрыгнет границу и начнет опять отсчет с нуля можно заподозрить что выражение if(millis()-lastDoTime>inteval) больше никогда не сработает. Так как разница (millis()-lastDoTime) - будет отрицательной (пока millis() опять не станет боьлше lastDoTime). И соответственно всегда меньше любого интервала.
Но.... это в математике. А тут нам нужно еще помнить про типы. И то что время мы храним в unsigned long. Следовательно отрицательных чисел - у нас просто не бывает. Попытка сохранить отрицательное числов в беззнаковую переменную, опять вызовет переполнение-переход. Только "в обратную сторону". И интервал (millis()-lastDoTime) - все-таки будет правильным. Несмотря на переполнение.

исправлюсь...
а насчёт трубы...
а вы соберите макет на несколько датчиков, потасуйте, поменяйте ,
увидите как удобно, само всё находится автоматически,
наладчику надо минимум навыков(не нужен програмист) - в этом и была цель.

Logik
Offline
Зарегистрирован: 05.08.2014

valiktom пишет:
а вы соберите макет на несколько датчиков, потасуйте, поменяйте , увидите как удобно, само всё находится автоматически, наладчику надо минимум навыков(не нужен програмист) - в этом и была цель.
Много лет как работает устройство с 3-я датчиками на пине. Нормас. Кстати методика поиска без бирок и лишних номеров проста. Накидали кучу датчиков, просканировали сеть и составили в устройстве список адресов всех найденых. Затем устанавливаем соответствие так. Греем один датчик, смотрим на каком адресе растет температура и прописываем этому адресу осмысленое название. Собственно все.

Я делал такое 2-я приложениями одно чисто для такой процедуры и сохраняет в EEPROM, а второе основное рабочее просто использует готовіе данные. Так размер основного приложения сокращается.