DS18B20 только с библиотекой OneWire
Питер Скаргилл нашел способ использовать датчик температуры DS18B20 без какой-либо библиотеки и просто используя Библиотека OneWire, и удивительно, насколько она молниеносна! (это старая статья 2013 года)
#include <OneWire.h>
int16_t dallas(int x,byte start){
OneWire ds(x);
byte i;
byte data[2];
int16_t result;
do{
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
for (int i = 0; i < 2; i++) data[i] = ds.read();
result=(data[1]<<8) |data[0];
result>>=4; if (data[1]&128) result |=61440;
if (data[0]&8) ++result;
ds.reset();
ds.write(0xCC);
ds.write(0x44, 1);
if (start) delay(1000);
} while (start--);
return result;
}
void setup (){
dallas(A0,1);
}
void loop (){
float currentTemp = dallas(A0,0);
}
Проблема в точности, он преобразует float в int, чтобы получить точность в 1 градус, и все работает нормально.
Как я могу получить точность 0,5 (или 0,2?) градуса, используя эту полубиблиотеку?
@ElectronSurf, 👍3
Обсуждение2 ответа
Лучший ответ:
На самом деле он не конвертирует float
в int
. Он никогда не использует float
, так как он ему не нужен. В таблице данных DS18B20 на странице 6 показано, как форматируются данные:
- 4 старших бита просто напоминают 11-й бит знака.
- Первая цифра с полными градусами – бит 4. Каждый бит ниже имеет значения ниже 1 °C.
Таким образом, байты данных 0b1111100001010000
будут представлять температуру -123°C, а 0b1111100001011000
-122,5°C.
Автор ссылки затем сдвигает эти данные на 4 бита вправо, так что все биты, представляющие значения меньше 1, исчезают. Вы также можете преобразовать полученное значение за раздачу в float
, используя это.
int16_t whole_degree = (result & 0x07FF) >> 4;
float temperature = whole_degree + 0.5*((data[0]&0x8)>>3) + 0.25*((data[0]&0x4)>>2) + 0.125*((data[0]&0x2)>>1) + 0.625*(data[0]&0x1);
if (data[1]&128) temperature*=-1;
Поскольку float не имеет той же структуры, что и данные, нам нужно их преобразовать. Поэтому я сначала рассчитываю количество целых градусов по аналогии с вашим кодом. Затем я добавляю это со значениями младших 4 бит. ((data[0]&0x8)>>3)
и его братья и сестры будут равны 1, если установлен соответствующий бит, и 0, если нет.
Таким образом, вы получаете полную точность датчика (12 бит). Обратите внимание, что для того, чтобы это работало, вы не должны настраивать сенсор на меньшее разрешение. В этом случае вам придется игнорировать соответствующие младшие биты. Но датчик все равно находится в 12-битном режиме при включении питания, и ваш код не настраивает его иначе.
Примечание. Я не уверен в строке result |=61440;
в исходном коде. Это устанавливает 4 старших бита 16-битного значения равным 1. Я не понимаю, почему это должно быть правильным здесь, поскольку обычное 16-битное целое число имеет только 1 знаковый бит. В моем понимании исходный код привел бы к ложным показаниям (далеко), при чтении температуры ниже нуля. Вместо этого я просто умножил полученную температуру на -1
.
Весь код будет выглядеть следующим образом (я также добавил оператор для вывода чистых полученных данных в виде двоичных файлов, как я просил в своем комментарии. Эти операторы в настоящее время закомментированы):
#include <OneWire.h>
float dallas(int x,byte start){
OneWire ds(x);
byte i;
byte data[2];
int16_t result;
float temperature;
do{
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
for (int i = 0; i < 2; i++) data[i] = ds.read();
result=(data[1]<<8) |data[0];
// Здесь вы можете распечатать полученные байты в двоичном виде, как и просили в моем комментарии:
// Serial.println(результат, BIN);
int16_t whole_degree = (result & 0x07FF) >> 4; // вырезаем знаковые биты и сдвигаем
temperature = whole_degree + 0.5*((data[0]&0x8)>>3) + 0.25*((data[0]&0x4)>>2) + 0.125*((data[0]&0x2)>>1) + 0.625*(data[0]&0x1);
if (data[1]&128) temperature*=-1;
ds.reset();
ds.write(0xCC);
ds.write(0x44, 1);
if (start) delay(1000);
} while (start--);
return temperature;
}
void setup{
//Добавление Serial.begin(9600); для печати полученных байтов здесь
//Серийный.начало(9600);
dallas(A0,1);
}
void loop{
float currentTemp = dallas(A0,0);
}
я внедрил это в код, и чтение составляет около 470 градусов!, @ElectronSurf
Mhh, вы можете вывести чистое чтение в двоичном формате и написать это в комментарии. Вы можете сделать это через серийный номер с помощью Serial.println(result, BIN);
, @chrisl
я думаю, может быть, моя имплантация неверна, не могли бы вы вставить этот код в мой код или дать какую-то инструкцию, куда я должен вставить эти строки?, @ElectronSurf
""результат" не был объявлен в этой области", @ElectronSurf
@newbie Я добавил в свой ответ непроверенную реализацию. Можешь попробовать. Есть также операторы для печати чистого чтения в двоичном формате. Эти утверждения просто нужно раскомментировать в случае, если этот код работает некорректно., @chrisl
спасибо, там написано: «Результат не был объявлен в этой области», когда я хочу выполнить «Serial.println (результат, BIN)» в пустом цикле / настройке. а температура все равно выше 400..., @ElectronSurf
Да, конечно, это говорит о том, что в цикле, так как вы не должны помещать его туда, а в функцию dallas()
. Но вы можете просто использовать предоставленный мной код и раскомментировать строки с Serial
в dallas()
и setup()
, @chrisl
111001010 458,00
, @ElectronSurf
@newbie, вы просили меня взглянуть на этот вопрос, но я думаю, что этот ответ хорошо его объяснил (и проголосовал за него) ... или у вас есть что-то конкретное, на что я могу обратить внимание?, @Michel Keijzers
@MichelKeijzers да, спасибо, Крис хорошо объяснил, но показания температуры неверны. подумал, может быть, вы имеете представление об этом..., @ElectronSurf
@newbie Я исправил свой код. Дело со знаком не сработало, как я думал, поэтому теперь я сделал это, просто умножив на -1. Также я включил бит, чтобы вырезать биты знака из integer_grade перед сдвигом, чтобы единицы не могли создавать мусорные значения. Пожалуйста, еще раз проверьте, работает ли это для вас. Надеюсь, что теперь это правильно. Я проверил расчеты с запасным Arduino Nano и значением макета (тот, который вы разместили в качестве комментария, должен дать 28 625 ° C)., @chrisl
@chrisl спасибо, но результат для меня все тот же! 111000011
451,00
Очень странно!, @ElectronSurf
@newbie Более эффективно следить за исправлением Крисла, поскольку он почти или уже нашел правильный ответ, вместо того, чтобы я начал погружаться в эту проблему., @Michel Keijzers
@MichelKeijzers, спасибо, что заглянули, чувак, очень ценю это., @ElectronSurf
@chrisl я скопировал/вставил точный код, который вы разместили, и я просто делаю две печати: Serial.println(result, BIN);
и Serial.println(dallas(A0,0));
, почему я я все еще получаю это 111000011
451,00
на выходе!, @ElectronSurf
Я буду исследовать снова, @chrisl
@chrisl Я бы купил тебе выпить, если бы знал тебя в реальном мире, ты такой хороший джентльмен., @ElectronSurf
@newbie всегда пожалуйста... но все кредиты для chrisl, @Michel Keijzers
Я думаю, что нашел проблему *facepalm* Я не изменил оператор return
функции. Он по-прежнему возвращает «результат», но реальная температура находится в переменной «температура». Я меняю это сейчас, @chrisl
Комментарии не для расширенного обсуждения; этот разговор был [перемещен в чат] (https://chat.stackexchange.com/rooms/96267/discussion-on-answer-by-chrisl-ds18b20-with-only-onewire-library)., @VE7JRO
Почему бы не переписать функцию dallas() так, чтобы она возвращала число с плавающей запятой?
#include <OneWire.h>
OneWire ds(A0);
float dallas(OneWire& ds, byte start = false) {
int16_t temp;
do {
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
ds.read_bytes((uint8_t*) &temp, sizeof(temp));
ds.reset();
ds.write(0xCC);
ds.write(0x44, 1);
if (start) delay(1000);
} while (start--);
return (temp * 0.0625);
}
void setup {
dallas(ds, true);
}
void loop {
float currentTemp = dallas(ds);
}
- Программа arduino выдаёт ошибку expected //primary-expression before ')' token error: //expected ';' before '}' token E
- (Код ультразвукового датчика: такого файла или каталога нет)
- Несколько неблокирующих таймеров обратного отсчета?
- Датчик HC-SR505 PIR выдает только HIGH уровень
- Отправка данных из ESP8266 в PHP
- Определение уровня заряда с помощью датчика тока (ACS758) с arduino uno
- Использование YS-IRTM с Arduino Uno
- Как объединить два разных скетча датчика в один полный скетч?
Какой контакт у DS18B20? я не понимаю, @Uriel