DS18B20 ведет себя непонятно

Grats
Offline
Зарегистрирован: 27.04.2017

Доброго времени суток.

Подскажите, в чем я ошибаюсь. Подключил к ардуино уно 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. Поэтому как ни изголяйся, паузу держать придется, а это приводит к миганию индикатора, что никак не приемлимо.

Где я ошибся?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1. Паузу совершенно необязательно держать при помощи delay(750).

2. Остального не понял. Вероятно потому что нет схемы.

T.Rook
Offline
Зарегистрирован: 05.03.2016

Просто, что бы привнести еще немного неразберихи - а при чем тут I2C? onewire и i2c совершенно разные протоколы. DS18B20 - это onewire

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Не используйте дилэи не и не будет странностей...
У вас есть две части кода для работы с датчиком, между ними должна быть задержка, но весь этот код не должен блокировать выполнение остальной части программы. Значит вам нужен флаг, с помощью которого определяется нужность выполнения первой части кода (до задержки), а также, переменная, которая будет хранить некое время, что бы знать, прошла задержка или нет.
Итого, всё сводится к виду -

//Переменные Флаг (логическая) и Время (беззнаковый лонг) - глобальные или статические
  if (Флаг) {
    //тут инициализация и команда на конвертацию
    Флаг = false;
  }
  if (!Флаг && millis() - Время > 750) { //750 - это ваша задержка
    Время = millis();
    //Выполняем преобразование данных
    Флаг = true;
  }
}
Grats
Offline
Зарегистрирован: 27.04.2017

1. на тему паузы не delay. я четко написал, что любые другие вводы/выводы прибивают данные с 1wire.

2. схема тут не нужна, все по программе ясно. для совсем полной картины скажу, что резистор на 4.7к на датчике висит.

Следующий ))) по I2C и 1wire - мой косяк, виноват. попутало чего-то в голове дурной )

OlegK. При всем уважении. Про код с флагами я написал более чем понятно. Любой ввод/вывод в любой порт (а это необходимо для обновления индикаторов) собьет данные с датчика на непонятные 85.00

Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных

T.Rook
Offline
Зарегистрирован: 05.03.2016

Grats пишет:

Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных

В качестве версии  - нестабильное питание во время вывода не рассматривали? Питание ds18b20 паразитное или полное?

Grats
Offline
Зарегистрирован: 27.04.2017

питание полное. на отладке от усб с компа, ради прикола сейчас подключил внешнее - все так же (

Меня больше смущает, что датчик не отлавливается. ммм. попробую уточнить. 1wire search говорит, что нет там никого. но отвечает, гад такой. может гемор в датчике, а я тут мозг всем компосирую... Сейчас попробую без one wire ручками протокол продумать, а там поглядим.

Но идеи почему я дурак, выслушаю с радостью. Но только обоснованные )

T.Rook
Offline
Зарегистрирован: 05.03.2016

Grats пишет:

питание полное. на отладке от усб с компа, ради прикола сейчас подключил внешнее - все так же (

Ок. Оставляем вызов "перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных", но закоменти все digitalWrite остается влияние?

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Grats пишет:
собьет данные с датчика на непонятные 85.00

85.00, насколько я помню - это начальное состояние регистра датчика. Стр. 6 ДШ.

Цитата:
Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных

Ну и я ещё разок попробую...
Без задержки этот датчик не будет нормально работать. Значит нужна альтернатива дилэю, с которым работает, но моргает.
Открываете ДШ на датчик и находите параметр Temperature Conversion Time.
Вот на это самое время и нужна задержка, минимум, взависимости от заданной разрядности.

Контрольный вопрос - showDisplay() за какое время выполняется, что вы его вместо дилэя воткнули?

T.Rook
Offline
Зарегистрирован: 05.03.2016

OlegK пишет:

Контрольный вопрос - showDisplay() за какое время выполняется, что вы его вместо дилэя воткнули?

Почему вместо? написали же - перед!

 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

Grats пишет:
может гемор в датчике, а я тут мозг всем компосирую

Проверить датчик (заменой на заведомо исправны), правильность подключения и надёжность соединения.
Это то, что нужно было сделать в первую очередь...

ЗЫ. Есть уникумы, которые регулярно путают цоколёвку датчика из-за характрного обозначения на корпусе.

 

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

T.Rook пишет:
Почему вместо? написали же - перед!

А... Ай эм сории, прочитал, как "вместо" ))

Grats
Offline
Зарегистрирован: 27.04.2017

OlegK, при все уважении, какайте в других ветках. Датчик работает. данные шлет. прочтите топик старт, обдумайте, прочтите еще раз, уйдите в рекурсию. Дня через три возвращайтесь

