Подключил для примера 3 датчика по схеме :
Из стандартных библиотек подключил только OneWire. Написал класс для удобства.
Программу и класс предоставляю на обзор.
У класса есть 4 режима работы, 0 - выключено; 1 - запрос температуры и ожидание результат , вешает всю систему delay-ем; 2 - запрос температуры, по готовности выставляет флаг и можно считывать данные; 3 - то же что и 2, но по готовности вызывает CallBack функцию и передает туда температуру в "сыром виде", не преобразованную.
Есть возможность настроить каждый режим для разового и постоянного опрашивания. В примере 1 -ый и 2-ой датчик включаются по таймеру раз в 10 секунд, датчки 3 использует функцию обратного вызова и следит за температурой непрерывно.
Реализована функция выставления точности датчика, но не сделал сохранение установки в самом датчике. При перезагрузке точность надо выставлять заново. Изначально стоит самая высокая точность, после 1-го считывания температуры точность в любом случае будет выставлена по точности датчика.
Подключенные по такой схеме 3 датчика в режиме слежения дают порядка 7000 циклов loop в секунду, чем выше точность, тем больше циклов пройдет.
Не уверен, что будет работать со схемой паразитного подключения.
Функция обратного вызова назначается вручную
Из стандартных библиотек подключил только OneWire. Написал класс для удобства.
Программу и класс предоставляю на обзор.
C++:
#include <OneWire.h>
#include "term18b20.h"
uint32_t StTime;
OneWire ds(3); //пин куда полдключены термодатчики
// адреса подключенных термодатчиков
byte TerAdr[] = {0x28, 0xAA, 0x19, 0x85, 0x55, 0x14, 0x01, 0x9D};
byte TerAdr2[] = {0x28, 0xAA, 0xAB, 0x3E, 0x55, 0x14, 0x01, 0x54};
byte TerAdr3[] = {0x28, 0xAA, 0x73, 0x40, 0x55, 0x14, 0x01, 0x89};
// 3 объекта 18B20
OneTerm MyTerm(TerAdr);
OneTerm MyTerm2(TerAdr2);
OneTerm MyTerm3(TerAdr2);
void PrintBalcon(int16_t T) // тестовая функция обратного вызова, печатает только измененное значение
{
static float oldtm;
float tm = (float)T / 16.0;
if (oldtm != tm)
{
Serial.print("Температура на балконе: ");
Serial.println(tm);
oldtm = tm;
}
}
void setup() {
Serial.begin(9600);
delay(205);
MyTerm.SetPrecession(ds, Max_Prec);
String("Room ").toCharArray(MyTerm.t_name, 8);
MyTerm.SetMode(2);
MyTerm2.SetPrecession(ds, Max_Prec);
String("Kitch ").toCharArray(MyTerm2.t_name, 8);
MyTerm2.SetMode(2);
MyTerm3.SetPrecession(ds, Max_Prec);
String("Bath ").toCharArray(MyTerm3.t_name, 8);
MyTerm3.func_callback = PrintBalcon;
MyTerm3.SetMode(3);
MyTerm3.SetFollow(true);
StTime = millis(); //отсчет секунд с начала работы,
}
uint32_t Cntr = 0;
float newt3, oldt3 = 0;
void loop() {
Cntr++; // количество циклов loop за определенное время (изначально за 10 сек)
MyTerm.Tick(ds);
if (MyTerm.IsReady())
{
Serial.print(MyTerm.t_name);
Serial.println(MyTerm.Celsius());
};
MyTerm2.Tick(ds);
if (MyTerm2.IsReady())
{
Serial.print(MyTerm2.t_name);
Serial.println(MyTerm2.Celsius());
};
MyTerm3.Tick(ds);
if ((millis() - StTime) > 10000)
{
Serial.print("Кол-во ");
Serial.println(Cntr);
Cntr = 0;
StTime = millis();
MyTerm.SetMode(2);
MyTerm2.SetMode(2);
};
}
C++:
#include <OneWire.h>
typedef void (*callback_term)(int16_t);
void PrintAdr(byte a[8]) // вывод 16-отчного адреса на экран. теоретически не нужна
{
for (int i = 0; i < 8; i++)
{
if (a[i] < 16)Serial.print("0");
Serial.print(a[i], HEX);
}
};
#define Max_Prec 3
#define High_Prec 2
#define Low_Prec 1
#define Min_Prec 0
#define Max_Time 760
#define High_Time 380
#define Low_Time 190
#define Min_Time 95
#define Term_OFF 0
#define Term_long 1
#define Term_wait 2
#define Term_Callback 3
#define Term_Follow 4 // если флаг установлен, то режим не сбрасывается. сочетается Term_long Term_wait и Term_Callback
#define Term_ready 128 // бит выставляется по готовности результатов, после чтения Celsius сбрасывается, но всегда можно читать еще раз последнее значение
class OneTerm
{
public:
char t_name[8]; //отображаемое название датчика
byte addres[8]; //адрес датчика
byte mode = 0b01100000; // задержка по времени, изначально самая большая. после 1-го получения температуры меняется на актулаьную
uint32_t start_time = 0; // время начала запроса температуры
int16_t Temperatura = 0; // здесь температура хранится после получения.
callback_term func_callback=NULL; // эта функция будет вызываиться после получения температуры
OneTerm(byte a[8]); // конструктор
bool IsReady(); // true если запрос получения температуры обработан
int Term_Delay(); // возвращает время обработки запроса температуры датчиком. изначально максимальное время.
void TermRequest(OneWire D_Wire); // запрос подготовки данных о температуре датчика
void TermReceive(OneWire D_Wire); // получение данных с датчика , только при условии пройденного времени
void Tick(OneWire D_Wire); // выполняет действия согласно регистру mode
float Celsius(); //
void SetMode(byte m);
void SetPrecession(OneWire D_Wire, byte m);
bool isFollow();
void SetFollow(bool f);
};
OneTerm::OneTerm(byte a[8]) // создаем экземпляр класс с указанным адресом термодатчика;
{
for (int i = 0; i < 8; i++) {
addres[i] = a[i];
};
}
bool OneTerm::IsReady() {
return (mode & Term_ready);
};
int OneTerm::Term_Delay() //озвращает время обработки запроса температуры датчиком в милисекундах.
{
switch ((mode & 96) >> 5)
{
case 0: return Min_Time;
case 1: return Low_Time;
case 2: return High_Time;
case 3: return Max_Time;
}
};
void OneTerm::TermRequest(OneWire D_Wire)
{
bitClear(mode, 7);
D_Wire.reset();
D_Wire.select(addres);
D_Wire.write(0x44);
start_time = millis();
};
void OneTerm::TermReceive(OneWire D_Wire)
{
uint32_t ctim = millis();
// Serial.println((ctim - start_time));
if ((ctim - start_time) < Term_Delay()) return;
byte i;
byte present = 0;
byte data[12];
present = D_Wire.reset();
D_Wire.select(addres);
D_Wire.write(0xBE);
for ( i = 0; i < 9; i++) {
data[i] = D_Wire.read();
};
Temperatura = (data[1] << 8) | data[0];
mode = (mode & 0b10011111) | (data[4] & 0b01100000);
bitSet(mode, 7);
};
float OneTerm::Celsius()
{
bitClear(mode, 7);
return (float)Temperatura / 16.0;
}
void OneTerm::SetMode(byte m)
{
if ((m < 0) && (m > 2)) return;
mode = (mode & 248) | m;
}
void OneTerm::SetPrecession(OneWire D_Wire, byte m)
{
if ((m < 0) | (m > 3)) return;
m = m << 5;
mode = (mode & 0b10011111) | m ;
D_Wire.reset();
D_Wire.select(addres);
D_Wire.write(0x4E);
D_Wire.write(0x7F); D_Wire.write(0xFF); D_Wire.write(m << 1);
};
bool OneTerm::isFollow()
{
return (mode & Term_Follow);
};
void OneTerm::SetFollow(bool f)
{
if (f) bitSet(mode, 2); else bitClear(mode, 2);
};
void OneTerm::Tick(OneWire D_Wire)
{
byte smode = mode & 3;
//Serial.println(smode);
switch (smode)
{
case 0: return;
case 1: {
TermRequest(D_Wire);
delay(Term_Delay() + 5);
TermReceive(D_Wire);
if (! isFollow()) mode = mode & 248; //если не стоит следить, то очистить режим.
return;
};
case 2: {
if (start_time == 0)
TermRequest(D_Wire);
else
{
TermReceive(D_Wire);
if (IsReady())
{
if (!isFollow()) mode = mode & 248; //если не стоит следить, то очистить режим.
start_time = 0;
}
};
return;
}
case 3: {
if (start_time == 0)
TermRequest(D_Wire);
else
{
TermReceive(D_Wire);
if (IsReady())
{
if (!isFollow()) mode = mode & 120; //если не стоит следить, то очистить режим и готовность, т.к. сразу вызываем функцию
start_time = 0;
if (func_callback!=NULL) func_callback(Temperatura);
}
};
return;
}
}
};
У класса есть 4 режима работы, 0 - выключено; 1 - запрос температуры и ожидание результат , вешает всю систему delay-ем; 2 - запрос температуры, по готовности выставляет флаг и можно считывать данные; 3 - то же что и 2, но по готовности вызывает CallBack функцию и передает туда температуру в "сыром виде", не преобразованную.
Есть возможность настроить каждый режим для разового и постоянного опрашивания. В примере 1 -ый и 2-ой датчик включаются по таймеру раз в 10 секунд, датчки 3 использует функцию обратного вызова и следит за температурой непрерывно.
Реализована функция выставления точности датчика, но не сделал сохранение установки в самом датчике. При перезагрузке точность надо выставлять заново. Изначально стоит самая высокая точность, после 1-го считывания температуры точность в любом случае будет выставлена по точности датчика.
Подключенные по такой схеме 3 датчика в режиме слежения дают порядка 7000 циклов loop в секунду, чем выше точность, тем больше циклов пройдет.
Не уверен, что будет работать со схемой паразитного подключения.
Функция обратного вызова назначается вручную
Изменено: