-=FISHER=-

DS18B20 выдает неадекватные показания при паразитном питании

79 сообщений в этой теме

-=FISHER=-    5

Здравствуйте!

 

В своей поделке применил датчик DS18B20, чтобы сэкономить провода, решил подключить его по двум проводам или при помощи так называемого паразитного питания. Однако, он всегда выдает мне температуру 27,5 С, и не изменяет показания при нагреве. Если же подключить его тремя проводами с отдельным питанием, то он сразу же начинает правильно измерять температуру. Опытные люди, будьте добры, подскажите в чём может быть проблема? Код и схема во вложении. Заранее спасибо!

Схема:

Скрытый текст

1.thumb.jpg.f6685d34d6fc443574e3bdc4ffe00442.jpg

Код для работы с DS18B20:

Скрытый текст

 


#include "DS18B20.h"

//функция определения датчика на шине
char dt_testdevice(void) //dt - digital termomether | определим, есть ли устройство на шине
{
	char stektemp=SREG;// сохраним значение стека
	cli(); //запрещаем прерывание
	char dt;
	DDRTEMP |= 1<<BITTEMP; //притягиваем шину
	_delay_us(485); //задержка как минимум на 480 микросекунд
	DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	_delay_us(65); //задержка как максимум на 60 микросекунд
	if ((PINTEMP & (1<<BITTEMP))==0)//проверяем, ответит ли устройство
	{
		dt=1;//устройство есть
	} 
	else dt=0;//устройства нет
	SREG = stektemp;// вернем значение стека
	_delay_us(420); //задержка как минимум на 480 микросекунд, но хватит и 420, тк это с учетом времени прошедших команд
	return dt; //вернем результат
}


//функция записи бита на устройство
void dt_sendbit(char bt)
{
	char stektemp=SREG;// сохраним значение стека
	cli(); //запрещаем прерывание
	DDRTEMP |= 1<<BITTEMP; //притягиваем шину
	_delay_us(2); //задержка как минимум на 2 микросекунды
	if(bt)
		DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	_delay_us(65); //задержка как минимум на 60 микросекунд
	DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	SREG = stektemp;// вернем значение стека
}
//функция записи байта на устройство
void dt_sendbyte(unsigned char bt)
{
	char i;		
	for(i=0;i<8;i++)//посылаем отдельно каждый бит на устройство
	{
		if((bt & (1<<i)) == 1<<i)//посылаем 1
			dt_sendbit(1);
		else //посылаем 0
			dt_sendbit(0);
	}	
}

//функция чтения бита с устройства
char dt_readbit(void)
{
	char stektemp=SREG;// сохраним значение стека
	cli(); //запрещаем прерывание
	char bt; //переменная хранения бита
	DDRTEMP |= 1<<BITTEMP; //притягиваем шину
	_delay_us(2); //задержка как минимум на 2 микросекунды
	DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	_delay_us(13);
	bt = (PINTEMP & (1<<BITTEMP))>>BITTEMP; //читаем бит
	_delay_us(45);
	SREG = stektemp;// вернем значение стека
	return bt; //вернем результат
}

//функция чтения байта с устройства
unsigned char dt_readbyte(void)
{
	char c=0;
	char i;
	for(i=0;i<8;i++)
		c|=dt_readbit()<<i; //читаем бит
	return c;
}

//функция преобразования показаний датчика в температуру
int dt_check(void)
{
	unsigned char bt;//переменная для считывания байта
	unsigned int tt=0;
	if(dt_testdevice()==1) //если устройство нашлось
	{
		dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине
		dt_sendbyte(T_CONVERT); //измеряем температуру
		_delay_ms(750); //в 9 битном режиме преобразования - 750 милисекунд
		dt_testdevice(); //снова используем  те же манипуляции с шиной что и при проверке ее присутствия
		dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине
		dt_sendbyte(READ_DATA); //даем команду на чтение данных с устройства
		bt = dt_readbyte(); //читаем младший бит
		tt = dt_readbyte(); //читаем старший бит MS
		tt = (tt<<8)|bt;//сдвигаем старший влево, младший пишем на его место, тем самым получаем общий результат
	}
	return tt;
}

//преобразование температуры в единицы
char converttemp (unsigned int tt)
{
	char t = tt>>3;//сдвиг и отсечение части старшего байта
	return t;
}

 

Изменено пользователем -=FISHER=-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

А вы подаете на линию данных 5 вольт "без резистора" - чтобы паразитно его запитать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
27 минут назад, ARV сказал:

А вы подаете на линию данных 5 вольт "без резистора"?

С подтяжкой 4,7к... В даташите правда говорят что нужно ещё мосфет для увеличения тока в момент конвертации и чтения температуры, однако я встречал схемы и без мосфета, где со слов автора паразитное питание и так работает.

321.JPG.60699a60d1469b0a3c6ce08e73c2a8a1.JPG

Вывод - уменьшить номинал подтягивающего резистора?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

какая длина провода до датчика? Подключите датчик пока прямо на разъём.

и что-то странное у вас в коде с сохранением и восстановлением стека, можете получить большие проблемы используя такой код на Си. Похоже код переводили с asm на Си. Лучше сохранять только флаг прерывания (I).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Darth_Vader    64

В чем смысл сохранять стек? Да и с запретом прерываний все странно.

Включение и выключение pull-up резистора - зачем?

Изменено пользователем Darth_Vader

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

Без принудительного соединения линии данных с 5в (отдельный MOSFET не нужен, у вас МК может выполнить эту функцию) работают только датчики с маркировкой DS18B20P или PAR.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Обычные датчики DS18B20 должны работать с паразитным питанием, но там есть несколько условий, одно из них

стр.11

Convert T [44h]

If the device is being used in parasite power mode, within 10μs (max) after this command is issued the master must enable a strong pullup on the 1-Wire bus for the duration of the conversion (t CONV) as described in the Powering the DS18B20 section.

видимо надо подавать "честную" единичку на 10 мкс после команды конвертации [44h]

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500
35 минут назад, technik-1017 сказал:

видимо надо подавать "честную" единичку на 10 мкс после команды конвертации [44h]

Только не на 10 мкс, а максимум 10 мкс спустя подачи команды, и держать её не менее длительности измерения.

Изменено пользователем ARV

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
13 часа назад, technik-1017 сказал:

какая длина провода до датчика? Подключите датчик пока прямо на разъём.

Испытываю поделку на столе, длинна провода не более 10 см.

12 часа назад, Darth_Vader сказал:

В чем смысл сохранять стек? Да и с запретом прерываний все странно.

Код работы с датчиком писал не я, взял с урока про программированию МК. С обычным подключением этот код хорошо отрабатывает...

 

11 час назад, technik-1017 сказал:

видимо надо подавать "честную" единичку на 10 мкс после команды конвертации [44h]

11 час назад, ARV сказал:

Только не на 10 мкс, а максимум 10 мкс спустя подачи команды, и держать её не менее длительности измерения.

То есть между вот этими строчками кода? А вы можете на пальцах объяснить пожалуйста, что значит подавать честную единичку?...

		dt_sendbyte(T_CONVERT); //измеряем температуру
		_delay_ms(750); //в 9 битном режиме преобразования - 750 милисекунд

Я так понимаю принудительно подать 1 на ножку, к которой подключен сигнальный контакт датчика, вот типа так?

DDRTEMP &= ~(1<<BITTEMP);

PINTEMP &= (1<<BITTEMP);

 

Изменено пользователем -=FISHER=-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500
Только что, -=FISHER=- сказал:

А вы можете на пальцах объяснить пожалуйста, что значит подавать честную единичку?...

По стандарту 1-wire ведущее устройство либо притягивает линию данных к нулю, формируя в ней 0, либо "отпускает" её в третье состояние, т.е. как бы бросает неподключенной, и тогда линия за счет подтягивающего резистора сама возвращается к лог.1. Подавать честную единичку - это значит, вместо "отпускания" линии выдать в неё 1 принудительно. Т.е. соединить линию с +5 не через резистор, а напрямую через порт МК.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
1 минуту назад, ARV сказал:

Т.е. соединить линию с +5 не через резистор, а напрямую через порт МК.

Отпустить и выдать на пин 1 так?:

DDRTEMP &= ~(1<<BITTEMP);

PINTEMP &= (1<<BITTEMP);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

DDRTEMP &= ~(1<<BITTEMP); устанавливает в соответствующем DDR-бите НОЛЬ, т.е. "отпускает" пин в третье состояние. А следующая команда у вас испортит регистр. А надо просто вывести 1 в оба регистра:

PINTEMP |= (1<<BITTEMP);
DDRTEMP |= (1<<BITTEMP);

А после замера вернуть, как было.

Причем именно в том порядке, как я написал: сначала вывести 1, т.е. включить внутреннюю подтяжку, а потом перевести порт на вывод "жесткой" единицы, иначе у вас кратковременно в линии пролетит 0 - мало ли, как датчик на него среагирует...

Изменено пользователем ARV
  • Лайк 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
4 минуты назад, ARV сказал:

 


DDRTEMP |= (1<<BITTEMP);

PINTEMP |= (1<<BITTEMP);

А после замера вернуть, как было.

Я правильно понял смысл, что необходимо отпустить шину и выставить на ней 1 и так продержать весь промежуток вот этой задержки? Как раз пока идёт заполнение регистров датчика?

_delay_ms(750); //в 9 битном режиме преобразования - 750 милисекунд

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

