DS18B20 ведет себя непонятно
- Войдите на сайт для отправки комментариев
Доброго времени суток.
Подскажите, в чем я ошибаюсь. Подключил к ардуино уно 4хразрядный 7сегментный индикатор с регистрами для динамической индикации. Проверил - цифирки показывает, все работает. Следующим шагом подключил датчик температуры DS18B20, загрузил тестовый скетч, на сериал монитор все выводит. Далее начались странности
#include <OneWire.h>
OneWire ds(8); // 8 пин для I2C
int _LCDData;
byte data[9];
//задействованные контакты ардуино для LCD
#define SCLK 3
#define RCLK 4
#define DIO 5
byte digitBuffer[4];
void setup(){
pinMode(RCLK, OUTPUT);
pinMode(SCLK, OUTPUT);
pinMode(DIO, OUTPUT);
Serial.begin(9600);
}
void loop(){
ds.reset();
ds.write(0xCC);
ds.write(0x44);
delay(750); // ----------- странность будет тут
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
for (int i=0; i < 9; i++){
data[i] = ds.read();
}
int Temp = ((data[1]<< 8) | data[0]);
double Temp2 = (double)Temp * 100 / 16;
Temp = (int)Temp2;
Serial.println(Temp);
_LCDData = Temp;
convertNumber(_LCDData, 2);
showDisplay();
}
void convertNumber(int _number, int _pointPosition){
digitBuffer[3] = _number % 10; _number = _number / 10;
digitBuffer[2] = _number % 10; _number = _number / 10;
digitBuffer[1] = _number % 10; _number = _number / 10;
digitBuffer[0] = _number % 10; _number = _number / 10;
switch (_pointPosition){
case 0: digitBuffer[3] += 10;
break;
case 1: digitBuffer[2] += 10;
break;
case 2: digitBuffer[1] += 10;
break;
case 3: digitBuffer[0] += 10;
break;
}
}
void showDisplay(){
//маска для цифр 0-9 без точки, 10-19 с точкой, 20 - погашен, 21 - нижний сегмент, 22 - средний сегмент, 23 - верхний сегмент, 24 - маленький ноль
// побитно 7-точка, 6-средний, 5-верхний левый, 4-нижний левый, 3-нижний, 2-правый нижний, 1-правый верхний, 0-верхний
const byte digit[25] = {0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010, 0b10000010, 0b11111000, 0b10000000, 0b10010000,
0b01000000, 0b01111001, 0b00100100, 0b00110000, 0b00011001, 0b00010010, 0b00000010, 0b01111000, 0b00000000, 0b00010000,
0b11111111, 0b11110111, 0b10111111, 0b11111110, 0b10100011};
// маска для разряда
const byte chr[4] = {0b00001000, 0b00000100, 0b00000010, 0b00000001};
//выполняем один проход по всем цифрам
for(byte i = 0; i <= 3; i++)
{
digitalWrite(RCLK, LOW); // Открываем защелку
shiftOut(DIO,SCLK,MSBFIRST, digit[digitBuffer[i]]); // Отправляем байт с "числом"
shiftOut(DIO,SCLK,MSBFIRST, chr[i]); // выбираем разряд
digitalWrite(RCLK, HIGH); // Защелкиваем регистры (завтавляем защелку выставить состояние выводов соответственно отправленным байтам)
delay(1);
}
}
Этот код работает с диким мерцанием LED, что вполне понятно (delay(750). Но работает! Все попытки обойти вариантами счетчиками в теле цикла, созданием счетчика/таймера, который бы вызывал обновление индикатора, заканчивались получением от термодатчика 85.00. Далее начал копать - оказывается датчик ни одним скетчем не определяется. Все говорят, что нет на I2C ни одного датчика. Но он-то работает, когда греешь, температуру поднимает, комнатную показывает. Но не в это суть. Если выполнить любой ввод/вывод в любой другой порт (не I2C) в течении 50мс перед строкой с паузой 750 - датчик значения не вернет. Точнее вернет 85.00. Поэтому как ни изголяйся, паузу держать придется, а это приводит к миганию индикатора, что никак не приемлимо.
Где я ошибся?
1. Паузу совершенно необязательно держать при помощи delay(750).
2. Остального не понял. Вероятно потому что нет схемы.
Просто, что бы привнести еще немного неразберихи - а при чем тут I2C? onewire и i2c совершенно разные протоколы. DS18B20 - это onewire
Не используйте дилэи не и не будет странностей...
У вас есть две части кода для работы с датчиком, между ними должна быть задержка, но весь этот код не должен блокировать выполнение остальной части программы. Значит вам нужен флаг, с помощью которого определяется нужность выполнения первой части кода (до задержки), а также, переменная, которая будет хранить некое время, что бы знать, прошла задержка или нет.
Итого, всё сводится к виду -
//Переменные Флаг (логическая) и Время (беззнаковый лонг) - глобальные или статические if (Флаг) { //тут инициализация и команда на конвертацию Флаг = false; } if (!Флаг && millis() - Время > 750) { //750 - это ваша задержка Время = millis(); //Выполняем преобразование данных Флаг = true; } }1. на тему паузы не delay. я четко написал, что любые другие вводы/выводы прибивают данные с 1wire.
2. схема тут не нужна, все по программе ясно. для совсем полной картины скажу, что резистор на 4.7к на датчике висит.
Следующий ))) по I2C и 1wire - мой косяк, виноват. попутало чего-то в голове дурной )
OlegK. При всем уважении. Про код с флагами я написал более чем понятно. Любой ввод/вывод в любой порт (а это необходимо для обновления индикаторов) собьет данные с датчика на непонятные 85.00
Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных
Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных
В качестве версии - нестабильное питание во время вывода не рассматривали? Питание ds18b20 паразитное или полное?
питание полное. на отладке от усб с компа, ради прикола сейчас подключил внешнее - все так же (
Меня больше смущает, что датчик не отлавливается. ммм. попробую уточнить. 1wire search говорит, что нет там никого. но отвечает, гад такой. может гемор в датчике, а я тут мозг всем компосирую... Сейчас попробую без one wire ручками протокол продумать, а там поглядим.
Но идеи почему я дурак, выслушаю с радостью. Но только обоснованные )
питание полное. на отладке от усб с компа, ради прикола сейчас подключил внешнее - все так же (
Ок. Оставляем вызов "перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных", но закоменти все
digitalWriteостается влияние?85.00, насколько я помню - это начальное состояние регистра датчика. Стр. 6 ДШ.
Ну и я ещё разок попробую...
Без задержки этот датчик не будет нормально работать. Значит нужна альтернатива дилэю, с которым работает, но моргает.
Открываете ДШ на датчик и находите параметр Temperature Conversion Time.
Вот на это самое время и нужна задержка, минимум, взависимости от заданной разрядности.
Контрольный вопрос - showDisplay() за какое время выполняется, что вы его вместо дилэя воткнули?
Контрольный вопрос - showDisplay() за какое время выполняется, что вы его вместо дилэя воткнули?
Почему вместо? написали же - перед!
Проверить датчик (заменой на заведомо исправны), правильность подключения и надёжность соединения.
Это то, что нужно было сделать в первую очередь...
ЗЫ. Есть уникумы, которые регулярно путают цоколёвку датчика из-за характрного обозначения на корпусе.
А... Ай эм сории, прочитал, как "вместо" ))
OlegK, при все уважении, какайте в других ветках. Датчик работает. данные шлет. прочтите топик старт, обдумайте, прочтите еще раз, уйдите в рекурсию. Дня через три возвращайтесь
По теме. закомментил. не помогло (
P.S. закомментил еще и шифтауты - помогло. вот не могу понять этого бреда. при чем тут другие порты?
есть мысль, может кто быстрее наковыряет. на каких портах таймер 2 за шимы отвечает?
P.S. закомментил еще и шифтауты - помогло. вот не могу понять этого бреда. при чем тут другие порты?
Копайте питание. как мне, кажется. Перво наперво - кондеры на линию питания DS18B20. Поближе к датчику.
http://arduino.ru/Tutorial/Arduino_Interrupts_part2
Таймеры на Arduino
Я связался с Дэвидом Меллисом (David Mellis) из команды разработчиков Arduino и узнал, что Arduino пользуется всеми тремя таймерами ATMega168.
Используется для хранения счетчика времени работы программы. Функция millis() возвращает число миллисекунд с момента запуска программы, используя ISR глобального приращения таймера 0. Таймер 0 также используется для реализации ШИМ на выводах 5 и 6.
Используется для реализации ШИМ для цифровых выводах 9 и 10.
Используется для управления выходами ШИМ для цифровых выводов 3 и 11.
переставил с 3го выхода на 6й, 20% начал писать температуру, но 80% продолжает 8500
переставил с 3го выхода на 6й, 20% начал писать температуру, но 80% продолжает 8500
??? в коде же был 8 пин, а на 3 висело SCLK! На текущий момент мне нечего добавить :( завтра подключу ds18b20, побалуюсь.
переставил с 3го выхода на 6й, 20% начал писать температуру, но 80% продолжает 8500
Все таки, проверьте (желательно осцилографом) или обеспечьте нормальное питание датчика. 85 - это еще и сбой во время преобразования...
я и переставил с SCLK, не потому что он такой, а потому что он на втором таймере.
Копайте питание. как мне, кажется. Перво наперво - кондеры на линию питания DS18B20. Поближе к датчику.
Мозга нихт арбайтен, на сколько кондер лучше поставить?
и это, к сожалению, осцилографа нет. я программер вообще, электроника ко мне пришла в виде коробки с деталюшками, ардуиной и всяческой хренью ))) Во! у меня паялник есть )))) и даже мультиметр )))
Мозга нихт арбайтен, на сколько кондер лучше поставить?
да любой элетролит. от 100 микрофарад и больше . его задача - сгладить просадку питания. Ради прикола можете запитать датчик от отдельного источника только для него (про общую землю тока не забудьте).
Вот, кстати, пример подключения и считывания (Sanyaba +) и обсуждение DS18b20 на этом форуме.
Помог кондер. Поставил под руками что попалось 220мкф х 25в. Спасибо огромное за помощь
Сдаю готовый код, может кого на подвиги потянет. ) Код не прилизанный, доделывать необходимо до красоты, просто в нем сборник вражеских кусков, обучения на скорую руку и пачки нервов.
#define SCLK 6 #define RCLK 4 #define DIO 5 #include <OneWire.h> OneWire ds(11); byte digitBuffer[4]; volatile int _LCDData = 22, _counter = 0; byte data[9]; bool _timer2Setup(){ // запретить прерывание по переполнению счетчика 2 для внесения корректировки курса партии TIMSK2 &= ~(1<<TOIE2); // выбор источника синхронизации таймера ASSR &= ~(1<<AS2); // изменить регистр управления А счетчиком TCCR2A = (1<<WGM21); // режим работы: прерывание по совпадению // изменить регистр управления Б счетчиком TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024 // изменить регистр сравнения А счетчиком TCNT2 = 253; // разрешить прерывание по переполнению счетчика 2 для продолжения внедрения курса партии TIMSK2 |= (1<<TOIE2); } ISR(TIMER2_OVF_vect){ // OCR2A = 253; TCNT2 = 253; _counter++; switch (_counter){ case 20: showDisplay2(3); break; case 40: showDisplay2(2); break; case 60: showDisplay2(1); break; case 80: showDisplay2(0); _counter = 0; convertNumber(_LCDData, 2); break; } } void setup(){ pinMode(RCLK, OUTPUT); pinMode(SCLK, OUTPUT); pinMode(DIO, OUTPUT); Serial.begin(9600); Serial.println("Start"); _timer2Setup(); } void loop(){ _DSRequest(); delay(500); _DSGetData(); } void _DSRequest(){ ds.reset(); ds.write(0xCC); ds.write(0x44); } void _DSGetData(){ ds.reset(); ds.write(0xCC); ds.write(0xBE); for (int i = 0; i < 9; i++) { data[i] = ds.read(); } int Temp = ((data[1]<< 8) | data[0]); double Temp2 = (double)Temp * 100 / 16; Temp = (int)Temp2; Serial.print("data = "); Serial.println(Temp); _LCDData = Temp; } void convertNumber(int _number, int _pointPosition){ digitBuffer[3] = _number % 10; _number = _number / 10; digitBuffer[2] = _number % 10; _number = _number / 10; digitBuffer[1] = _number % 10; _number = _number / 10; digitBuffer[0] = _number % 10; _number = _number / 10; switch (_pointPosition){ case 0: digitBuffer[3] += 10; break; case 1: digitBuffer[2] += 10; break; case 2: digitBuffer[1] += 10; break; case 3: digitBuffer[0] += 10; break; } } void showDisplay2(byte _digit){ const byte digit[25] = {0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010, 0b10000010, 0b11111000, 0b10000000, 0b10010000, 0b01000000, 0b01111001, 0b00100100, 0b00110000, 0b00011001, 0b00010010, 0b00000010, 0b01111000, 0b00000000, 0b00010000, 0b11111111, 0b11110111, 0b10111111, 0b11111110, 0b10100011}; const byte chr[4] = {0b00001000, 0b00000100, 0b00000010, 0b00000001}; digitalWrite(RCLK, LOW); // Открываем защелку shiftOut(DIO,SCLK,MSBFIRST, digit[digitBuffer[_digit]]); // Отправляем байт с "числом" shiftOut(DIO,SCLK,MSBFIRST, chr[_digit]); // выбираем разряд digitalWrite(RCLK, HIGH); // Защелкиваем регистры (завтавляем защелку выставить состояние выводов соответственно отправленным байтам) }Вот тут в цикле можно делай как угодно гонять - не срывается. по идее должен быть 750мс, но нормально и 500мс
Помог кондер. Поставил под руками что попалось 220мкф х 25в. Спасибо огромное за помощь
Вот тут в цикле можно делай как угодно гонять - не срывается. по идее должен быть 750мс, но нормально и 500мс
Мусье знает толк в извращениях.)))) Посмотрите здесь, в 4 посте на WDT, в 47 на миллис для нескольких датчиков, на один переделывается легко. Поизящнее будет и блокирующих делаев нет в принципе.
500мС, не факт, что отдает верную температуру. Если преобразование еще не закончено и пришел запрос на считывание, будет возвращено предыдущее значение. Ну и такие частые замеры не рекомендованы для низких температур типа комнатной. Емеет место саморазогрев датчика.
1. на тему паузы не delay. я четко написал, что любые другие вводы/выводы прибивают данные с 1wire.
А Вам чётко написали, что проблемы надо решать по мере поступления. Сначала избавиться от delay, чтобы не колбасило экран, а там видно будет.
2. схема тут не нужна, все по программе ясно.
Вам, профессионалам, виднее, а вот нам тупым лохам схема нужна, т.к. без неё ничего непонятно. Например, чем Вы кормите датчик и экран? Как разведена земля? Если у дачика и экрана земля общая, без отдельных фильтров, то ... в общем, схема не нужна только тем, кто её на своём столе и так видит.
я написал более чем понятно. Любой ввод/вывод в любой порт (а это необходимо для обновления индикаторов) собьет данные с датчика на непонятные 85.00
Если Вам всё "более, чем понятно", нафига Вы пришли сюда и хамите людям, которые по ошибке посчитали, что Вам что-то непонятно и пытаются Вам помочь?
----------
В общем, схему в студию или помогайте себе сами, раз Вам всё "более, чем понятно".
1. на тему паузы не delay. я четко написал, что любые другие вводы/выводы прибивают данные с 1wire.
2. схема тут не нужна, все по программе ясно. для совсем полной картины скажу, что резистор на 4.7к на датчике висит.
Следующий ))) по I2C и 1wire - мой косяк, виноват. попутало чего-то в голове дурной )
OlegK. При всем уважении. Про код с флагами я написал более чем понятно. Любой ввод/вывод в любой порт (а это необходимо для обновления индикаторов) собьет данные с датчика на непонятные 85.00
Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных
Вы сами себе противоречите.