Устанавливаем четыре датчика температуры Ds18x20 на объекты, например улица, комната, подача котла, обратка котла. Подключаем их на один пин к ардуино, например А0. Организовываем библиотеку протокола 1-Wire, <OneWire.h>, так как датчики Ds18x20 работают по этому протоколу. Организовываем место визуального наблюдения температуры, например LCD.
Работу и подключение LCD и Ds18x20 можно почитать на канале, ссылки в конце статьи.
Запускаем и получаем
Ни один датчик не попал куда планировалось. Дело в том, что любая библиотека определяет очередь датчиков по степени их "ШУСТРОСТИ" . Сначала самый шустрый, затем менее шустрый... итд, а программа организована - Улица - Подача - Комната - Обратка.
Да, можно переписать бумажку, то есть установить датчики по объектам эмпирическим путем или переписать LCD. Но, во первых это не очень удобно. Во вторых, чо будет если один из датчиков выйдет из строя... Заменить его нужно будет по шустрости совпадающим со старым, это невозможно и опять эмпирический путь.
А что если "обучать" микроконтроллер, то есть привязывать датчики к месту визуального наблюдения. Прописать в EEPROM (энерго независимая память) 64 битный адрес и битный тип (type_s) очередного датчика, а затем по очереди читать адрес датчика и выводить температуру. Простым языком составить таблицу в энерго независимой памяти. Так как ЕЕПРОМ не стирается после отключения питания, девайс обучается один раз за все время своего существования или до очередной замены датчиков (датчика). Этим и займемся.
Для облегчения дальнейшей работы создадим маски LCD и EEPROM.
Сначала подключаем библиотеки, загружаем маску LCD и запрашиваем обучение.
Да, первый датчик должен быть подключен, затем запускаем программу.
Запрос на обучение продолжается 10 сек. Если обучение необходимо,нажимаем кнопку, подключенную к пину 12.
Он применен для лучшего понимания. Если понадобится, избавимся в 5 сек. Антидребезг кнопки организован грубой силой с применением делей. Думаю делей в области setup не помешает, но можно избавится. В основном цикле (loop) делеев не будет
Нам нужно обучение, нажимаем кнопку, if (digitalRead(12) == 0) break; , попадаем в "вечный" цикл while(true) { ... }. В каждой итерации вечного цикла на экране запрашивается подключение очередного датчика. Цикл останавливается и ждет команды (нажатия кнопки). Подключаем очередной датчик, нажимаем кнопку for(;;) {if (digitalRead(12) == 0) goto AAA} , прибавляем очередь датчика kol++;, а функция search(addr) считывает 64 битный адрес очередного датчика и помещает его значение в глобальный массив byte addr[8]; (8 байт, т.е. 64 бита)
По первому байту 64 битного адреса вычисляем тип датчика
По порядковому номеру kol++; записываем в ЕЕПРОМ по жестко прописанному адресу тип датчика. С помощью аргумента функции Write_Ee_Addr (х) передаем и записываем в ЕЕПРОМ адрес датчика
При достижении if (kol == 4){break;} выходим в loop, где мы с успехом считываем из ЕЕПРОМ адреса и типы датчиков и выводим температуру. Прежде производится предварительная подготовка экрана.
Подводим общую черту алгоритма действий. Подключаем первый датчик, запускаем девайс
Первый датчик прописан, подключаем второй, нажимаем кнопку
Второй датчик прописан. Подключаем третий, нажимаем кнопку.
Третий прописан. Подключаем четвертый, нажимаем кнопку
Четвертый прописан. Девайс готов к работе. Четвертый показывает температуру, так как подключен пока он один. Подключаем все, проверяем
Теперь все датчики совпадают с "бумажкой" (объектами).
Скетч можно с легкостью доточить на любое количество датчиков, вернее на сколько хватит свободного ЕЕПРОМ. Посчитаем, ЕЕПРОМ / 9 + 1 . Можно добавить интеллекта, например проверка каждого датчика при "прописке" итд... Оптимизировать.
ВИДЕО ТУТ
Рабочий скетч для копирования
#include <OneWire.h>
#include <EEPROM.h> // импортируем библиотеку
#include <LiquidCrystal_I2C.h> // Подключаем библиотеку для работы с LCD дисплеем по шине I2C
LiquidCrystal_I2C lcd (0x27, 20, 4);// ОБЪЕКТ ( АДРЕС_I2C , КОЛ_СТОЛБЦОВ , КОЛ_СТРОК );
OneWire ds(A0);// on pin A0 (a 4.7K resistor is necessary)
byte type_s;
//byte data[12];
byte addr[8];
// float celsius;, fahrenheit;
byte z = 0;
byte Cursor = 6, Stroka = 2;
unsigned long timing;
void setup(void) {
// Serial.begin(9600);
lcd.init(); // инициализация LCD дисплея
lcd.backlight(); // включение подсветки дисплея
pinMode(12,INPUT_PULLUP); // 12 пин на ввод, кнопка
byte kol = 0; // переменная для колличества датчиков
byte No_Obuchenie = 0;
byte Cursor_Sp = 0;
lcd.setCursor(0,2);
lcd.print("T_\251\273\345 \231 \T_Ko\274\ \231" ); // Т_Улц Т_ Ком
lcd.setCursor(0,3);
lcd.print("T_\250\343\300 \231 \T_O\262\p \231"); // Т_Пдч Т_Обр
for (;;){ // запрос на обучение 10 sec
lcd.setCursor(1,0);
lcd.print("O\240\251\253\105\H\245\105 \340\AT\253\245\KOB");// обучение датчиков
if (digitalRead(12) == 0)break ; //goto AAA;
No_Obuchenie ++;
if (No_Obuchenie > 10) goto EX; //Ext_To_Loop ;
lcd.setCursor(Cursor_Sp,1);
lcd.print("\377\377");
Cursor_Sp = Cursor_Sp + 2;
delay(1000);
}
AAA:///////////////////////////////ОБУЧЕНИЕ///////////////////////////////////////////
delay(200);
while (digitalRead(12) == 0);
while (true){
if ( !ds.search(addr)) {
Num_Ds(kol);
for(;;){ // for (;;) выполняется вечно...пока не нажата кнопка
for(;;){ if (digitalRead(12) == 0 ) goto AAA; }
}
ds.reset_search();
delay(250);
//return;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return;
}
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
// Serial.println(" Chip = DS18S20"); //выбор типа
type_s = 1; // датчика
break;
case 0x28:
// Serial.println(" Chip = DS18B20");
type_s = 0;
break;
case 0x22:
// Serial.println(" Chip = DS1822");
type_s = 0;
break;
// default:
// Serial.println("Device is not a DS18x20 family device.");
// return;
}
switch (kol) { // выбор очередного датчика
case 0:
EEPROM.write(1,type_s); // запись в еепром типа
Write_Ee_Addr(2); // получение и запись
// 64 битного адреса
break;
case 1:
EEPROM.write(10,type_s);
Write_Ee_Addr(11);
break;
case 2:
EEPROM.write(19,type_s);
Write_Ee_Addr(20);
break;
case 3:
EEPROM.write(28,type_s);
Write_Ee_Addr(29);
break;
}
kol++;
EEPROM.write(0,kol); // пригодится
if(kol >= 4){break;} // goto loop
}
EX:///////////////////// ОЧИСТКА ПЕРЕД loop/////////////////////////////////////////////////////////////////////
lcd.setCursor(0,0);
lcd.print(" K PA\240\OTE \241\OTOB "); // К РАБОТЕ ГОТОВ
for ( byte Cursor = 0; Cursor < 20; Cursor++){
lcd.setCursor(Cursor,1);
lcd.print("\40");
delay(100);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop(void) {
// byte i_ds = EEPROM.read(0);
if (millis() - timing > 1000){ //задержка
Find_Temperature(Cursor, Stroka); // вывод на LCD
Read_Temperature(z); // чтенте температуры
z = z >= 4 ? 0 : z + 1; // если z больше равно 4, то z в ноль,иначе увеличиваем на 1
timing = millis();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Write_Ee_Addr(byte a){
for(byte i = 0; i < 8; i++) {
EEPROM.write(a,addr[i]);
a = a + 1;
}
}
void Read_Temperature(byte x){
switch (x){
case 0:
type_s = EEPROM.read(1);
//(начало адреса очередного (первого) еепром = 2,курсор = 6,строка = 2,тип датчтка = type_s)
// смотри картинку масок еепрома и дисплея
Read_Ee_Addr(2);
Cursor = 6; Stroka = 2;
ds.reset();
ds.select(addr);
ds.write(0x44);
break;
case 1:
type_s = EEPROM.read(10);
//(начало еепром = 11,курсор = 6,строка = 3,тип датчтка = type_s)
Read_Ee_Addr(11);
Cursor = 6; Stroka = 3;
ds.reset();
ds.select(addr);
ds.write(0x44);
break;
case 2:
type_s = EEPROM.read(19);
//(начало еепром = 20,курсор = 16,строка = 2,тип датчтка = type_s)
Read_Ee_Addr(20 );
Cursor = 16; Stroka = 2;
ds.reset();
ds.select(addr);
ds.write(0x44);
break;
case 3:
type_s = EEPROM.read(28);
//(начало еепром = 29,курсор = 16,строка = 3,тип датчтка = type_s)
// Read_Ee_Addr(29, 16, 3, type_s);
Read_Ee_Addr(29);
Cursor = 16; Stroka = 3;
ds.reset();
ds.select(addr);
ds.write(0x44); // запрос на считывание температуры очередного датчика
break;
}
}
void Read_Ee_Addr(byte a){
for(byte i = 0; i < 8; i++) { //получение адреса очередного датчика 8 байт 64 (64 бит)
addr[i] = EEPROM.read(a);
Serial.print(addr[i], HEX);
a++;
}
}
void Find_Temperature(byte Cursor,byte Stroka ){ // вывод на дисплей
int celsius;
byte present;
byte data[12];
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // считывание данных температуры
for (byte i = 0; i < 9; i++) { // 9 байт
data[i] = ds.read();
}
Serial.print(" CRC=");
// Serial.print(OneWire::crc8(data, 8), HEX);
Serial.println();
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[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
}
// celsius = (float)raw / 16.0;
celsius = (int)raw / 16;
//fahrenheit = celsius * 1.8 + 32.0;
// Serial.print(" Temperature = ");
//Serial.print(celsius);
// Serial.print(" Celsius, ");
lcd.setCursor(5,2); //очистка знака минус при переходе с -1 на 0
lcd.print("\40"); // или с температуры 100 на 99
lcd.setCursor(Cursor, Stroka);
lcd.print(celsius);
}
void Num_Ds(byte n ){
Serial.print(n);
lcd.setCursor(0, 1);
lcd.print(" \340\101\124\253\245\113\ N "); // датчик N
lcd.setCursor(11, 1);
lcd.print(n + 1);
// Ext_To_Loop (n);
}
ВИДЕО ТУТ
Работа LCD по протоколу I2C ТУТ
Работа Ds18x20 и <OneWire.h> ТУТ
Продолжение следует... Ваяю контроллер горения котла, в частности пеллетной горелки.
Удачи