По теме. закомментил. не помогло (

P.S. закомментил еще и шифтауты - помогло. вот не могу понять этого бреда. при чем тут другие порты?

Grats
Offline
Зарегистрирован: 27.04.2017

есть мысль, может кто быстрее наковыряет. на каких портах таймер 2 за шимы отвечает?

T.Rook
Offline
Зарегистрирован: 05.03.2016

Grats пишет:

P.S. закомментил еще и шифтауты - помогло. вот не могу понять этого бреда. при чем тут другие порты?

Копайте питание. как мне, кажется. Перво наперво - кондеры на линию питания DS18B20. Поближе к датчику.

 

T.Rook
Offline
Зарегистрирован: 05.03.2016

http://arduino.ru/Tutorial/Arduino_Interrupts_part2

 

Таймеры на Arduino

Я связался с Дэвидом Меллисом (David Mellis) из команды разработчиков Arduino и узнал, что Arduino пользуется всеми тремя таймерами ATMega168.

  • Tаймер 0 (Системное время, ШИМ 5 and 6)
    Используется для хранения счетчика времени работы программы. Функция millis() возвращает число миллисекунд с момента запуска программы, используя ISR глобального приращения таймера 0. Таймер 0 также используется для реализации ШИМ на выводах 5 и 6.
  • Tаймер 1 (ШИМ 9 и 10)
    Используется для реализации ШИМ для цифровых выводах 9 и 10.
  • Tаймер 2 (ШИМ 3 и 11)
    Используется для управления выходами ШИМ для цифровых выводов 3 и 11.
Grats
Offline
Зарегистрирован: 27.04.2017

переставил с 3го выхода на 6й, 20% начал писать температуру, но 80% продолжает 8500

T.Rook
Offline
Зарегистрирован: 05.03.2016

Grats пишет:

переставил с 3го выхода на 6й, 20% начал писать температуру, но 80% продолжает 8500

???  в коде же был 8 пин, а на 3 висело SCLK!  На текущий момент мне нечего добавить :( завтра подключу ds18b20, побалуюсь.

T.Rook
Offline
Зарегистрирован: 05.03.2016

Grats пишет:

переставил с 3го выхода на 6й, 20% начал писать температуру, но 80% продолжает 8500

Все таки, проверьте (желательно осцилографом) или обеспечьте нормальное питание датчика. 85 - это еще и сбой во время преобразования...

Grats
Offline
Зарегистрирован: 27.04.2017

я и переставил с SCLK, не потому что он такой, а потому что он на втором таймере.

Grats
Offline
Зарегистрирован: 27.04.2017

T.Rook пишет:

Копайте питание. как мне, кажется. Перво наперво - кондеры на линию питания DS18B20. Поближе к датчику.

Мозга нихт арбайтен, на сколько кондер лучше поставить?

и это, к сожалению, осцилографа нет. я программер вообще, электроника ко мне пришла в виде коробки с деталюшками, ардуиной и всяческой хренью ))) Во! у меня паялник есть )))) и даже мультиметр )))

T.Rook
Offline
Зарегистрирован: 05.03.2016

Grats пишет:

Мозга нихт арбайтен, на сколько кондер лучше поставить?

 
 
 

 

да любой элетролит. от 100 микрофарад и больше . его задача - сгладить просадку питания. Ради прикола можете запитать датчик от отдельного источника  только для него (про общую землю тока не забудьте).

T.Rook
Offline
Зарегистрирован: 05.03.2016

Вот, кстати, пример подключения и считывания (Sanyaba +) и обсуждение DS18b20  на этом форуме.

Grats
Offline
Зарегистрирован: 27.04.2017

Помог кондер. Поставил под руками что попалось 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мс

bwn
Offline
Зарегистрирован: 25.08.2014

Grats пишет:

Помог кондер. Поставил под руками что попалось 220мкф х 25в. Спасибо огромное за помощь

Вот тут в цикле можно делай как угодно гонять - не срывается. по идее должен быть 750мс, но нормально и 500мс

Мусье знает толк в извращениях.)))) Посмотрите здесь, в 4 посте на WDT, в 47 на миллис для нескольких датчиков, на один переделывается легко. Поизящнее будет и блокирующих делаев нет в принципе.
500мС, не факт, что отдает верную температуру. Если преобразование еще не закончено и пришел запрос на считывание, будет возвращено предыдущее значение. Ну и такие частые замеры не рекомендованы для низких температур типа комнатной. Емеет место саморазогрев датчика.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Grats пишет:

1. на тему паузы не delay. я четко написал, что любые другие вводы/выводы прибивают данные с 1wire.

А Вам чётко написали, что проблемы надо решать по мере поступления. Сначала избавиться от delay, чтобы не колбасило экран, а там видно будет.

Grats пишет:

2. схема тут не нужна, все по программе ясно. 

Вам, профессионалам, виднее, а вот нам тупым лохам схема нужна, т.к. без неё ничего непонятно. Например, чем Вы кормите датчик и экран? Как разведена земля? Если у дачика и экрана земля общая, без отдельных фильтров, то ... в общем, схема не нужна только тем, кто её на своём столе и так видит.

Grats пишет:

я написал более чем понятно. Любой ввод/вывод в любой порт (а это необходимо для обновления индикаторов) собьет данные с датчика на непонятные 85.00

Если Вам всё "более, чем понятно", нафига Вы пришли сюда и хамите людям, которые по ошибке посчитали, что Вам что-то непонятно и пытаются Вам помочь?

----------

В общем, схему в студию или помогайте себе сами, раз Вам всё "более, чем понятно".

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Grats пишет:

1. на тему паузы не delay. я четко написал, что любые другие вводы/выводы прибивают данные с 1wire.

2. схема тут не нужна, все по программе ясно. для совсем полной картины скажу, что резистор на 4.7к на датчике висит.

Следующий ))) по I2C и 1wire - мой косяк, виноват. попутало чего-то в голове дурной )

OlegK. При всем уважении. Про код с флагами я написал более чем понятно. Любой ввод/вывод в любой порт (а это необходимо для обновления индикаторов) собьет данные с датчика на непонятные 85.00

Еще раз. Даже если перед delay(750); воткнуть showDisplay(); приводит к сбою в получении данных

Вы сами себе противоречите.