Подключение нескольких DS18b20 на одну шину и на разные выводы
- Войдите на сайт для отправки комментариев
 
      Втр, 15/09/2015 - 20:53
          
      
	Всем доброго времени суток.
	Выручайте, мужики. Весь мозг себе сломал.
	Есть вроде бы простая задача подключить несколько датчиков DS18b20 на одну шину и на разные выводы, а конкретно 3 датчика подключить на пин 8 и по одному датчику на пины 5, 6, 7. Примеров в интернете море, НО
	1)Многие примеры создатели "гавно-сайтов" просто копипастят не понимая смысла и потому код нерабочий.
	Например, описывают подключение нескольких DS18b20 на шину, а в коде объявляют переменные только для одного датчика : 
	byte data[12];
	byte addr[8];
	2)Есть примеры, в которых ID (ROM) каждого DS18b20 надо определять отдельно и прописывать в коде. По-моему это как мерседес заводить ручкой ("кривым стартером")
	3)Рабочие примеры для нескольких датчиков DS18b20 даны с использованием библиотеки DallasTemperature.h. Но в ней прописана задержка 750мсек, что для моего проекта не подходит.
	Вот список страниц, на которых в какой-то степени есть решение моего вопроса:
	http://playground.arduino.cc/Learning/OneWire  Dallas Semiconductor's 1-Wire Protocol
	http://research.andbas.com/2012/02/1-wire-ds18s20.html   Измерение температуры или освоение 1-wire протокола на примере DS18S20
	http://robocraft.ru/blog/187.html   вопрос по DS18B20
	http://habrahabr.ru/post/242377/  Читаем все датчики в автоматическом режиме
	http://mk90.blogspot.com.by/2013/05/web.html  Web-термометр
	http://geektimes.ru/post/257256/  Zyxel Keenetic 4G, arduino и датчики температуры ds18b20
	http://arduino.ru/forum/programmirovanie/3-datchika-ds18b20arduino 3 датчика DS18B20+Arduino
	http://arduino.ru/forum/programmirovanie/pomogite-optimizirovat-kod-i-pa...  Помогите оптимизировать код и пару вопросов по 1-Ware
	Решения на приведенных страницах я не нашел.
	Что хочу я?
	1)Решить вопрос с использованием библиотеки OneWire.h средствами ардуино
	2)Понимать используемый код, т.е. какие переменные используются и как они изменяются
	3)Подключенные датчики DS18B20 автоматически определяются в SETUP, что бы в LOOP использовать без потери времени.
	Вот часть моего кода в части DS18B20
#include <OneWire.h>//для работы с DS18b20(датчик температуры)
//****************** Создаем объекты библиотечных классов **********************************
//Если на 1-шине сидит один датчик, то его ID знать не требуется!
OneWire ds5(5); // создаем объект ds класса OneWire с единственным параметром номер пина шины OneWire
OneWire ds6(6);
OneWire ds7(7);
OneWire ds(8);//!!!! на этой шине будет несколько датчиков
const byte kol_DS = 3; //количество датчиков на 1-wire шине
byte addr[kol_DS][8];//Создал массив: строки-кол-во датчиков по 8 байт в каждой для хранения адреса(ROM, ID) датчика
byte present = 0;
byte data[kol_DS][12];//Создал массив: строки-ном датчика по 12 байт с температурой
byte type_s;
void setup(void)
  {
  Serial.begin(9600);
Serial.println("Find"); //Find DS18хх
  Find_DS18b20();//вызов подпрограммы
}
void loop(void)
 {
//Когда данные датчиков будут в массиве, тогда понятно как получать температуру
}
void Find_DS18b20()
{
  //Пример кода, когда датчиков 2шт: http://playground.arduino.cc/Learning/OneWire
  // 1) Сначала проверим, а есть ли хоть какой датчик на шине
  for (byte i = 0; i < kol_DS; i++) //начало цикла (0,1,2) определения адресов датчиков
  {
    Serial.println(i);
    if ( !ds.search(addr[i])) //тогда нет. addr - у меня двумерный массив байтов, в котором будет храниться номер п.п. и адрес
    {
      Serial.println("NoDS");//No DS18"
      //delay(50);
      //break;
            ds.reset_search(); // если не нашли, сбрасываем поиск в начало
      return; // и возвращаемся в самое начало главного цикла void loop(void)
    }//КонецIF
    else // что-то на шине есть
    {
      //*********для отладки******
      for (int g = 0; g < 8; g++)
      {
        Serial.write(' ');
        Serial.print(addr[i][g], HEX);
      }
      Serial.println();
     //******конец для отладки***************
      
 //     ds.reset_search();//addr[k] Если разремировать, то определяется только один датчик)!!!!!!!!!!!!!!! 
//      {
//        switch (addr[i][0]) //n_ds18xx - номер п/п датчика, 0- 1-й байт содержит тип датчика
//        {
//          case 0x10://Find_Chip: DS18S20
//            type_s = 1;
//            break;
//          case 0x28:
//            //Serial.println("Find_Chip: DS18B20");
//            type_s = 0;
//            break;
//          case 0x22://Find_Chip: DS1822
//            type_s = 0;
//            break;
//            //default:
//            //Serial.println("Device is not a DS18x20 family device.");
//            //     return;
//        }//КонецSwitch
//      }
    }
  }
}
	Вот что программа выдает при этом коде
	Find
	0
	 28 51 2 45 6 0 0 34
	1
	 28 69 F6 44 6 0 0 4E
	2
	 28 D5 AC 2 5 0 0 11
	Но мне нужен весь код. Если я разремирую, 
#include <OneWire.h>//для работы с DS18b20(датчик температуры)
//****************** Создаем объекты библиотечных классов **********************************
//Если на 1-шине сидит один датчик, то его ID знать не требуется!
OneWire ds5(5); // создаем объект ds класса OneWire с единственным параметром номер пина шины OneWire
OneWire ds6(6);
OneWire ds7(7);
OneWire ds(8);//на этой шине будет несколько датчиков
const byte kol_DS = 3; //количество датчиков на 1-wire шине
byte addr[kol_DS][8];//Создал массив: строки-кол-во датчиков по 8 байт в каждой для хранения адреса(ROM, ID) датчика
byte present = 0;
byte data[kol_DS][12];//Создал массив: строки-ном датчика по 12 байт с температурой
byte type_s;
byte Gl_buffer_save[16];//Буфер (0-16) сбора информации
void setup(void)
  {
  Serial.begin(9600);
Serial.println("Find"); //Find DS18хх
  Find_DS18b20();//вызов подпрограммы
}
void loop(void)
 {
//Когда данные датчиков будут в массиве, тогда понятно как получать температуру
//start_termo();//начать измерение температуры
//delay(1000);
//get_termo();
//Send_UART_SD();//отправка данных в UART
}
void Find_DS18b20()
{
  //Пример кода, когда датчиков 2шт: http://playground.arduino.cc/Learning/OneWire
  // 1) Сначала проверим, а есть ли хоть какой датчик на шине
  for (byte i = 0; i < kol_DS; i++) //начало цикла (0,1,2) определения адресов датчиков
  {
    Serial.println(i);
    if ( !ds.search(addr[i])) //тогда нет. addr - у меня двумерный массив байтов, в котором будет храниться номер п.п. и адрес
    {
      Serial.println("NoDS");//No DS18"
      //delay(50);
      //break;
            ds.reset_search(); // если не нашли, сбрасываем поиск в начало
      return; // и возвращаемся в самое начало главного цикла void loop(void)
    }//КонецIF
    else // что-то на шине есть
    {
      //*********для отладки******
      for (int g = 0; g < 8; g++)
      {
        Serial.write(' ');
        Serial.print(addr[i][g], HEX);
      }
      Serial.println();
     //******конец для отладки***************
      
     ds.reset_search();//addr[k] Если разремировать, то определяется только один датчик)!!!!!!!!!!!!!!! 
      {
        switch (addr[i][0]) //n_ds18xx - номер п/п датчика, 0- 1-й байт содержит тип датчика
        {
          case 0x10://Find_Chip: DS18S20
            type_s = 1;
            break;
          case 0x28:
            //Serial.println("Find_Chip: DS18B20");
            type_s = 0;
            break;
          case 0x22://Find_Chip: DS1822
            type_s = 0;
            break;
            //default:
            //Serial.println("Device is not a DS18x20 family device.");
            //     return;
        }//КонецSwitch
      }
    }
  }
}
то получу :
	Find
	0
	 28 51 2 45 6 0 0 34
	1
	 28 51 2 45 6 0 0 34
	2
	 28 51 2 45 6 0 0 34
	Т.е. программа видит только один датчик.
	Также хотелось бы от умных людей услышать описание "на пальцах" приведенных ниже команд.
	Вот как понимаю их я:
	ds.search(addr[i])
	Арудино пытается определить есть ли хоть какое-нибуть устройство на 1-wire. Если есть, то записывает
	"засветившийся" ROM (8байт) в строку i массива addr. Это понятно для одного датчика. Но если датчиков много, то при каждом обращении к шине подается сигнал сброса (здесь не видно) и первым откликнувшимся опять является "шустрый" DS18x20, что собственно и видно из второго примера.
	Допустим, библиоткека сама определяет, что такой ROM она уже сохранила и продолжает "пинговать" шину, пока не словит нововый ROM. Т.е. я подсовываю команде ds.search()только место для сохранения ROM, а она сама все делает.
	Но тогда непонятен смысл команды ds.reset_search(). Что я ей должен скормить? Она что-то куда-то запишет?
	P.S. Кода решится вопрос с несколькми датчиками, я думаю, что сам разберусь с датчиками на отдельных пинах.
	P.S.S Толковый учитель по вопросам ученика видит его больше, чем по ответам. И только даун при любом вопросе видит дауна.
	Очень надеюсь на помощь.
          
Почитайте , там весьма подробно описаны все команды и алгоритмы.
VCC на 3,3 В
GND на GND
Все DATA на нужный пин
Между пином DATA и VCC подключаешь резистор на 4,7 кОм.
У каждого датчика есть свой уникальный адрес типа MAC на сетевой карте. В примере из DallasTemperature для двух датчиков есть кусок для получения адремсов всех датчков на пине.
Если у тебя датчики привязаны к конкретному месту уставноки, то храни адреса в EEPROM (один адрес - 8 байт), считывай их при запуске контроллера и используй в программе.
Команду на начала измерений можно пулять без задания адреса, тогда её получат все датчики на шине и начнут замер.
Почитайте , там весьма подробно описаны все команды и алгоритмы.
Спасибо, но Яндекс говорит, что такой страницы нет (404)
VCC на 3,3 В
GND на GND
Все DATA на нужный пин
Между пином DATA и VCC подключаешь резистор на 4,7 кОм.
У каждого датчика есть свой уникальный адрес типа MAC на сетевой карте. В примере из DallasTemperature для двух датчиков есть кусок для получения адремсов всех датчков на пине.
Если у тебя датчики привязаны к конкретному месту уставноки, то храни адреса в EEPROM (один адрес - 8 байт), считывай их при запуске контроллера и используй в программе.
Команду на начала измерений можно пулять без задания адреса, тогда её получат все датчики на шине и начнут замер.
Похоже у Вас между мозгом и глазами стоит стена. Я не спрашиваю как мне ОБОЙТИ проблему, я спрашиваю как её РЕШИТЬ в конкретных условиях. Чувствуете разницу?
Утро вечера мудреннее. Вот рабочий скетч для поиска и использования НЕСКОЛЬКИХ (2, 3, 4, 5, 6 ...) датчиков (указывается в настройках #define kol_DS 3 ) DS18b20 на одной шине с использованием библиотеки OneWire.h
компилировал под IDE 1.6.5. Библиотеку OneWire скачивал, так как в "коробке 1.6.5" не было. http://www.pjrc.com/teensy/td_libs_OneWire.html Version 2.1:
#include <OneWire.h>//для работы с DS18b20(датчик температуры) //****************** Создаем объекты библиотечных классов ********************************** //Если на 1-шине сидит один датчик, то его ID знать не требуется! OneWire ds(8);//на этой шине будет несколько датчиков #define kol_DS 3 //const byte kol_DS = 3; //количество датчиков на 1-wire шине byte addr[kol_DS][8];//Создал массив: строки-кол-во датчиков по 8 байт в каждой для хранения адреса(ROM, ID) датчика byte present = 0; byte data[kol_DS][12];//Создал массив: строки-ном датчика по 12 байт с температурой byte type_s; byte Gl_buffer_save[16];//Буфер (0-16) сбора информации void setup(void) { Serial.begin(9600); Serial.println("Find"); //Find DS18хх Find_DS18b20();//вызов подпрограммы } void loop(void) { //Когда данные датчиков будут в массиве, тогда понятно как получать температуру start_termo();//начать измерение температуры delay(1000);//подождать пока DS18b20 закончит пересчитывать температуру в цифровой код get_termo();//прочитать температуру из всех датчиков DS18b20 Send_UART_SD();//отправить данные в UART } void Find_DS18b20() { for (int i = 0; i < kol_DS; i++) { // Serial.println("Initialising DS18B20..."); if (!ds.search(addr[i])) { Serial.println("ErrInit1w");//инициализация не выполнена:DS18B20 не найдены return; } else //датчики найдены { //**********вывести номер датчика и его ROM ****** // Serial.print("Temp. Sensor "); // Serial.print(i); // Serial.print(": "); // for (int j = 0; j < 8; j++) // { // Serial.print(addr[i][j], HEX); // Serial.print(addr[i][j], HEX); // } //**************вывел ROM********** }//конец else // Serial.println("...done!"); if (OneWire::crc8(addr[i], 7) != addr[i][7]) { Serial.println("ErrCRC");//CRC Failed! return; } if (addr[i][0] != 0x28) { Serial.println("notDS18B20");//"OW Device is not DS18B20!" } }//КонецЦикла } //начало измер температуры*********************************************************************************************** void start_termo() { //для отладки //Serial.println("1000_start_termo()"); // Serial.println(n_ds18xx); //Запускаем преобразователи во всех датчиках, найденных на этапе SETUP for (byte i = 0; i < 3; i++) { ds.reset(); ds.select(addr[i]); ds.write(0x44, 1); // start conversion, with parasite power on at the end /*После окончания преобразования данные сохраняются в 2-байтовом температурном регистре в оперативной памяти, а DS18B20 возвращается в неактивное состояние с низким энергопотреблением*/ } //установить разрешение DS18b20 //00011111 -9bit 0x1F //00111111 -10bit //01011111 -11bit //01111111 -12bit 0x7F //byte conf=0x7F;// //НЕ РАБОТАЕТ // ds.reset(); // ds.skip(); // skip ROM, что бы обратиться ко всем устройствам на шине одновременно // ds.write(0x4E); // write scratchpad Для записи данных в байты 2, 3, и 4 ОЗУ // ds.write(0); // Th // ds.write(0); // Tl // ds.write(conf); // configuration } //получение температуры************************************************* void get_termo() { //для отладки http://usbsergdev.narod.ru/DOC/DS18B20_RU.pdf // Serial.println("1016_get_termo()"); //Serial.println(n_ds18xx); for (byte n_ds18xx = 0; n_ds18xx < kol_DS; n_ds18xx++) //начало цикла (0,1,2) определения адресов датчиков { present = ds.reset();//работа с датчиком всегда должна начинаться с сигнала ресета ds.select(addr[n_ds18xx]);//выбирается адрес (ROM ) датчика //Чтобы проверить корректность записи данных, необходимо выполнить чтение (используя команду чтения //Read Scratchpad [BEh]) после того, как данные (какие) будут записаны(куда). ds.write(0xBE); /*(0xBE = 190)/читать содержание ПАМЯТИ. Передача данных начинается с наименьшего значащего бита байта 0 и продолжается до 9-ого байта (байт 8 - циклический контроль избыточности). */ for ( byte i = 0; i < 9; i++) { data[n_ds18xx][i] = ds.read();//сохраняем температуру(9 байт) в массиве соответствующего датчика } //проверка контрольной суммы:Старишие 8бит из 64 ROM, а не температуры!! содержат crc if ( OneWire::crc8( addr[n_ds18xx], 7) != addr[n_ds18xx][7]) { Serial.println("ErrCRC"); //если контрольная сумма не совпала с тем, что мы приняли – работать с такими данными нельзя. //Поэтому запишем в массив с результатом такие значения, которых в нормальных условиях мы получить не сможем //return; Gl_buffer_save[n_ds18xx + 5] = 131;//придумать получше вариант } else { int16_t raw = (data[n_ds18xx][1] << 8) | data[n_ds18xx][0];//Тип 16-разрядных целых byte cfg = (data[n_ds18xx][4] & 0x60); if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms byte celsius = (float)raw / 16.0; //16.0 будет 2 знака после запятой. Мне надо целое //byte s = 0; Gl_buffer_save[n_ds18xx + 5] = celsius; //для отладки // Serial.print("1051 t="); // Serial.print(Gl_buffer_save[n_ds18xx + 5]); // Serial.println(" "); } } } //******Конец Функция void get_termo() измерения температуры void Send_UART_SD() { //Serial.println("793_Send_UART_SD()"); String dataString = ""; byte tt = 0; for ( byte s = 0; s < 17; s++) // перебираем(0,1,2...) индексы массива Gl_buffer_save[ ] { tt = Gl_buffer_save[s]; if (((s == 5) or (s == 6) or (s == 7)) and (tt > 127)) //больше 127- значит температура отрицательная { tt = 256 - tt; Serial.print('-'); dataString += '-';//наполняем строку (выводимой в UART) информацией для записи на SD карты } Serial.print(tt);//name[7] = i%10 + '0'; dataString += String(tt);//наполняем строку (выводимой в UART) информацией для записи на SD карты Serial.print(" ; "); dataString += ";";//наполняем строку (выводимой в UART) информацией для записи на SD карты } Serial.println(); }//Конец Send_UART_SD()Пользуйтесь на здоровье! И забудьте про этот дебилизм загонять ID датчиков в прошивку
Обратите внимание на одну тонкость: для хранения темпрературы я выделил байт. Т.е. можно записать число от 0 до 255, но тепература может быть отрицательной . Положительная температура будет записана числом от 0 до 127, а отрицательная от 128 (старший бит =1) до 255. Поэтому ставим знак минус перед числом. а модуль температуры получаем как (256-число)
> указывается в настройках #define kol_DS 3
Взоржал с тебя.
Не путай flash и eeprom, засмеют.
И вопрос со звездочкой. Как датчик успеет измерить температуру, если у тебя не предполагаются задерки?
А код бибилиотеки всё же изучи. Много полезного про нее узнаешь.
Тогда наберите "DS18B20 описание на русском" Чернов Геннадий.
На тему загоняния адресов в прошивку или EEPROM, готов сильно поспорить. После сбоя питания, откуда программа узнает местонахождение всех датчиков? Ваша попытка повесить их на отдельные пины, подозреваю связана именно с этим.
Похоже у Вас между мозгом и глазами стоит стена. Я не спрашиваю как мне ОБОЙТИ проблему, я спрашиваю как её РЕШИТЬ в конкретных условиях. Чувствуете разницу?
Вот бы Пухлявому так ответил)))))))
> указывается в настройках #define kol_DS 3
Взоржал с тебя.
1)Смех продлевает жизнь, а ржачь делает из человека животное.
Не путай flash и eeprom, засмеют.
2) Меня это не смущает. Есть пословица: Умный промолчит, дурак не заметит. Засмеивающие, мне кажется, ближе ко второй категории. Не стоит обращать на них внимания. За информацию спасибо. Гляну. Но код от этого не перестанет работать
И вопрос со звездочкой. Как датчик успеет измерить температуру, если у тебя не предполагаются задерки?
Открываем канал между глазами и мозгами и смотрим функцию LOOP
Я сделаю и забуду про этот проект. Некогда вникать во все библиотеки.
И все таки, как прога определяет местонахождение датчика? Могу предположить: датчики отсортированы по адресам и расположены последовательно. Что делать если датчик сдох? Перемещать все датчики, у которых адрес выше? Объясните, в чем преимущество вашего метода? Крику много, но не понятно.
1)И все таки, как прога определяет местонахождение датчика? 2)Могу предположить: датчики отсортированы по адресам и расположены последовательно. 3)Что делать если датчик сдох? 4)Перемещать все датчики, у которых адрес выше? 5)Объясните, в чем преимущество вашего метода? 6)Крику много, но не понятно.
Извините, но внес в цитаты цифры, что бы проще было отвечать.
1)датчики, подключенные к отдельным пинам будут установлены на определенные физические объекты и под это будет заточена программа. "Гирлянда" будет крепиться по обстоятельствам. Как узнать местонашождения датчика с гирлянды? Погреть и записать на бумажку, если угодно.
2)Ничего не сортировал. Ответ в п1
3)Если датчик сдох на отдельном пине, то об этом сообщит программа. Заменю, перезагружу программу и забуду. Если на "гирлянде" - тоже самое.
4)Наши абстракции не пересекаются. Не понимаю, о чем Вы.
5)Я не знаю, что Вы подразумеваете под "моим методом".
6)Странно, я вообще-то не кричал.
Видимо Ваши вопросы от потери контекста моего вопроса. Кратко повтою. Интесовал код для работы несколькими датчиками DS18b20 в определенных программных условиях. Другие моменты неактуальны, например, точность температуры.
1)Извини чувак, я хрустальный шар вчера разбил, хотя будущее он всё равно хреново показывал.
2)А хамить не надо, хамить я и сам умею. А таких шибкоумных велосипедостроителей тут в неделю по 5 штук бывает.
3)И вот тут я ловлю тебя на слове.
4)Ты сначала говришь про неприемлимость делаев и вот уже правишь пост с delay(1000). Либо крестик сними, либо трусы надень.
А устройство с двумя датчиками и адресами в EEPROM у меня сейчас на подоконнике лежит и температуру показывает.
> И все таки, как прога определяет местонахождение датчика?
5)Да никак. Я уже имел дело с таким говнокодером. Сренькнул и в кусты.
1)Думаю моё прощение Вам не поможет.
2)При обвинениях приводят цитаты. Но "чуваки" об этом не знают.
3)Опять бы цитата не помешала.
4)Т.е. моя фраза "Вот часть моего кода в части DS18B20" Вам ничего не говорит. Ладно скажу по другому. Так как проект очень большой и нет смысла его весь выкладывать, я выложил только часть кода, которая показывает суть проблемы. А что бы этот демо-код работал я добавил задержку в 1 сек там где надо.
5)Вообще-то я сам решил свой вопрос и выложил решение в общий доступ. Но у Вас, очевидно, к таким поспупкам свое специфическое отношение. Поэтому более с Вами объясняться не желаю.
Мальчики не сортесь по пустякам! 123ksn Ты вобще чего хотел то?! смотри стр.57
// ds.reset_search();заремлен. В цикле нашли 1 датчик, потом 2 и третий. Разремилds.reset_search();и нашли 1 датчик сбросили контекст поиска снованашли первый датчик.. Уберds.reset_search();на...Да, еще как с тремя датчиками на одном выводе буш работать, то конвертацию запускай по очереди, иначе питания может нехватать, если сильно надо одновременно, то надо подпитку приличную. Но токо вот зачем оно может быть надо одновременно, не термоядерный реактор мониторить же, температура меняется не быстро. Можна и все датчики на один вывод поцепить.
А с сканированием датчиков кажется класно, типа новый датчик подключил, он автоматом обнаружился, но в реале неудобняк - ну нашли допустим ваши 3 датчика (а что если 2, или 4 обнаружилось?), а какой из них какую температуру меряет? Нужна табличка соответствия, с сохранением адресов датчиков в энергонезависимой памяти данных ;) Это загрузка, и/или редактирование. Невесело получается. Подключил новый датчик - пропиши его, заменил старый - правь табличку. Если же есть табличка - нафига сканировать каждый раз?!
А с сканированием датчиков кажется класно, типа новый датчик подключил, он автоматом обнаружился, но в реале неудобняк - ну нашли допустим ваши 3 датчика (а что если 2, или 4 обнаружилось?), а какой из них какую температуру меряет? Нужна табличка соответствия, с сохранением адресов датчиков в энергонезависимой памяти данных ;) Это загрузка, и/или редактирование. Невесело получается. Подключил новый датчик - пропиши его, заменил старый - правь табличку. Если же есть табличка - нафига сканировать каждый раз?!
Не, ну это мелочи, пришел такой крутой чувак, рассказал всем, что можно адреса в массив считать. Потом для его удобства и нежелания подумать, вместо одного шлейфа использовать три. Открыл истину, как хранить отрицательные числа в байте. В итоге получил высокотехнологичную х-ню на дорогом цифровом датчике, с которой вполне может справиться любой p-n переход.
1) Да, еще как с тремя датчиками на одном выводе буш работать, то конвертацию запускай по очереди, иначе питания может нехватать, если сильно надо одновременно, то надо подпитку приличную. Но токо вот зачем оно может быть надо одновременно, не термоядерный реактор мониторить же, температура меняется не быстро. Можна и все датчики на один вывод поцепить.
2)А с сканированием датчиков кажется класно, типа новый датчик подключил, он автоматом обнаружился, но в реале неудобняк - ну нашли допустим ваши 3 датчика (а что если 2, или 4 обнаружилось?), а какой из них какую температуру меряет? Нужна табличка соответствия, с сохранением адресов датчиков в энергонезависимой памяти данных ;) Это загрузка, и/или редактирование. Невесело получается. Подключил новый датчик - пропиши его, заменил старый - правь табличку. Если же есть табличка - нафига сканировать каждый раз?!
1)Я датчики DS18b20 давно использую и с тонкостями знаком. Вот на ардуине впервый раз. Но спасибо за добрый совет.
2)Logik, не придумывайте сложности. Пусть каждый делает как ему лучше, а я буду делать как мне лучше. Как говорится на вкус и цвет... DS18b20 можно подключить квазизвездой. Пользователь может даже не знать, что перед ним не звезда. Переключил вилку в нужную розетку и готово (Я использую провода и коннекторы от телефона)
Да, извините, строку 57 нет смысла обсуждать, так как я опубликовал пример рабочего кода
Кароч вывод простой : каждый точит как хочет :)
Ваши углы заточки возможно оптимальны для Вашего проекта, который остался вне обсуждения. Для понимания большинства присутствующих проЭктантов обоснованы другие углы заточки. К ним отношу себя и я. Работаю с этими датчиками не один год. Ваш подход понял, резоны нет.
Спасибо.
PS. Когда помещаете код, не забывайте пожалуйста ставить крыжык в закладке дополнительно, пункт сворачивать.
1)Кароч вывод простой : каждый точит как хочет :)
Ваши углы заточки возможно оптимальны для Вашего проекта, который остался вне обсуждения. Для понимания большинства присутствующих проЭктантов обоснованы другие углы заточки. К ним отношу себя и я. Работаю с этими датчиками не один год. Ваш подход понял, резоны нет.
2)Спасибо.
3) PS. Когда помещаете код, не забывайте пожалуйста ставить крыжык в закладке дополнительно, пункт сворачивать.
1) Конечно, сколько людей столько и мнений.
2)Не знаю за что спасибо, но скажу пожалуйста.
3)Спасибо. Не знал о такой возможности.
Добавьте впереди незначащие нули и вписывайте после х, только то, что вам написал экран, точно не DS18B20. Его ID начинается с 28.
спасибо разобрался
В чем причина при использовании кода периодически теряется связь с датчиками выводит на дисплей как о("sensor error") испытываю в протеусе
В чем причина при использовании кода периодически теряется связь с датчиками выводит на дисплей как о("sensor error") испытываю в протеусе
Ошибка - error.
Потыкай датчики по индексу вместо адреса.
И еще http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukomment...
Ошибка - error.
Потыкай датчики по индексу вместо адреса.
И еще http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukomment...
по индексу изначально не известно где какой датчик
Если по индексу все датчики отвечают, то проверяй адреса. Если не отвечают, то смотри соединение. Логика работает или где?
Если по индексу все датчики отвечают, то проверяй адреса. Если не отвечают, то смотри соединение. Логика работает или где?
может протеус глючит)?
При проверке в метале код работает получается протеус не всегда есть хорошо
При проверке в метале код работает получается протеус не всегда есть хорошо
Что то вроде резиновой женщины. ИМХО.
Помогите пожалуйста -начальство уже мозг проело, не могу прописать 6 датчиков ds18b20 на sd накопитель. Пишет только один датчик на флешку,остальные не удается. Микроконтлллер Atmega 328p. Ардуино писал Си плюс иде.Помогите как прописать поавильно чтобы писались все датчики на sd карту. Выручите мужики!
Код и схему в студию. Без кода в "Ищу исполнителя".
А за каким ..... их писать на SD? Вы базу адресов наличных датчиков создаете? Родного EEPROMа 328 штук на 100 датчиков хватит. Или у вас их больше?
двумя руками поддерживаю "123ksn"!!! вот моя мини-переписка с другого сайта: >>>>>>>>>>>>>>>>>>>>>> valiktom кто-нибудь может разобраться со скетчем ? 1.что делает "12" в byte data[12]; ,если собираем значения до девяти "for ( i = 0; i < 9; i++) { // нам необходимо 9 байт" ? 2.что делает параметр "present" в "present = ds.reset();"и почему без него нельзя как выше "ds.reset();"? 3.как берутся и меняются значения в "addr[8];" для "if ( !ds.search(addr)) {" ? 4.какие значения сбрасывает "ds.reset_search();" ? 5.для чего нужен "delay(250);"? заранее спасибо... Е. > valiktom 1. мне тоже не понятно. У меня с data[9] всё как надо работает. 2. без present тоже всё работает прекрасно. А present - видимо, можно использовать, например, для вывода сообщения об ошибке: if (!present) {....} 3. Что касается ds.reset_search(), вот кусок из OneWire.cpp: // You need to use this function to start a search again from the beginning. // You do not need to do it for the first search, though you could. // void OneWire::reset_search() { // reset the search state LastDiscrepancy = 0; LastDeviceFlag = FALSE; LastFamilyDiscrepancy = 0; for(int i = 7; ; i--) { ROM_NO[i] = 0; if ( i == 0) break; } valiktom > Е. по поводу "addr[8];" для "if ( !ds.search(addr)) {" поставлю вопрос по-другому: ...если ds.search(addr) прочёсывает все адреса от минимального до максимального, натыкается на существующий, выдаёт единицу и дальше по коду, то почему он до этого не ушёл в "No more addresses." и "loop"... ...а если код библиотеки (может я не разобрался) не даёт выйти из прочёсывания адресов, то как мы видим два и больше сенсора за раз цикла... ..а если это разные циклы, то откуда известно с какого адреса продолжать, ведь он объявляется по-новому каждый цикл и нигде не запоминается... где собака зарыта? <<<<<<<<<<<<<<<<<<<<<<<< в конечном счёте всё сводится к тому,что происходит в цикле? while (ds.search(addr) == 1) { Serial.println(addr); } виден аналогичный взгляд на вещи...вот тоже понадобилось на три датчика на три входа повесить, без привязки к внутренним номерам датчиков.
для развития темы, притащил код из интернета:
/ подключение нескольких датчиков на разніе пині ардуино. /* Стандартная библиотека DallasTemperature несколько модернизирована и позволяет подключить несколько датчиков к одному пину Ардуино и обращаться к ним по уникальным адресам, что удобно, если надо провести датчики температуры на большие расстояния от Ардуино к местам измерения температур, так как количество проводов уменьшается до трёх или даже двух с паразитным подключением, и толщина проводов может передать сигнал напряжением в 5 вольт на большие расстояния. Но что делать, если датчик испортился, например из-за перегрева, при замене цифрового датчика на шине с другими датчиками нужно заново прописывать в программе новый уникальный номер датчика DS18b20 и заново прошивать Ардуино. Одно из решений подключить цифровые датчики, как аналоговые каждый на свой вывод и считывать температуру с привязкой к выводу, а не к уникальному адресу или к номеру в последовательности определения на шине. Если требуется подключить несколько цифровых датчиков DS18b20 на разные выводы по шине onewire воспользуётесь примером скетча: * два цифровых датчика DS18B20 на отдельные пины для быстрой замены с разрешениями для быстроты срабатывания (менее 2 секунд) и проверкой на отсутствие */ #include <OneWire.h> #include <DallasTemperature.h> // пин 10 датчик температуры 1 OneWire oW_podacha(10); // пин 11 датчик температуры 2 OneWire oW_Obratka(11); DallasTemperature podacha(&oW_podacha); DallasTemperature Obratka(&oW_Obratka); DeviceAddress podachaAddress, ObratkaAddress; int Obrat; int podach; int raznost; // float floatObrat; // float floatpodach; void setup(void) { Serial.begin(9600); podacha.begin(); Obratka.begin(); podacha.setResolution(11); Obratka.setResolution(11); <p>// при максимальной точности время срабатывания 2 секунды если не указана точность // 12 точность 0.06 // 11 точность 0.12 // 10 точность 0.25 // 9 точность 0.5 // 6 точность 0.5 } void loop(void) { Serial.println("Datchiki temperaturi:"); Obratka.requestTemperatures(); delay(40); podacha.requestTemperatures(); delay(40); Serial.print("Podacha:"); Serial.println(podacha.getTempCByIndex(0)); Serial.print("Obratka:"); Serial.println(Obratka.getTempCByIndex(0)); int Obrat = Obratka.getTempCByIndex(0); int podach = podacha.getTempCByIndex(0); int raznost = podach - Obrat; Serial.print("RaZnost:"); Serial.println(raznost); delay(100); oW_podacha.reset_search(); oW_Obratka.reset_search(); if ( !podacha.getAddress(podachaAddress, 0) ) { Serial.print("datchika Podachi net");} if ( !Obratka.getAddress(ObratkaAddress, 0) ) { Serial.print("datchika Obratki net");} } //Также часто требуется проверка на наличие датчика в случае плохого контакта. //Для ускорения работы цифровых датчиков следует установить разрешение (точность ) снятия измерений, если не указывать разрешение , //по умолчанию оно будет максимальным, а значит процесс замера температуры займёт 2 секунды.http://arduino.ru/forum/programmirovanie/arduino-i-termodatchiki-ds18b20...
Тогда наберите "DS18B20 описание на русском" Чернов Геннадий.
Для развития темы скажу, что пробовал его библиотеку под контроллер PIC. После танцев с бубном все заработало. Обработка датчиков через прерывания сделана грамотно. Но код не просто перенести на другой микроконтроллер. Мне пришлось два вечера потратить на сверку регистров таймера моего микроконтроллера с тем, который использовал Геннадий, переделку кода и вылавливание ошибок. И там используется устаревший метод работы с EEPROM из-за чего библиотека занимает много места в памяти микроконтроллера. Т. е. все операции чтения/записи в EEPROM там расписаны вручную. В современных компиляторах для PIC этого не нужно, компилятор все делает сам, достаточно указать префикс eeprom при описании переменной.
А в целом именно так должа выглядеть нормальная библиотека для работы с датчиками температуры: до 16 датчиков на один провод, автоматический опрос датчиков, сохранение кодов датчиков в EEPROM, автоматическая замена кодов датчиков в EEPROM при смене датчика, работа через прерывания, что исключает задержки на ожидание ответа от датчика. В идеале ещё переделать её под ООП, чтобы можно было одновременно запускать несколько датчиков по нескольким пинам.
AlexeySh, даже и не знал про его библиотеки, именно перевод-описание работы с DS18B20 понравилось.
AlexeySh, даже и не знал про его библиотеки, именно перевод-описание работы с DS18B20 понравилось.
Добавлю ложку дегтя. Его же библиотеку для работы с LCD дисплеями на HD44780 запустить так и не удалось. Хотя она вообще не использует прерывания, только временные задержки. После пары дней развлечений с её отладкой нашел в Инете другую библиотеку, на которой сейчас и работает моё устройство на PIC16F648A.
#include <EEPROM.h> #include <OneWire.h> // OneWire DS18B20 only //Скетч использует 10 574 байт (32%) памяти устройства. Всего доступно 32 256 байт. //Глобальные переменные используют 455 байт (22%) динамической памяти, //оставляя 1 593 байт для локальных переменных. Максимум: 2 048 байт. /* UNO: 32 кБ флэш памяти 2 кБ ОЗУ (SRAM) 1 Кб EEPROM 14 цифровых выводов Последовательная шина: 0 (RX) и 1 (TX) Внешнее прерывание: 2 и 3 ШИМ: 3, 5, 6, 9, 10, 11 SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). LED: 13 I2C: 4 (SDA) и 5 (SCL). 6 аналоговых входов (обозначенных как A0 .. A5)/14..19 в качестве цифровых выводов 7, 8 - только для цифровых выводов */ #define NumGroup 18 //количество задействованных пинов для датчиков #define MaxNumberSensor 113 //максимальное число датчиков, ограниченное объёмом EEPROM //113x9=1017<1024 byte max EEPROM unsigned long timeSens;//время события int diftime = 0;//разница времени между двумя событиями //список номеров задействованных пинов: byte numPin[NumGroup] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};//for UNO: A0..A5=>14..19 int Sensor[MaxNumberSensor];//значения измерянной температуры boolean ReadSens = false;//признак чтения\записи датчика boolean boot = false;//признак завершения полного первого цикла записи\чтения всех датчиков byte present;//признак готовности датчика к ответу //без паразитного питания - если датчик готов к ответу =1,иначе =0. для паразитного питания - читайте документацию void setup() { Serial.begin(9600); timeSens = millis();// 4,294,967,295 max Serial.println(F("If you Need to Run the Automatic Scanning T* Sensors DS18B20 - Send Any Value\r\nWaiting for Answer 10sec...")); //ждём ответа пользователя 10 секунд while (Serial.read() == -1 && diftime < 100) { diftime = int(millis() - timeSens) / 100; } if (diftime < 100) {//если согласились на автоматическое сканирование датчиков Serial.println(F("Runing...")); //проверяем присутствие уже записаных в EEPROM датчиков по их номерам: //каждый 9-й адрес(включая нулевой) в EEPROM соответствует порядковому номеру датчика, //по нему и может обращаться программа контроля температуры; //его значение совпадает с номером пина, к которому подключён датчик. //MaxNumberSensor * 9 - число задействованных адресов в EEPROM(макс. 113x9 для UNO) for (int eAddrSens = 0; eAddrSens < MaxNumberSensor * 9; eAddrSens = eAddrSens + 9) { byte Pin = EEPROM.read(eAddrSens);//читаем номер пина в EEPROM if (Pin != 255) {//значит - записан в EEPROM byte n = 0; byte ID[8];//собираем его ID for (byte i = eAddrSens + 1; i < eAddrSens + 9; i++) { ID[n] = EEPROM.read(i); n++; } OneWire ds(Pin);//активизируем общение по записанному пину n = 0;//количество возможных повторов опроса датчика while (n < 3) { present = ds.reset();//если датчик готов к ответу present=1. //полезно только для общего случая: //если на пине больше одного датчика, то пользы мало - ответят все, //но "ds.reset();" обязан быть до начала общения с датчиком. ds.select(ID);//выбираем датчик по записанному ID //без преобразования - значение не важно, важно наличие верного ответа ds.write(0xBE);//Чтение памяти(+85*С после сброса питания или предыдущее значение измерения без сброса) byte data[9];//( - если датчик отсутсвует) Serial.println(); //смотрим ответ датчика - для индикации for (byte d = 0; d < 9; d++) {//собираем его ответ data[d] = ds.read();//читаем по-байтово Serial.print(data[d], HEX); Serial.print(' '); } Serial.print("CRC="); byte CRC = OneWire::crc8(data, 8); Serial.println(CRC, HEX); int T = (data[1] << 8) | data[0];//может быть и отрицательным T = (T + 8) >> 4;//целые *C с округлением Serial.print(F("Temp = ")); Serial.print(T);//0*C - если датчик отсутсвует Serial.println(F("*C")); //проверяем ответ датчика. если датчик отсутсвует: //1.если датчик на дигитальном пине: //-если резистор подключён к пину, то data = {FF FF FF FF FF FF FF FF FF},а CRC=C9 и != FF(data[8]) //-если пин висит в воздухе, то data = {0 0 0 0 0 0 0 0 0},а CRC=0 и == 0(data[8]) //2.если датчик на аналоговом пине: //-если резистор подключён к пину, то data = {FF FF FF FF FF FF FF FF FF},а CRC=C9 и != FF(data[8]) //-если пин висит в воздухе, то в зависимости от наводок сработает один из двух вариантов // дигитального пина или 'CRC' общего случая, если наводки прыгают на грани срабатывания //по-этому: if (CRC != data[8] || present == 0 || CRC == 0) {//датчик отсутсвует или мусор n++; delay(100);//повторяем опрос датчика } else {//опрос успешный break; } } //обобщаем данные Serial.print(F("Sensor #")); Serial.print(eAddrSens / 9 + 1); Serial.print(F(" ID from EEPROM # ")); for (byte d = 0; d < 8; d++) { Serial.print(ID[d], HEX); Serial.write(' '); } Serial.print(F("on Pin #")); Serial.print(Pin); if (n == 3) {//если датчик отсутсвует Serial.println(F(" not Responds.\r\nWaiting for Answer: Delete = 'd', Skip = 's'...")); char answer; do {//ждём ответа пользователя answer = Serial.read(); if (answer == 'd') {//удаляем датчик из EEPROM for (int i = eAddrSens; i < eAddrSens + 9; i++) { EEPROM.write(i, 255); } Serial.println(F("Deleted.")); } else if (answer == 's') {//пропускаем до выяснения потом Serial.println(F("Skipped.")); } else if (answer >= 0) {//что-то ответили, но не то Serial.println(F("Waiting for the Correct Answer...")); answer = '\0';//ждём в цикле верный ответ } else {//ничего не ответили//answer == -1(int) answer = '\0';//ждём в цикле ответ } } while (answer == '\0'); } else {//всё впорядке Serial.println(F(" is Exists and Responds.")); } } } SearchSensor(); } else { Serial.println(F("Skipping...")); } Serial.println(F("\r\nEnd Setup.\r\nIf you Need to Run the Automatic Scanning during program execution - Send Value 's'.\r\n")); } //====================================================================== void loop() { //надо помнить, что исполнение основной программы управления и выходы //зависают в том положении, в котором мы остановились в момент начала поиска датчиков if (Serial.read() == 's') {//если хотим проверить датчики без перезагрузки SearchSensor(); ReadSens = false; boot = false; } else {//в програмном режиме if (timeSens > millis()) { diftime = int(4294967295 - timeSens + millis()); } else { diftime = int(millis() - timeSens); } if (ReadSens == false) { for (byte i = 0; i < NumGroup; i++) { OneWire ds(numPin[i]); // обращение ко всем датчикам шины сразу: ds.reset();//сброс шины ds.write(0xCC);//Игнорировать адрес if (boot == false) {//имеет смысл при первом запуске или замене\добавлении датчиков ds.write(0x4E);//разрешение записать конфиг //write scratchpad (starts at byte 2) //задаём аварийные температуры(верхняя\нижняя) - изменить, если пользуетесь ds.write(0x4B);//default value of TH reg (user byte 1) - верхняя ds.write(0x46);//default value of TL reg (user byte 2) - нижняя //задаём точность измерения датчика(от неё зависит время преобразованя)= 0,125гр ds.write(0x5F);//default value of Config = 0x7F (user byte 3) //точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F - подставить нужное\учесть время преобразования ds.write(0x48);// копируем три байта в EEPROM DS18B20, чтобы сохранить постоянно } ds.write(0x44);//начать преобразование температуры(без паразитного питания) } ReadSens = true; timeSens = millis(); } else if (ReadSens == true && diftime >= 500) {//500ms(с запасом)-т.к. время преобразования 375ms для (0x5F) for (byte NumSens = 0; NumSens < MaxNumberSensor; NumSens++) { int AddrSensor = NumSens * 9; byte Pin = EEPROM.read(AddrSensor); if (Pin != 255) { OneWire ds(Pin); byte m = 0; byte ID[8]; Serial.print(F("Sensor ID #")); for (int id = AddrSensor + 1; id < AddrSensor + 9; id++) { ID[m] = EEPROM.read(id); Serial.print(ID[m], HEX); Serial.write(' '); m++; } Serial.println(); byte crc = 0;//индекс числа повторов опроса датчика while (crc < 3) { present = ds.reset();//коментарии в "void setup()" ds.select(ID); ds.write(0xBE);//Чтение памяти byte data[9]; for (byte i = 0; i < 9; i++) { data[i] = ds.read(); } //проверяем ответ датчика byte CRC = OneWire::crc8(data, 8);//коментарии в "void setup()" if (CRC == data[8] && present == 1 && CRC != 0) {//ответ корректный Sensor[NumSens] = (data[1] << 8) | data[0]; Sensor[NumSens] = (Sensor[NumSens] * 10) >> 4;//целое в десятых *C (214=>21,4*C)//(t*10)>>4 == (t*10)/16 break; } else {//датчик отсутсвует или мусор crc++; Serial.print(F("Error ")); Serial.println(crc); delay(100); } } Serial.print(F("Sensor #")); Serial.print(NumSens + 1); if (crc == 3) { Serial.println(F(" Error.\r\n")); } else { Serial.print(F(" Temp: ")); Serial.print(Sensor[NumSens] / 10); Serial.write(','); Serial.print(Sensor[NumSens] % 10); //если в десятых *C Serial.println(F("*C.\r\n")); } } else if (boot == false) { Serial.print(F("Sensor #")); Serial.print(NumSens + 1); Serial.println(F(" is Blank.\r\n")); } } boot = true; ReadSens = false; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //место основной программы для Sensor[Sensor Number], //т.к. в другом месте значения не меняются //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //место другой основной программы //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } //========================================================================================= void SearchSensor() { //задавая номер обнаруженного нового датчика мы можем/хотим перезаписать уже существующий в EEPROM. //по-этому после записи нового датчика в EEPROM мы должны заново проверить датчики на пине заменяемого старого датчика, //а затем вернуться на предыдущий пин нового и продолжить поиск с того-же места,где прервали поиск. //это позволяет добавлять/заменять/тасовать датчики по номерам,не меняя основную программу. //в общем случае пины могут и совпадать, а поиск может и дублироваться повтором. //эти значения заведомо больше, чем NumGroup, например: byte ReplaceNumPin = NumGroup + 1;//номер группы(привязаной к пину) датчика на замену по номеру(остановка в непрерывном поиске) byte OldNumPin = NumGroup + 1;//номер группы(привязаной к пину) старого датчика с тем-же номером //делаем поиск датчиков перебирая пины for (byte Group = 0; Group < NumGroup; Group++) { //т.к. ds.search(addr) не останавливается сам в поиске датчиков и идёт по-кругу, нам надо создать //список их ID, и если ID повторяется - значит мы пошли на следующий круг...тут и выходим из него. //в общем случае всё максимальное число датчиков может быть и на одном пине...поэтому: byte ID[MaxNumberSensor][9];//список всех найденых на пине ID датчиков:ID[s][1_8] с их програмными номерами датчиков в EEPROM:ID[s][0]. //если ID[s][0]=0,то датчик не записан в EEPROM и по-этому он без номера. for (byte n = 0; n < MaxNumberSensor; n++) {//обнуляем значения for (byte x = 0; x < 9; x++) { ID[n][x] = 0; } } //если хотим заменить датчик: if (OldNumPin != NumGroup + 1) { Group = OldNumPin;//проверяем группу заменяемого датчика OldNumPin = NumGroup + 1;//отменяем повтор на следующий цикл } else if (ReplaceNumPin != NumGroup + 1) { Group = ReplaceNumPin;//проверяем группу нового датчика на замену ReplaceNumPin = NumGroup + 1;//отменяем повтор на следующий цикл } OneWire ds(numPin[Group]);//активизируем общение по очередному пину Serial.print(F("\r\nStart Search Pin #")); Serial.println(numPin[Group]); byte addr[8];//прочитанный ID датчика byte end_search = 0;//число совершённых поисков датчиков на пине byte s = 0;//порядковый номер в списке ID byte crc = 0;//индекс числа повторов поиска датчиков при ошибке чтения "crc" while (end_search < 2) {//ищем существующий ID датчика на пине timeSens = millis();// 4,294,967,295 max //запускаем поиск датчиков на ограниченное время, //в нашем случае = 2сек(с запасом)- т.к. возможно идентифицировать до 75 ROM в секунду while (ds.search(addr) != 1 && diftime < 200) {//2sec diftime = int(millis() - timeSens) / 10; } if (diftime < 200) {//если нашли датчик за это время, то проверяем CRC для его ID if (OneWire::crc8(addr, 7) != addr[7]) {//если мусор Serial.println(F("Detected New Sensor but CRC is not valid!")); if (crc == 0) {//сброс и повтор поиска сначала Serial.println(F("Repeat Search...")); crc++; ds.reset_search(); delay(250); } else {//уже повторяли поиск Serial.println(F("Skipping...")); } } else {//если корректный ID //проверяем есть ли такой ID в списке for (byte n = 0; n < MaxNumberSensor; n++) { if (ID[n][8] == 0) {//если попали на пустой ID ,то прекращаем поиск break; } byte m = 0;//иначе сравниваем побайтово значения записи с обнаруженым ID for (byte x = 0; x < 8; x++) { if (ID[n][x + 1] == addr[x]) { m++; } else {//не совпадает break;//идём к следующей записи } //"break" не даёт обойти "goto", по-этому - условие: if (m == 8) {//если есть в списке, значит мы прошли полный цикл поиска с момента его сброса Serial.println(F("Checked All Possible IDs. Found Sensor IDs:")); goto EndSearchPin;//уходим на следующий пин } } } //если дошли сюда, то нашли новый ID и заносим его в список for (byte i = 0; i < 8; i++) { ID[s][i + 1] = addr[i]; } //проверяем, записан ли найденый датчик в EEPROM byte same = 0;//индекс соответствия в поиске for (int eAddrSens = 0; eAddrSens < MaxNumberSensor * 9; eAddrSens = eAddrSens + 9) { byte Pin = EEPROM.read(eAddrSens); if (Pin == numPin[Group]) { for (byte n = eAddrSens + 1; n < eAddrSens + 9; n++) { if (addr[same] == EEPROM.read(n)) { same++; } else { break; } } if (same == 8) {//если найден в EEPROM Serial.print(F("Sensor #")); Serial.print(eAddrSens / 9 + 1); Serial.print(F(" ID # ")); for (byte d = 0; d < 8; d++) { Serial.print(addr[d], HEX); Serial.write(' '); } Serial.print(F("on Pin #")); Serial.print(numPin[Group]); Serial.println(F(" Already Recorded on EEPROM.")); ID[s][0] = eAddrSens / 9 + 1;//записываем номер датчика break; } else { same = 0; } } } if (same == 0) {//если нет в EEPROM, то датчик новый Serial.print(F("Detected New Sensor ID # ")); for (byte d = 0; d < 8; d++) { Serial.print(addr[d], HEX); Serial.write(' '); } Serial.print(F("on Pin #")); Serial.println(numPin[Group]); Serial.print(F("You Want to Add to EEPROM?\r\nWaiting for Answer:Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); String answer; do {//ждём ответа пользователя answer = Serial.readString(); byte numSens = answer.toInt();//теоретически тут можно начудить с ответом, //по-этому дальше попросим подтверждения ответа if (answer == "n") {//не хотим вносить в EEPROM Serial.println(F("Continue without Changes...")); //ID[s][0] = 0;//обнуляем номер датчика-он и был нулём goto ContSearchPin; } else if (numSens > 0) {//если задали номер датчика,то смотрим его Serial.print(F("Sensor #")); Serial.print(numSens); numSens--;//приводим к програмному значению if (numSens < MaxNumberSensor) {//если в рамках допустимого int eAddrSens = numSens * 9;//вычисляем начальный адрес ID датчика в EEPROM if (EEPROM.read(eAddrSens) == 255) {//если он свободен(пустой) Serial.println(F("\r\nAre You Sure?\r\nWaiting for Answer:YES='y'/NO='n'...")); char ans;//просим подтверждения ответа do {//ждём ответа пользователя ans = Serial.read(); if (ans == 'n') {//если ошиблись или передумали, то возвращаемся к предыдущему вопросу Serial.print(F("Waiting for Answer:Add to EEPROM Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); answer = ""; } else if (ans == 'y') {//если согласны, то:(same==0) EEPROM.write(eAddrSens, numPin[Group]);//записываем номер пина в EEPROM for (int y = eAddrSens + 1; y < eAddrSens + 9; y++) {// записываем ID датчика в EEPROM EEPROM.write(y, addr[same]); same++; } ID[s][0] = numSens + 1;//записываем номер датчика в список Serial.println(F("Added.")); } else if (ans >= 0) {//что-то ответили, но не то Serial.println(F("Waiting for the Correct Answer...")); ans = '\0';//ждём в цикле верный ответ } else {//ничего не ответили//ans == -1(int) ans = '\0';//ждём в цикле ответ } } while (ans == '\0'); } else {//если он не занят старой записью Serial.println(F(" is Exists on EEPROM.You Want to Replace?\r\nWaiting for Answer:YES='y'/NO='n'/Change Number='c'...")); char ans; do {//ждём ответа пользователя ans = Serial.read(); if (ans == 'n') {//не хотим заменяь датчик в EEPROM Serial.println(F("Continue without Changes...")); //ID[s][0] = 0;//обнуляем номер датчика-он и был нулём goto ContSearchPin; } else if (ans == 'c') {//хотим поменяь номер датчика Serial.print(F("Waiting for Answer:Add Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); answer = "";//ждём в цикле ответ } else if (ans == 'y') {//если согласны заменить датчик ReplaceNumPin = Group;//запоминаем номер группы найденого нового датчика OldNumPin = EEPROM.read(eAddrSens);//читаем\запоминаем номер пина старого датчика for (byte i = 0; i < NumGroup; i++) {//переводим номер пина старого датчика в номер его группы if (numPin[i] == OldNumPin) { OldNumPin = i;//запоминаем номер группы старого датчика break; } } //проверяем, есть ли старый ID в списке for (byte n = 0; n < MaxNumberSensor; n++) { if (ID[n][8] == 0) {//если попали на пустой ID ,то прекращаем поиск break; } byte m = 0;//иначе for (byte x = 1; x < 9; x++) {//сравниваем побайтово записи if (ID[n][x] == EEPROM.read(eAddrSens + x)) { m++; } else {//если не соответствует, то переходим к следующей записи break; } //если дошли сюда, значит ID есть в списке с порядковым номером "n". if (n == MaxNumberSensor - 1) {//если запись последняя, то просто обнуляем её for (byte i = 0; i < 9; i++) { ID[n][i] = 0; } } else {//иначе, затираем её,сдвигая все записи for (byte z = n; z < MaxNumberSensor; z++) { if (ID[z][8] == 0) {//если попали на пустой ID, break;//то прекращаем перезапись } for (byte i = 0; i < 9; i++) { ID[z][i] = ID[z + 1][i]; } } } s--;//уменьшаем количество записей на одну } if (m == 8) {//если уже нашли старый ID в списке, то прекращаем поиск break; } } EEPROM.write(eAddrSens, numPin[Group]);//записываем номер пина в EEPROM(same==0) for (int y = eAddrSens + 1; y < eAddrSens + 9; y++) {// записываем ID датчика в EEPROM EEPROM.write(y, addr[same]); same++; } ID[s][0] = numSens + 1;//записываем номер датчика в список Serial.println(F("Replaced.")); ds.reset_search(); delay(250); } else if (ans >= 0) { Serial.println(F("Waiting for the Correct Answer...")); ans = '\0'; } else { ans = '\0'; } } while (ans == '\0'); } } else { Serial.print(numSens + 1); Serial.println(F(" is greater than the maximum number of sensors = ")); Serial.print(MaxNumberSensor); answer = ""; } } else if (answer == "") { //answer = ""; } else { Serial.println(F("Waiting for the Correct Answer...")); answer = ""; } } while (answer == ""); } } } else { Serial.print(F("Sensors not Found.")); if (end_search == 0) { Serial.println(F("Repeat Search...")); ds.reset_search(); delay(250); } else { Serial.println(F("Skipping...")); } end_search++; } ContSearchPin: s++; if (s == MaxNumberSensor) { Serial.print(F("Found maximum number of sensors = ")); Serial.println(MaxNumberSensor); break;//выходим из поиска на пине } diftime = 0; } EndSearchPin: for (byte n = 0; n < s; n++) {// значения по порядку нахождения ID if (ID[n][8] != 0) { Serial.print(F("Sensor #")); for (byte x = 0; x < 9; x++) { Serial.print(ID[n][x], HEX); Serial.write(' '); } if (ID[n][0] == 0) { Serial.print(F("Not writed to EEPROM.")); } Serial.println(); } } Serial.print(F("End Search Pin #")); Serial.println(numPin[Group]); } }написал тут программу поиска\замены датчиков...
думаю будет полезно для новичков, каким я и являюсь,
для понимания их работы.
> goto EndSearchPin
По рукам линейкой за такое.
профееееессор... и грубиян.
Прочитай про функции и отучайся от подобного говнокодерства.
ну я же говорю - грубиян.
Да, Си-шники не любят оператор goto. А мне вот, после ассемблера, тоже очень трудно без него обходиться. Хотя стараюсь.
#include <EEPROM.h> #include <OneWire.h> // OneWire DS18B20 only //Скетч использует 11 550 байт (35%) памяти устройства. Всего доступно 32 256 байт. //Глобальные переменные используют 455 байт (22%) динамической памяти, //оставляя 1 593 байт для локальных переменных. Максимум: 2 048 байт. /* UNO: 32 кБ флэш памяти 2 кБ ОЗУ (SRAM) 1 Кб EEPROM 14 цифровых выводов Последовательная шина: 0 (RX) и 1 (TX) Внешнее прерывание: 2 и 3 ШИМ: 3, 5, 6, 9, 10, 11 SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). LED: 13 I2C: 4 (SDA) и 5 (SCL). 6 аналоговых входов (обозначенных как A0 .. A5)/14..19 в качестве цифровых выводов 7, 8 - только для цифровых выводов */ #define NumGroup 18 //количество задействованных пинов для датчиков #define MaxNumberSensor 113 //максимальное число датчиков, ограниченное объёмом EEPROM //113x9=1017<1024 byte max EEPROM unsigned long timeSens;//время события int diftime = 0;//разница времени между двумя событиями //список номеров задействованных пинов: byte numPin[NumGroup] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};//for UNO: A0..A5=>14..19 int Sensor[MaxNumberSensor];//значения измерянной температуры boolean ReadSens = false;//признак чтения\записи датчика boolean boot = false;//признак завершения полного первого цикла записи\чтения всех датчиков byte present;//признак готовности датчика к ответу //без паразитного питания - если датчик готов к ответу =1,иначе =0. для паразитного питания - читайте документацию void setup() { Serial.begin(9600); timeSens = millis();// 4,294,967,295 max Serial.println(F("If you Need to Run the Automatic Scanning T* Sensors DS18B20 - Send Any Value\r\nWaiting for Answer 10sec...")); //ждём ответа пользователя 10 секунд while (Serial.read() == -1 && diftime < 100) { diftime = int(millis() - timeSens) / 100; } if (diftime < 100) {//если согласились на автоматическое сканирование датчиков Serial.println(F("Runing...")); //проверяем присутствие уже записаных в EEPROM датчиков по их номерам: //каждый 9-й адрес(включая нулевой) в EEPROM соответствует порядковому номеру датчика, //по нему и может обращаться программа контроля температуры; //его значение совпадает с номером пина, к которому подключён датчик. //MaxNumberSensor * 9 - число задействованных адресов в EEPROM(макс. 113x9 для UNO) for (int eAddrSens = 0; eAddrSens < MaxNumberSensor * 9; eAddrSens = eAddrSens + 9) { byte Pin = EEPROM.read(eAddrSens);//читаем номер пина в EEPROM if (Pin != 255) {//значит - записан в EEPROM byte n = 0; byte ID[8];//собираем его ID for (int i = eAddrSens + 1; i < eAddrSens + 9; i++) { ID[n] = EEPROM.read(i); n++; } OneWire ds(Pin);//активизируем общение по записанному пину n = 0;//количество возможных повторов опроса датчика while (n < 3) { present = ds.reset();//если датчик готов к ответу present=1. //полезно только для общего случая: //если на пине больше одного датчика, то пользы мало - ответят все, //но "ds.reset();" обязан быть до начала общения с датчиком. ds.select(ID);//выбираем датчик по записанному ID //без преобразования - значение не важно, важно наличие верного ответа ds.write(0xBE);//Чтение памяти(+85*С после сброса питания или предыдущее значение измерения без сброса) byte data[9]; Serial.println(); //смотрим ответ датчика - для индикации for (byte d = 0; d < 9; d++) {//собираем его ответ data[d] = ds.read();//читаем по-байтово Serial.print(data[d], HEX); Serial.print(' '); } Serial.print("CRC="); byte CRC = OneWire::crc8(data, 8); Serial.println(CRC, HEX); int T = (data[1] << 8) | data[0];//может быть и отрицательным T = (T + 8) >> 4;//целые *C с округлением Serial.print(F("Temp = ")); Serial.print(T);//0*C - если датчик отсутсвует Serial.println(F("*C")); //проверяем ответ датчика. если датчик отсутсвует: //1.если датчик на дигитальном пине: //-если резистор подключён к пину, то data = {FF FF FF FF FF FF FF FF FF},а CRC=C9 и != FF(data[8]) //-если пин висит в воздухе, то data = {0 0 0 0 0 0 0 0 0},а CRC=0 и == 0(data[8]) //2.если датчик на аналоговом пине: //-если резистор подключён к пину, то data = {FF FF FF FF FF FF FF FF FF},а CRC=C9 и != FF(data[8]) //-если пин висит в воздухе, то в зависимости от наводок сработает один из двух вариантов // дигитального пина или 'CRC' общего случая, если наводки прыгают на грани срабатывания //по-этому: if (CRC != data[8] || present == 0 || CRC == 0) {//датчик отсутсвует или мусор n++; delay(100);//повторяем опрос датчика } else {//опрос успешный break; } } //обобщаем данные Serial.print(F("Sensor #")); Serial.print(eAddrSens / 9 + 1); Serial.print(F(" ID from EEPROM # ")); for (byte d = 0; d < 8; d++) { Serial.print(ID[d], HEX); Serial.write(' '); } Serial.print(F("on Pin #")); Serial.print(Pin); if (n == 3) {//если датчик отсутсвует Serial.println(F(" not Responds.\r\nWaiting for Answer: Delete = 'd', Skip = 's'...")); char answer; do {//ждём ответа пользователя answer = Serial.read(); if (answer == 'd') {//удаляем датчик из EEPROM for (int i = eAddrSens; i < eAddrSens + 9; i++) { EEPROM.write(i, 255); } Serial.println(F("Deleted.")); } else if (answer == 's') {//пропускаем до выяснения потом Serial.println(F("Skipped.")); } else if (answer >= 0) {//что-то ответили, но не то Serial.println(F("Waiting for the Correct Answer...")); answer = '\0';//ждём в цикле верный ответ } else {//ничего не ответили//answer == -1(int) answer = '\0';//ждём в цикле ответ } } while (answer == '\0'); } else {//всё впорядке Serial.println(F(" is Exists and Responds.")); } } } SearchSensor(); } else { Serial.println(F("Skipping...")); } Serial.println(F("\r\nEnd Setup.\r\nIf you Need to Run the Automatic Scanning during program execution - Send Value 's'.\r\n")); } //====================================================================== void loop() { //надо помнить, что исполнение основной программы управления и выходы //зависают в том положении, в котором мы остановились в момент начала поиска\удаления датчиков if (Serial.read() == 's') {//если хотим проверить датчики без перезагрузки SearchSensor(); ReadSens = false; boot = false; } else if (Serial.read() == 'd') {//если хотим удалить датчик без перезагрузки Serial.print(F("\r\nWaiting for Answer: Delete Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); String answer; do {//ждём ответа пользователя answer = Serial.readString(); byte numSens = answer.toInt();//теоретически тут можно начудить с ответом, //по-этому дальше попросим подтверждения ответа if (answer == "n") {//не хотим удалять из EEPROM Serial.println(F("Continue without Changes...")); //продожаем исполнение основной программы } else if (numSens > 0) {//если задали номер датчика,то смотрим его Serial.print(F("Sensor Number = ")); Serial.print(numSens); Serial.println(F("\r\nAre You Sure?\r\nWaiting for Answer:YES='y'/NO='n'...")); char ans;//просим подтверждения ответа do {//ждём ответа пользователя ans = Serial.read(); if (ans == 'n') {//если ошиблись или передумали, то возвращаемся к предыдущему вопросу Serial.print(F("Waiting for Answer:Delete Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); answer = ""; } else if (ans == 'y') {//если согласны, то: int eAddrSens = (numSens - 1) * 9;//вычисляем начальный адрес ID датчика в EEPROM for (int y = eAddrSens; y < eAddrSens + 9; y++) {//стираем датчик из EEPROM EEPROM.write(y, 255); } Serial.println(F("Deleted.")); //продожаем исполнение основной программы } else if (ans >= 0) {//что-то ответили, но не то Serial.println(F("Waiting for the Correct Answer...")); ans = '\0';//ждём в цикле верный ответ } else {//ничего не ответили//ans == -1(int) ans = '\0';//ждём в цикле ответ } } while (ans == '\0'); } } while (answer == ""); ReadSens = false; boot = false; } else {//в програмном режиме if (timeSens > millis()) { diftime = int(4294967295 - timeSens + millis()); } else { diftime = int(millis() - timeSens); } if (ReadSens == false) { for (byte i = 0; i < NumGroup; i++) { OneWire ds(numPin[i]); // обращение ко всем датчикам шины сразу: ds.reset();//сброс шины ds.write(0xCC);//Игнорировать адрес if (boot == false) {//имеет смысл при первом запуске или замене\добавлении датчиков ds.write(0x4E);//разрешение записать конфиг //write scratchpad (starts at byte 2) //задаём аварийные температуры(верхняя\нижняя) - изменить, если пользуетесь ds.write(0x4B);//default value of TH reg (user byte 1) - верхняя ds.write(0x46);//default value of TL reg (user byte 2) - нижняя //задаём точность измерения датчика(от неё зависит время преобразованя)= 0,125гр ds.write(0x5F);//default value of Config = 0x7F (user byte 3) //точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F - подставить нужное\учесть время преобразования ds.write(0x48);// копируем три байта в EEPROM DS18B20, чтобы сохранить постоянно } ds.write(0x44);//начать преобразование температуры(без паразитного питания) } ReadSens = true; timeSens = millis(); } else if (ReadSens == true && diftime >= 500) {//500ms(с запасом)-т.к. время преобразования 375ms для (0x5F) for (byte NumSens = 0; NumSens < MaxNumberSensor; NumSens++) { int AddrSensor = NumSens * 9; byte Pin = EEPROM.read(AddrSensor); if (Pin != 255) { OneWire ds(Pin); byte m = 0; byte ID[8]; Serial.print(F("Sensor ID #")); for (int id = AddrSensor + 1; id < AddrSensor + 9; id++) { ID[m] = EEPROM.read(id); Serial.print(ID[m], HEX); Serial.write(' '); m++; } Serial.println(); byte crc = 0;//индекс числа повторов опроса датчика while (crc < 3) { present = ds.reset();//коментарии в "void setup()" ds.select(ID); ds.write(0xBE);//Чтение памяти byte data[9]; for (byte i = 0; i < 9; i++) { data[i] = ds.read(); } //проверяем ответ датчика byte CRC = OneWire::crc8(data, 8);//коментарии в "void setup()" if (CRC == data[8] && present == 1 && CRC != 0) {//ответ корректный Sensor[NumSens] = (data[1] << 8) | data[0]; Sensor[NumSens] = (Sensor[NumSens] * 10) >> 4;//целое в десятых *C (214=>21,4*C)//(t*10)>>4 == (t*10)/16 break; } else {//датчик отсутсвует или мусор crc++; Serial.print(F("Sensor Error ")); Serial.println(crc); delay(100); } } Serial.print(F("Sensor #")); Serial.print(NumSens + 1); if (crc == 3) { Serial.println(F(" Error.\r\n")); } else { Serial.print(F(" Temp: ")); Serial.print(Sensor[NumSens] / 10); Serial.write(','); Serial.print(Sensor[NumSens] % 10); //если в десятых *C Serial.println(F("*C.\r\n")); } } else if (boot == false) { Serial.print(F("Sensor #")); Serial.print(NumSens + 1); Serial.println(F(" is Blank.\r\n")); } } boot = true; ReadSens = false; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //место основной программы для Sensor[Sensor Number], //т.к. в другом месте значения не меняются //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //место другой основной программы //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } //========================================================================================= void SearchSensor() { //задавая номер обнаруженного нового датчика мы можем/хотим перезаписать уже существующий в EEPROM. //по-этому после записи нового датчика в EEPROM мы должны заново проверить датчики на пине заменяемого старого датчика, //а затем вернуться на предыдущий пин нового и продолжить поиск с того-же места,где прервали поиск. //это позволяет добавлять/заменять/тасовать датчики по номерам,не меняя основную программу. //в общем случае пины могут и совпадать, а поиск может и дублироваться повтором. //эти значения заведомо больше, чем NumGroup, например: byte ReplaceNumPin = NumGroup + 1;//номер группы(привязаной к пину) датчика на замену по номеру(остановка в непрерывном поиске) byte OldNumPin = NumGroup + 1;//номер группы(привязаной к пину) старого датчика с тем-же номером //делаем поиск датчиков перебирая пины for (byte Group = 0; Group < NumGroup; Group++) { //т.к. ds.search(addr) не останавливается сам в поиске датчиков и идёт по-кругу, нам надо создать //список их ID, и если ID повторяется - значит мы пошли на следующий круг...тут и выходим из него. //в общем случае всё максимальное число датчиков может быть и на одном пине...поэтому: byte ID[MaxNumberSensor][9];//список всех найденых на пине ID датчиков:ID[s][1_8] с их програмными номерами датчиков в EEPROM:ID[s][0]. //если ID[s][0]=0,то датчик не записан в EEPROM и по-этому он без номера. for (byte n = 0; n < MaxNumberSensor; n++) {//обнуляем значения for (byte x = 0; x < 9; x++) { ID[n][x] = 0; } } Serial.println(); //если хотим заменить датчик: if (OldNumPin != NumGroup + 1) { Group = OldNumPin;//проверяем группу заменяемого датчика OldNumPin = NumGroup + 1;//отменяем повтор на следующий цикл Serial.print(F("Re")); } else if (ReplaceNumPin != NumGroup + 1) { Group = ReplaceNumPin;//проверяем группу нового датчика на замену ReplaceNumPin = NumGroup + 1;//отменяем повтор на следующий цикл Serial.print(F("Re")); } OneWire ds(numPin[Group]);//активизируем общение по очередному пину Serial.print(F("Start Search Pin #")); Serial.println(numPin[Group]); byte addr[8];//прочитанный ID датчика byte end_search = 0;//число совершённых поисков датчиков на пине byte s = 0;//порядковый номер в списке ID byte crc = 0;//индекс числа повторов поиска датчиков при ошибке чтения "crc" while (end_search < 2) {//ищем существующий ID датчика на пине timeSens = millis();// 4,294,967,295 max //запускаем поиск датчиков на ограниченное время, //в нашем случае = 2сек(с запасом)- т.к. возможно идентифицировать до 75 ROM в секунду while (ds.search(addr) != 1 && diftime < 200) {//2sec diftime = int(millis() - timeSens) / 10; } byte m = 0;//индекс нахождения записи в списке ID if (diftime < 200) {//если нашли датчик за это время, то проверяем CRC для его ID if (OneWire::crc8(addr, 7) != addr[7]) {//если мусор Serial.println(F("Detected New Sensor but CRC is not valid!")); if (crc == 0) {//сброс и повтор поиска сначала Serial.println(F("Repeat Search...")); crc++; ds.reset_search(); delay(250); } else {//уже повторяли поиск Serial.println(F("Skipping...")); } } else {//если корректный ID //проверяем есть ли такой ID в списке for (byte n = 0; n < MaxNumberSensor; n++) { if (ID[n][8] == 0) {//если попали на пустой ID ,то прекращаем поиск break; } //иначе сравниваем побайтово значения записи с обнаруженым ID for (byte x = 0; x < 8; x++) { if (ID[n][x + 1] == addr[x]) { m++; } else {//не совпадает break;//идём к следующей записи } if (m == 8) {//запись обнаружена break; } } if (m == 8) {//запись уже обнаружена break; } m = 0; } if (m == 8) {//если есть в списке, значит мы прошли полный цикл поиска с момента его сброса Serial.println(F("Checked All Possible IDs. Found Sensor IDs:")); break;//выходим из поиска на пине } else {//если нет, то нашли новый ID и заносим его в список for (byte i = 0; i < 8; i++) { ID[s][i + 1] = addr[i]; } //проверяем, записан ли найденый датчик в EEPROM byte same = 0;//индекс соответствия в поиске for (int eAddrSens = 0; eAddrSens < MaxNumberSensor * 9; eAddrSens = eAddrSens + 9) { byte Pin = EEPROM.read(eAddrSens); if (Pin == numPin[Group]) { for (int n = eAddrSens + 1; n < eAddrSens + 9; n++) { if (addr[same] == EEPROM.read(n)) { same++; } else { break; } } if (same == 8) {//если найден в EEPROM Serial.print(F("Sensor #")); Serial.print(eAddrSens / 9 + 1); Serial.print(F(" ID # ")); for (byte d = 0; d < 8; d++) { Serial.print(addr[d], HEX); Serial.write(' '); } Serial.print(F("on Pin #")); Serial.print(numPin[Group]); Serial.println(F(" Already Recorded on EEPROM.")); ID[s][0] = eAddrSens / 9 + 1;//записываем номер датчика break; } else { same = 0; } } } if (same == 0) {//если нет в EEPROM, то датчик новый Serial.print(F("Detected New Sensor ID # ")); for (byte d = 0; d < 8; d++) { Serial.print(addr[d], HEX); Serial.write(' '); } Serial.print(F("on Pin #")); Serial.println(numPin[Group]); Serial.print(F("You Want to Add to EEPROM?\r\nWaiting for Answer:Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); String answer; do {//ждём ответа пользователя answer = Serial.readString(); byte numSens = answer.toInt();//теоретически тут можно начудить с ответом, //по-этому дальше попросим подтверждения ответа if (answer == "n") {//не хотим вносить в EEPROM Serial.println(F("Continue without Changes...")); //ID[s][0] = 0;//обнуляем номер датчика-он и был нулём break;//продожаем поиск датчиков на пине } else if (numSens > 0) {//если задали номер датчика,то смотрим его Serial.print(F("Sensor Number = ")); Serial.print(numSens); numSens--;//приводим к програмному значению if (numSens < MaxNumberSensor) {//если в рамках допустимого int eAddrSens = numSens * 9;//вычисляем начальный адрес ID датчика в EEPROM if (EEPROM.read(eAddrSens) == 255) {//если он свободен(пустой) Serial.println(F("\r\nAre You Sure?\r\nWaiting for Answer:YES='y'/NO='n'...")); char ans;//просим подтверждения ответа do {//ждём ответа пользователя ans = Serial.read(); if (ans == 'n') {//если ошиблись или передумали, то возвращаемся к предыдущему вопросу Serial.print(F("Waiting for Answer:Add to EEPROM Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); answer = ""; } else if (ans == 'y') {//если согласны, то:(same==0) EEPROM.write(eAddrSens, numPin[Group]);//записываем номер пина в EEPROM for (int y = eAddrSens + 1; y < eAddrSens + 9; y++) {// записываем ID датчика в EEPROM EEPROM.write(y, addr[same]); same++; } ID[s][0] = numSens + 1;//записываем номер датчика в список Serial.println(F("Added.")); } else if (ans >= 0) {//что-то ответили, но не то Serial.println(F("Waiting for the Correct Answer...")); ans = '\0';//ждём в цикле верный ответ } else {//ничего не ответили//ans == -1(int) ans = '\0';//ждём в цикле ответ } } while (ans == '\0'); } else {//если он занят старой записью Serial.println(F(" is Exists on EEPROM.You Want to Replace?\r\nWaiting for Answer:YES='y'/NO='n'/Change Number='c'...")); char ans; do {//ждём ответа пользователя ans = Serial.read(); if (ans == 'n') {//не хотим заменяь датчик в EEPROM Serial.println(F("Continue without Changes...")); //ID[s][0] = 0;//обнуляем номер датчика-он и был нулём break;//продожаем поиск датчиков на пине } else if (ans == 'c') {//хотим поменяь номер датчика Serial.print(F("Waiting for Answer:Add Sensor Number=(0<'?'<")); Serial.print(MaxNumberSensor + 1); Serial.println(F(")/NO='n'...")); answer = "";//ждём в цикле ответ } else if (ans == 'y') {//если согласны заменить датчик ReplaceNumPin = Group;//запоминаем номер группы найденого нового датчика OldNumPin = EEPROM.read(eAddrSens);//читаем\запоминаем номер пина старого датчика for (byte i = 0; i < NumGroup; i++) {//переводим номер пина старого датчика в номер его группы if (numPin[i] == OldNumPin) { OldNumPin = i;//запоминаем номер группы старого датчика break; } } //проверяем, есть ли старый ID в списке for (byte n = 0; n < MaxNumberSensor; n++) { if (ID[n][8] == 0) {//если попали на пустой ID ,то прекращаем поиск break; } //иначе byte y = 0;//индекс нахождения ID в списке for (byte x = 1; x < 9; x++) {//сравниваем побайтово записи if (ID[n][x] == EEPROM.read(eAddrSens + x)) { y++; } else {//если не соответствует, то переходим к следующей записи break; } if (y == 8) {//если дошли сюда, значит ID есть в списке с порядковым номером "n". if (n == MaxNumberSensor - 1) {//если запись последняя, то просто обнуляем её for (byte i = 0; i < 9; i++) { ID[n][i] = 0; } } else {//иначе, затираем её,сдвигая все записи for (byte z = n; z < MaxNumberSensor; z++) { if (ID[z][8] == 0) {//если попали на пустой ID, break;//то прекращаем перезапись } for (byte i = 0; i < 9; i++) { ID[z][i] = ID[z + 1][i]; } } } s--;//уменьшаем количество записей на одну break;//если нашли старый ID в списке, то прекращаем сравнение } } if (y == 8) {//если уже нашли старый ID в списке, то прекращаем поиск break; } } EEPROM.write(eAddrSens, numPin[Group]);//записываем номер пина в EEPROM(same==0) for (int y = eAddrSens + 1; y < eAddrSens + 9; y++) {// записываем ID датчика в EEPROM EEPROM.write(y, addr[same]); same++; } ID[s][0] = numSens + 1;//записываем номер датчика в список Serial.println(F("Replaced.")); ds.reset_search(); delay(250); } else if (ans >= 0) { Serial.println(F("Waiting for the Correct Answer...")); ans = '\0'; } else { ans = '\0'; } } while (ans == '\0'); } } else { Serial.print(F(" is greater than the maximum number of sensors = ")); Serial.println(MaxNumberSensor); Serial.println(F("Waiting for the Correct Number...")); answer = ""; } } else if (answer == "") { //answer = ""; } else { Serial.println(F("Waiting for the Correct Answer...")); answer = ""; } } while (answer == ""); } } } s++; } else { Serial.print(F("Sensors not Found.")); if (end_search == 0) { Serial.println(F("Repeat Search...")); ds.reset_search(); delay(250); } else { Serial.println(F("Skipping...")); } end_search++; } if (s == MaxNumberSensor) { Serial.print(F("Found maximum number of sensors = ")); Serial.println(MaxNumberSensor); break;//выходим из поиска на пине } diftime = 0; } for (byte n = 0; n < s; n++) {// значения по порядку нахождения ID Serial.print(F("Sensor #")); Serial.print(ID[n][0]); Serial.print(F(" ID # ")); for (byte x = 1; x < 9; x++) { Serial.print(ID[n][x], HEX); Serial.write(' '); } if (ID[n][0] == 0) { Serial.print(F("Not writed to EEPROM.")); } Serial.println(); } Serial.print(F("End Search Pin #")); Serial.println(numPin[Group]); } }по просьбе отдельных професоров ушёл от "goto",
заодно дополнив кое-что и исправив неколько описок\багов и коментариев...
вроде работает...
по просьбе отдельных професоров ушёл от "goto",вроде работает...
1) Не обращайте внимание на "профессоров". Главное, что бы работало.
2)А вот "вроде работает" опускает Вас значительно ниже чем чем "goto".
Успехов!
по просьбе отдельных професоров ушёл от "goto",вроде работает...
1) Не обращайте внимание на "профессоров". Главное, что бы работало.
2)А вот "вроде работает" опускает Вас значительно ниже чем чем "goto".
Успехов!
какую не прогнозируюмую реакцию может вызвать попытка выражения скромности...
но это недостаток всех форумов: больше воды, чем обсуждения по сути...
а суть в данном случае, по-моему, в следуещем:
я попытался показать способ исправления недостатка библиотеки в поиске датчиков
(на мой взгляд, если я её правильно понял; - тоже не факт)
применительно к желанию пользователей(и моему тоже) автоматически зафиксировать их
(удалять\добавлять\тасовать\заменять) путём создания временного списка их ID,
что-бы остановить в нужном месте поиск, иначе он годится только для ручного вбивания
адресов в программу(и почему это "просто" не сделано в библеотеке?).
плюс общеизвестный способ хранения ID в EEPROM,
плюс упорядочение и так доступной информации по датчикам для новичков...
а код... он зависит от времени пребывания в нём... никто не идеален,
иначе нафиг нужны форумы? для взаимного выяснения IQ?
какую не прогнозируюмую реакцию может вызвать попытка выражения скромности...
.....
иначе нафиг нужны форумы? для взаимного выяснения IQ?
Извините. Просто отделяю "мух от котлет". Думал, что и Вы такой-же. Ошибся. Еще раз извините.
не извиняйтесь... такой-же... про IQ - это не к вам...а вообще к форумам...
по просьбе отдельных професоров ушёл от "goto",
заодно дополнив кое-что и исправив неколько описок\багов и коментариев...
вроде работает...
Респект и уважуха за проделанную работу.
Теперь можно разбираться и ставить эксперементы как НАЙТИ, ПРОНУМЕРОВАТЬ и использовать несколько датчиков на одной шине.
Код я буду писать заново под свои нужды. :-) Главное с принципом работы разобрались!
В качестве замечания по форме - старайтесь объявлять переменные в начале функции, а не в процессе их применения. Так потом легче разобраться если косяк с типом переменной и вообще откуда она взялась.
И для перфекционистов (да и простым смертным помогает) - первые 1-2 символа от типа переменной, а потом имя. (int iX; char chText[10]; byte bAdress)
А в целом текст программы очень хорошо читается - спасибо! Особенно за развернутые коменты.
Всем привет, "чукча не читатель, чукча писатель" прочитал по диагонали, нужного не нашел.
ЗАДАЧА: сверить показания нескольких датчиков или вывести показания группы датчиков по одной шине с известными адресами датчиков.
СХЕМА: все датчики в параллель, подтяжка шины данных 2,2к , подключение с питанием - без паразитки.
БИБЛИАТЕКА ЭТА:
OneWire.h
#ifndef OneWire_h #define OneWire_h #include <inttypes.h> // you can exclude onewire_search by defining that to 0 #ifndef ONEWIRE_SEARCH #define ONEWIRE_SEARCH 1 #endif // You can exclude CRC checks altogether by defining this to 0 #ifndef ONEWIRE_CRC #define ONEWIRE_CRC 1 #endif // Select the table-lookup method of computing the 8-bit CRC by setting this to 1 #ifndef ONEWIRE_CRC8_TABLE #define ONEWIRE_CRC8_TABLE 0 #endif // You can allow 16-bit CRC checks by defining this to 1 // (Note that ONEWIRE_CRC must also be 1.) #ifndef ONEWIRE_CRC16 #define ONEWIRE_CRC16 0 #endif class OneWire { private: #if ONEWIRE_SEARCH uint8_t address[8]; char searchJunction; uint8_t searchExhausted; #endif uint8_t pin; uint8_t port; uint8_t bitmask; volatile uint8_t *outputReg; volatile uint8_t *inputReg; volatile uint8_t *modeReg; public: OneWire( uint8_t pin); // Perform a 1-Wire reset cycle. Returns 1 if a device responds // with a presence pulse. Returns 0 if there is no device or the // bus is shorted or otherwise held low for more than 250uS uint8_t reset(); // Issue a 1-Wire rom select command, you do the reset first. void select( uint8_t rom[8]); // Issue a 1-Wire rom skip command, to address all on bus. void skip(); // Write a byte. If 'power' is one then the wire is held high at // the end for parasitically powered devices. You are responsible // for eventually depowering it by calling depower() or doing // another read or write. void write( uint8_t v, uint8_t power = 0); // Read a byte. uint8_t read(); // Write a bit. The bus is always left powered at the end, see // note in write() about that. void write_bit( uint8_t v); // Read a bit. uint8_t read_bit(); // Stop forcing power onto the bus. You only need to do this if // you used the 'power' flag to write() or used a write_bit() call // and aren't about to do another read or write. You would rather // not leave this powered if you don't have to, just in case // someone shorts your bus. void depower(); #if ONEWIRE_SEARCH // Clear the search state so that if will start from the beginning again. void reset_search(); // Look for the next device. Returns 1 if a new address has been // returned. A zero might mean that the bus is shorted, there are // no devices, or you have already retrieved all of them. It // might be a good idea to check the CRC to make sure you didn't // get garbage. The order is deterministic. You will always get // the same devices in the same order. uint8_t search(uint8_t *newAddr); #endif #if ONEWIRE_CRC // Compute a Dallas Semiconductor 8 bit CRC, these are used in the // ROM and scratchpad registers. static uint8_t crc8( uint8_t *addr, uint8_t len); #if ONEWIRE_CRC16 // Compute a Dallas Semiconductor 16 bit CRC. Maybe. I don't have // any devices that use this so this might be wrong. I just copied // it from their sample code. static unsigned short crc16(unsigned short *data, unsigned short len); #endif #endif }; #endifOneWire.cpp
/* Copyright (c) 2007, Jim Studt Updated to work with arduino-0008 and to include skip() as of 2007/07/06. --RJL20 Modified to calculate the 8-bit CRC directly, avoiding the need for the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 -- Tom Pollard, Jan 23, 2008 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Much of the code was inspired by Derek Yerger's code, though I don't think much of that remains. In any event that was.. (copyleft) 2006 by Derek Yerger - Free to distribute freely. The CRC code was excerpted and inspired by the Dallas Semiconductor sample code bearing this copyright. //--------------------------------------------------------------------------- // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //-------------------------------------------------------------------------- */ #include "OneWire.h" #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #include "pins_arduino.h" #endif extern "C" { #include <avr/io.h> } OneWire::OneWire( uint8_t pinArg) { pin = pinArg; port = digitalPinToPort(pin); bitmask = digitalPinToBitMask(pin); outputReg = portOutputRegister(port); inputReg = portInputRegister(port); modeReg = portModeRegister(port); #if ONEWIRE_SEARCH reset_search(); #endif } // // Perform the onewire reset function. We will wait up to 250uS for // the bus to come high, if it doesn't then it is broken or shorted // and we return a 0; // // Returns 1 if a device asserted a presence pulse, 0 otherwise. // uint8_t OneWire::reset() { uint8_t r; uint8_t retries = 125; // wait until the wire is high... just in case pinMode(pin,INPUT); do { if ( retries-- == 0) return 0; delayMicroseconds(2); } while( !digitalRead( pin)); digitalWrite(pin,0); // pull low for 500uS pinMode(pin,OUTPUT); delayMicroseconds(500); pinMode(pin,INPUT); delayMicroseconds(65); r = !digitalRead(pin); delayMicroseconds(490); return r; } // // Write a bit. Port and bit is used to cut lookup time and provide // more certain timing. // void OneWire::write_bit(uint8_t v) { static uint8_t lowTime[] = { 55, 5 }; static uint8_t highTime[] = { 5, 55}; v = (v&1); *modeReg |= bitmask; // make pin an output, do first since we // expect to be at 1 *outputReg &= ~bitmask; // zero delayMicroseconds(lowTime[v]); *outputReg |= bitmask; // one, push pin up - important for // parasites, they might start in here delayMicroseconds(highTime[v]); } // // Read a bit. Port and bit is used to cut lookup time and provide // more certain timing. // uint8_t OneWire::read_bit() { uint8_t r; *modeReg |= bitmask; // make pin an output, do first since we expect to be at 1 *outputReg &= ~bitmask; // zero delayMicroseconds(1); *modeReg &= ~bitmask; // let pin float, pull up will raise delayMicroseconds(5); // A "read slot" is when 1mcs > t > 2mcs r = ( *inputReg & bitmask) ? 1 : 0; // check the bit delayMicroseconds(50); // whole bit slot is 60-120uS, need to give some time return r; } // // Write a byte. The writing code uses the active drivers to raise the // pin high, if you need power after the write (e.g. DS18S20 in // parasite power mode) then set 'power' to 1, otherwise the pin will // go tri-state at the end of the write to avoid heating in a short or // other mishap. // void OneWire::write(uint8_t v, uint8_t power) { uint8_t bitMask; for (bitMask = 0x01; bitMask; bitMask <<= 1) { OneWire::write_bit( (bitMask & v)?1:0); } if ( !power) { pinMode(pin,INPUT); digitalWrite(pin,0); } } // // Read a byte // uint8_t OneWire::read() { uint8_t bitMask; uint8_t r = 0; for (bitMask = 0x01; bitMask; bitMask <<= 1) { if ( OneWire::read_bit()) r |= bitMask; } return r; } // // Do a ROM select // void OneWire::select( uint8_t rom[8]) { int i; write(0x55,0); // Choose ROM for( i = 0; i < 8; i++) write(rom[i],0); } // // Do a ROM skip // void OneWire::skip() { write(0xCC,0); // Skip ROM } void OneWire::depower() { pinMode(pin,INPUT); } #if ONEWIRE_SEARCH // // You need to use this function to start a search again from the beginning. // You do not need to do it for the first search, though you could. // void OneWire::reset_search() { uint8_t i; searchJunction = -1; searchExhausted = 0; for( i = 7; ; i--) { address[i] = 0; if ( i == 0) break; } } // // Perform a search. If this function returns a '1' then it has // enumerated the next device and you may retrieve the ROM from the // OneWire::address variable. If there are no devices, no further // devices, or something horrible happens in the middle of the // enumeration then a 0 is returned. If a new device is found then // its address is copied to newAddr. Use OneWire::reset_search() to // start over. // uint8_t OneWire::search(uint8_t *newAddr) { uint8_t i; char lastJunction = -1; uint8_t done = 1; if ( searchExhausted) return 0; if ( !reset()) return 0; write( 0xf0, 0); for( i = 0; i < 64; i++) { uint8_t a = read_bit( ); uint8_t nota = read_bit( ); uint8_t ibyte = i/8; uint8_t ibit = 1<<(i&7); if ( a && nota) return 0; // I don't think this should happen, this means nothing responded, but maybe if // something vanishes during the search it will come up. if ( !a && !nota) { if ( i == searchJunction) { // this is our time to decide differently, we went zero last time, go one. a = 1; searchJunction = lastJunction; } else if ( i < searchJunction) { // take whatever we took last time, look in address if ( address[ ibyte]&ibit) a = 1; else { // Only 0s count as pending junctions, we've already exhasuted the 0 side of 1s a = 0; done = 0; lastJunction = i; } } else { // we are blazing new tree, take the 0 a = 0; searchJunction = i; done = 0; } lastJunction = i; } if ( a) address[ ibyte] |= ibit; else address[ ibyte] &= ~ibit; write_bit( a); } if ( done) searchExhausted = 1; for ( i = 0; i < 8; i++) newAddr[i] = address[i]; return 1; } #endif #if ONEWIRE_CRC // The 1-Wire CRC scheme is described in Maxim Application Note 27: // "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" // #if ONEWIRE_CRC8_TABLE // This table comes from Dallas sample code where it is freely reusable, // though Copyright (C) 2000 Dallas Semiconductor Corporation static uint8_t dscrc_table[] = { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; // // Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM // and the registers. (note: this might better be done without to // table, it would probably be smaller and certainly fast enough // compared to all those delayMicrosecond() calls. But I got // confused, so I use this table from the examples.) // uint8_t OneWire::crc8( uint8_t *addr, uint8_t len) { uint8_t i; uint8_t crc = 0; for ( i = 0; i < len; i++) { crc = dscrc_table[ crc ^ addr[i] ]; } return crc; } #else // // Compute a Dallas Semiconductor 8 bit CRC directly. // uint8_t OneWire::crc8( uint8_t *addr, uint8_t len) { uint8_t i, j; uint8_t crc = 0; for (i = 0; i < len; i++) { uint8_t inbyte = addr[i]; for (j = 0; j < 8; j++) { uint8_t mix = (crc ^ inbyte) & 0x01; crc >>= 1; if (mix) crc ^= 0x8C; inbyte >>= 1; } } return crc; } #endif #if ONEWIRE_CRC16 static short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; // // Compute a Dallas Semiconductor 16 bit CRC. I have never seen one of // these, but here it is. // unsigned short OneWire::crc16(unsigned short *data, unsigned short len) { unsigned short i; unsigned short crc = 0; for ( i = 0; i < len; i++) { unsigned short cdata = data[len]; cdata = (cdata ^ (crc & 0xff)) & 0xff; crc >>= 8; if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4]) crc ^= 0xc001; cdata <<= 6; crc ^= cdata; cdata <<= 1; crc ^= cdata; } return crc; } #endif #endifКОД РАБОЧИЙ ЭТОТ:
//100% рабочий алгоритм #include <OneWire.h> OneWire ds(A2); // линия 1-Wire будет на этом пине byte ndT = 9; // сколько датчиков подключили // список адресов моих датчиков для теста byte DeviceAddres[9][8]={ // ...а датчиков у мня 7 штук в наличии {0x28, 0xB2, 0x29, 0xD7, 0x8, 0x0, 0x0, 0xDE}, // датчик с нулевым адресом, 1й {0x28, 0x96, 0x66, 0xFA, 0x8, 0x0, 0x0, 0xDF}, // адрес 1, 2й второй по порядку {0x28, 0x3F, 0x43, 0xD6, 0x8, 0x0, 0x0, 0x5D}, // 3й {0x28, 0xD, 0xFD, 0xD7, 0x8, 0x0, 0x0, 0xBC}, // 4й {0x28, 0x28, 0x88, 0xD6, 0x8, 0x0, 0x0, 0xD1}, // 5й {0x28, 0xF1, 0xD0, 0xFA, 0x8, 0x0, 0x0, 0xD7}, // 6й - нет такого у меня, просто для теста кода {0x28, 0x2B, 0xB7, 0xF7, 0x8, 0x0, 0x0, 0x9C}, // 7й {0x28, 0xF1, 0xD0, 0xF7, 0x8, 0x0, 0x0, 0xD7}, // 8й {0x28, 0xF1, 0xF1, 0xF1, 0x8, 0x0, 0x0, 0xD7}, // 9й - нет такого у меня, просто для теста кода }; byte CheckDevicePresent[9]= {0, 0, 0, 0, 0, 0, 0, 0, 0}; // заняли место в памяти под проверку датчиков и переменные byte data[12]; // переменная для данных из датчика int SignBit; // знак температуры int Tc_100; // умножено на 100 целочисленное значение температуры, т.е. запятая "подвинута >>" на 2 знака void setup(void) { Serial.begin(9600); } void loop() { for (byte i = 0; i < ndT; i++) // чИпЯтаем шапку таблЫцЫ { Serial.print( "Device №" ); Serial.print( i ); Serial.print( " " ); } for (byte i = 0; i < ndT; i++) // проверяем все датчикии, запускаем АЦП { start_conversion_T (i); } Serial.println( " " ); Serial.print( " " ); for (byte i = 0; i < ndT; i++) // пичатаем для самоконтроля { Serial.print( CheckDevicePresent[i] , DEC ); Serial.print( " " ); } Serial.println( " " ); delay (1000); // задержка на конвертацию for (byte i = 0; i < ndT; i++) // получаем и печатаем результаты { GETTEMP (i); // получаем температуру if (CheckDevicePresent[i] != 0) //если датчик не нашли {Serial.print( " NC " );} else { if (SignBit) {Serial.print( " -" );} else {Serial.print( " " );} Serial.print( Tc_100 ); Serial.print( " " ); } } Serial.println( " " ); Serial.println( " " ); Serial.println( " " ); delay (30000); // задержка на конвертацию !!!!!! :)))))))))))))) } // конй loop void start_conversion_T (byte No) { ds.reset(); ds.select(DeviceAddres[No]); ds.write(0xBE); // Считываем ОЗУ датчика for (byte i = 0; i < 9; i++) // читаем в байты, 9 байт ОЗУ датчика { data[i] = ds.read(); } if (data[4] == 255) // проверяем CRC 8 или CONFIG 4 если его нет, нет датчика = 255 (0xFF) // в конфиге бит 1 всегда 0, а CRC может быть 255 { CheckDevicePresent[No]= 1; // пишем, что датчика нет return; } CheckDevicePresent[No]= 0; // датчик есть ds.reset(); ds.select(DeviceAddres[No]); ds.write(0x44, 1); // Запускаем конвертацию (получение температуры) } void GETTEMP (byte No) { if (CheckDevicePresent[No] != 0) // если датчика нет, пропускаем { return; } ds.reset(); ds.select(DeviceAddres[No]); ds.write(0xBE); // Считываем ОЗУ датчика for (byte i = 0; i < 9; i++) // Обрабатываем 9 байт { data[i] = ds.read(); } // Высчитываем температуру :) int TReading; TReading = (data[1] << 8) + data[0]; // собираем в кучку оба байта SignBit = TReading & 0x8000; // Проверяем дубак там или нет if (SignBit) // Если на улице дубак :) { TReading = (TReading ^ 0xffff) + 1; } // Tc_100 - это температура из датчика формата int со сдвинутой запятой на 2 знака Tc_100 = (6 * TReading) + TReading / 4; // Умножаем на (100 * 0.0625) или 6.25 // т.е. убираем 4 лишних бита }ПРОБЛЕМА: не могу избавиться от чтения 9 байт ОЗУ при поиске датчиков. Строки 89 - 96.
перечитал даташит - идеи не появились, может я чего не понял :( .
UP