Правильно - датчик будет питаться от этой линии.

Обратите внимание: я подкорректировал свое сообщение - ваша цитата уже не соответствует истине!

  • Лайк 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
3 минуты назад, ARV сказал:

Правильно

Спасибо! Я сейчас пробежался по функциям и понял, что перед тем как "уйти в задержку" на 750мс, шина "отпущена", то есть достаточно дописать только вторую строчку перед задержкой и вот такую после, так?

PINTEMP |= (1<<BITTEMP); //выставляем 1 на шине, шина к этому моменту уже отпущена
_delay_ms(750); //в 9 битном режиме преобразования - 750 милисекунд
PINTEMP &= ~(1<<BITTEMP); //выставляем 0 на шине

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500
Только что, -=FISHER=- сказал:

то есть достаточно дописать только вторую строчку перед задержкой и вот такую после, так?

Не так. Шина отпущена - это значит, режим пина "ввод", а надо ВЫВОД.

  • Лайк 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5

@ARV Чтобы не создавать отдельную тему, не могли бы Вы глянуть схему, приведенную мной в первом посте. Всё вроде бы работает, но почему-то наблюдается писк дросселя... Дроссель вроде как рекомендуют включать для дополнительной точности опорного напряжения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

КАК может пищать дроссель, по которому не течет силовой пульсирующий ток?! 

5b6fd0cb62e048e48d26b04993b96622_2440a91

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
52 минуты назад, ARV сказал:

КАК может пищать дроссель?! 

Но если его убрать с платы, писк пропадает... Я кстати использую SMD дроссель.

И ещё плата потребляет 120-140 мА (мне кажется это многовато или нет?), да так что МС L78M05CDT ощутимо греется, хотя рассчитана на ток до 500мА.

Изменено пользователем -=FISHER=-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
KomSoft    375

Какой ток через сегменты задает MAX? 7 сегментов по 15мА - это 105мА. (например). А (12-5)*0.12 - 0.8Вт, это много для работы без радиатора, будет ощутимо греться, что вы и получаете. Тут главное не ток, а рассеиваемая мощность. 

Судя по резистору R1 вы задали ток через сегменты 30-40мА. Увеличьте его - яркость упадет, но ток уменьшится. Если использован нормальный индикатор, то 40мА даже пикового тока - это много. Если яркость устраивает, то можно увеличивать его до 60кОм (примерно)

Screenshot_2018-08-08-10-21-01-653_com.google.android.apps.docs.png

  • Лайк 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

Если дроссель пищит, это однозначно свидетельствует о том, что через него течет пульсирующий ток. Это может быть только в одном случае: у вас по питанию гуляют страшные пульсации - больше взяться току через дроссель не из-за чего, потребление опорного источника AVR мизерное. Так же я могу предположить, что на С6 тоже пульсации будут - проконтролируйте осциллографом. Если там окажутся пульсации больше 2 мВ - это будет свидетельствовать о том, что толку от ADC будет не много. 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
-=FISHER=-    5
7 часов назад, ARV сказал:

В качестве теста отключите программно индикацию - пропадет писк?

Писка нет, если плата работает от программатора. Писк только если подключаю плату к 12В от ЛБП.

9 часов назад, ARV сказал:

Не так.

Сделал вот так, теперь показывает всегда 85 С...

		DDRTEMP |= 1<<BITTEMP; //притягиваем шину
		PINTEMP |= (1<<BITTEMP); //выставляем 1 на шине
		_delay_ms(750); //в 12 битном режиме преобразования - 750 милисекунд
		PINTEMP &= ~(1<<BITTEMP); //выставляем 0 на шине
		DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину

Что я сделал не так?

Изменено пользователем -=FISHER=-

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
DDRTEMP &= ~ (1<<BITTEMP); // настраиваем порт на ввод. Подтяжка к "1" за счёт внешнего резистора
PINTEMP |= (1<<BITTEMP);   // включаем подтяжку к "1" внутри контроллера
DDRTEMP |= 1<<BITTEMP; 	   // настраиваем порт на вывод, появляется честная "1"
_delay_ms(750); //в 12 битном режиме преобразования - 750 милисекунд
DDRTEMP &= ~(1<<BITTEMP);  // настраиваем порт на ввод. Осталась подтяжка к "1" внутри контроллера
PINTEMP &= ~(1<<BITTEMP);  // отключаем подтяжку к "1" внутри контроллера. Осталась только подтяжка за счёт внешнего резистора

а PINTEMP это случайно не PINx?
Должно быть PORTTEMP, т.е. PORTx

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ARV    500

По крайней мере, 85 - это показания датика "по умолчанию", т.е. после того, как подали на него питание, но не подали команду "старт преобразования". Иначе говоря, датчик не получил команду, но отвечает корректно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас