Работа с шиной 1-wire. Подключение термодатчика DS18B20 к AVR

Обновлено 21.01.14. Исходники переписаны под AVR Studio 6 (с тулчейном)

Сразу хочу сообщить, что в этой статье я не буду описывать принцип работы шины (описание временных слотов и т.д.). Статья будет типа «Быстрый старт». Конкретно: я выложу свою библиотеку для работы с 1-wire, опишу как ею пользоваться, как подключить устройства к шине, как производить поиск устройств, передавать данные и т.д. А так, как (вероятно) 70% радиолюбителей в первую очередь решит подключить к шине термодатчик DS18B20, я выложу библиотеку для работы с DS18B20, где надо тупо запустить преобразование, подождать пока идет преобразование и записать температуру в массив.

Теория

Итак, 1-wire(еще называют MicroLAN, dallas-wire) так назвали потому что для передачи данных в обе стороны используется только 1 провод. Среди самых популярных устройств, работающих на этой шине можно выделить термодатчик DS18B20 и электронный ключ DS1990 (которым вы в подъезде двери открываете). У сети 1-wire есть одно ведущее устройство(Master) и несколько (или 1) подчиненных (Slave). Бывают сети с несколькими ведущими, по это нам сейчас не нужно. Передачу данных начинает ведущий, только он может посылать сигнал сброса (Reset), остальные устройства могут только отвечать на его запросы. Все устройства подключаются к шине параллельно, то есть, линию данных с каждого устройства (она обозначается DATA, DQ или OW_DQ), включая линию ведущего, подключают к одному проводу, типа вот так: 

Еще линия должна быть подтянута к питанию через резистор 2,2-4,7 кОм. Каждое устройство имеет свой индивидуальный 64-битный адрес, который устанавливается при изготовлении устройства (прямо на заводе).

Практика

Работать с 1-wire мне приходится очень часто, поэтому, я написал безглючную библиотеку, которая имеет кучу функций, включая возможность эмуляции 1-wire с помощью USART. К тому же, библиотека стабильно работает даже в протеусе. Многие говорят, что 1-wire слишком медленный, а из-за того, что он требует очень точных временных задержек (в несколько микросекунд), с ним практически не возможно работать, если в микроконтроллере часто вызываются прерывания. Действительно, если одновременно использовать софтовый USB (V-USB) и 1-wire, то что то одно с них не будет стабильно работать. Я решил эту проблему эмуляцией 1-wire через USART микроконтроллера. Поэтому, если у вас будет свободный USART, то 1-wire обязательно вешайте на него. Как же будем подключать устройства? Я использую три (уже 4) способа. Первый. Эмуляция USARTом. Если вы используете длинную линию (более 20 метров) и более 4 устройств на шине, то подключать нужно вот так: Здесь сигнал усиливается с помощью двух транзисторов. На шине стоит метка OW_DQ, вот к ней и подключаем подчиненные устройства. Если длина не более 20 метров, то можно подключить вот так:Здесь резистор может быть номиналом 2,2 — 4,7 кОм. Если вы не используете USART для эмуляции 1-wire, то подключать нужно так:Здесь одна ножка МК работает в качестве и входа, и выхода. Есть еще и четвертый способ, подключение как на первом, только для эмуляции не используется USART, но мне этот способ ни разу не понадобился. Давайте теперь соберем схему в протеусе (можете скачать в прикрепленных файлах). USART будет занят терминалом, поэтому шина будет подключена по третьем способу. В качестве ведущего — ATMega8, подчиненные — термодатчики DS18B20 и DS18S20, память EEPROM на 256 Кбит, таблетка, DS18B20 и двухканальный ключ DS2413. Так же, на схеме есть терминал, в котором будут отображаться данные.

Код

Скачайте прикрепленные файлы и откройте onewire.h. В нем есть строка

#define MAXDEVICES 10

Здесь указывается максимальное количество подчиненных устройств, которые будет искать подчиненный, если выберите меньше, чем подключено, то просто не будут обнаружены все устройства, если больше — то увеличиться время процедуры поиска. Но лучше ставьте с запасом, при 32 поиск занимает не более двух секунд (а может и меньше секунды).

#define UART_AS_OneWire

Если вы не используете эмуляцию 1-wire через USART, то закомментируйте эту строку.

#define OW_DDR DDRB
#define OW_PORT PORTB
#define OW_PIN PINB
#define OW_BIT 0

Если не используется эмуляция, укажите здесь куда подключен 1-wire. В том же файле есть несколько функций:

unsigned char OW_Reset(void);
void OW_WriteBit(unsigned char bit);
unsigned char OW_ReadBit(void);
unsigned char OW_ReadByte(void);
void OW_WriteByte(unsigned char byte);
unsigned char OW_SearchROM( unsigned char diff, unsigned char *id );
void OW_FindROM(unsigned char *diff, unsigned char id[]);
unsigned char OW_ReadROM(unsigned char *buffer);
unsigned char OW_MatchROM(unsigned char *rom);

По названию функции можно определить их предназначение, поэтому не стоит их описывать. В исходниках откройте главный файл (main.c). Здесь есть функция search_ow_devices(), она производит поиск устройств на шине и записывает их адреса в многомерный массив owDevicesIDs[MAXDEVICES][8], возвращает количество найденных устройств. Вот главная функция:

int main(void)
{
	stdout = &usart_str; // указываем, куда будет выводить printf 
 
	DDRB = 0b00000000; PORTB = 0b00000000;
	DDRC = 0b00000000; PORTC = 0b00000000;
	DDRD = 0b00000010; PORTD = 0b00000000;
 
	USART_init(); // включаем uart
 
	timerDelayInit();
 
	nDevices = search_ow_devices(); // ищем все устройства
 
	printf("---------- Found %d devices ----------", nDevices);
 
	for (unsigned char i=0; i<nDevices; i++) // теперь сортируем устройства и запрашиваем данные
	{
		// узнать устройство можно по его груповому коду, который расположен в первом байте адресса
		switch (owDevicesIDs[i][0])
		{
			case OW_DS18B20_FAMILY_CODE: { // если найден термодатчик DS18B20
				printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес
				printf(" - Thermometer DS18B20"); // печатаем тип устройства
				DS18x20_StartMeasureAddressed(owDevicesIDs[i]); // запускаем измерение
				timerDelayMs(800); // ждем минимум 750 мс, пока конвентируется температура
				unsigned char	data[2]; // переменная для хранения старшего и младшего байта данных
				DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные
				unsigned char	themperature[3]; // в этот массив будет записана температура
				DS18x20_ConvertToThemperature(data, themperature); // преобразовываем температуру в человекопонятный вид
				printf(": %d.%d C", themperature[1],themperature[2]);
			} break;
			case OW_DS18S20_FAMILY_CODE: { // если найден термодатчик DS18B20
				printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес
				printf(" - Thermometer DS18S20"); // печатаем тип устройства
			} break;
 
			case OW_DS1990_FAMILY_CODE: { // если найден электронный ключ DS1990
				printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес
				printf(" - Serial button DS1990"); // печатаем тип устройства
			} break;
			case OW_DS2430_FAMILY_CODE: { // если найдена EEPROM
				printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес
				printf(" - EEPROM DS2430"); // печатаем тип устройства
			} break;
			case OW_DS2413_FAMILY_CODE: { // если найден ключ
				printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес
				printf(" - Switch 2413"); // печатаем тип устройства
			} break;
		}
	}
while(1){}
}

В начале у нас идет инициализация периферии, затем, производится поиск устройств на шине и найденное количество записывается в переменную nDevices. Далее, в цикле for определяется тип устройства (его можно определить по первом байту адреса). В терминале протеуса печатается адрес каждого устройства и его тип: Как видите, напротив DS18B20 написана еще и его температура, глянем в код:

printf("\r"); print_address(owDevicesIDs[i]); // печатаем знак переноса строки, затем - адрес
printf(" - Thermometer DS18B20"); // печатаем тип устройства
DS18x20_StartMeasureAddressed(owDevicesIDs[i]); // запускаем измерение
timerDelayMs(800); // ждем минимум 750 мс, пока конвентируется температура
unsigned char	data[2]; // переменная для хранения старшего и младшего байта данных
DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные
unsigned char	themperature[3]; // в этот массив будет записана температура
DS18x20_ConvertToThemperature(data, themperature); // преобразовываем температуру в человекопонятный вид
printf(": %d.%d C", themperature[1],themperature[2]);

В первых двух строчках просто печатается адрес устройства и его тип. Затем, запускается измерение с помощью функции DS18x20_StartMeasureAddressed(owDevicesIDs[i]);. В эту функцию передается массив с адресом устройства. Далее, нужно подождать 750 мс, пока конвертируется температура, после чего, считываем данные с устройства DS18x20_ReadData(owDevicesIDs[i], data);. В функцию передается указатель на массив с адресом и указатель на массив, в который надо записать результат (2 байта). Теперь надо перевести эти 2 байта в человекопонятный вид, то есть, «знак, целая часть, запятая, десятая часть», это делает функция DS18x20_ConvertToThemperature(data, themperature);. Кстати, совсем не обязательно для запуска измерения температуры передавать адрес устройства, можно просто написать DS18x20_StartMeasure(). Тогда преобразование запустится на всех DS18B20, которые подключены к шине, спустя 750мс можно считать данные по очереди со всех DS18B20 без задержки. Так же, если используете эмуляцию 1-wire через USART, то обязательно устанавливайте не только DDR пина TX, а и PORT, иначе обмен на шине будет запускаться максимум в 30% случаев.

Обновление №1 (5.12.2011):

Добавил возможность подключения четвертым способом. Подключение такое же как в первых двух, но для эмуляции не используется USART. Этот способ стоит использовать если у Вас занят USART и линия длинней 15-20 метров. В файле onewire.h появились новая опция:

// Если для эмуляции 1-wire не спольльзуется USART, но используется 2 пина (вход и выход)
#define OW_TWO_PINS

Также Вам стоит немного взглянуть сюда:

	#ifndef OW_TWO_PINS //если используется один пин, укажите его номер
		#define OW_BIT 0
	#else // если используются 2 пина, укажите их номера
		#define OW_BIT_OUT 1
		#define OW_BIT_IN 0
	#endif

При настройке портов нужно установить DDR и PORT входа в 0, а выхода в 1.

Обновление №2 (3.1.2012):

Добавил возможность проверки CRC. Теперь функция DS18x20_ReadData() возвращает 0, если crc ошибочная. Зачем это нужно? Делал один проект, где на шине висит много датчиков и есть вероятность, что после прочтения адреса один из датчиков может быть отключен и система должна знать, что его нет, но функция DS18x20_ReadData() возвращает 1, если на шине есть любое устройство 1-wire, так как наличие устройства функция определяет с помощью функции OW_Reset(). Теперь с датчика считываются не только первые 2 байта, в которых температура, а все 9, вместе с контрольной суммой (CRC), контрольная сумма проверяется, и если она не совпала, то возвращается 0. Вопросы в комментариях.

Скачать исходники и проект в Proteus (84 Kb)

175 комментариев Работа с шиной 1-wire. Подключение термодатчика DS18B20 к AVR

  • avtoneru

    Статья понравилась
    единсвенное не нашел в ней упоминания про среду прогаммирования вот и гадаю… вроде WinAvr?

  • maxlenin1979

    Доброго времени суток)Очень понравилась мне ваша статья)но…есть но..не как у меня датчики не ищутся…ну вообщем не чего не происходит))ткините мея носом есле не сложно что я нетак делаю))юарты все заняты так что эмуляция их отпадает))тоесть закоментил как указано выше) пин изменил на 7 …и тишина

  • maxlenin1979

    может это звучит нагло)) но всётаки попрошу используется ATMEGA 128 порт В7 тоесть один пин и именно этот если не трудно подскажите дефайны

  • maxlenin1979

    // Если для эмуляции шины используется USART
    //#define UART_AS_OneWire

    // Если для эмуляции 1-wire не спольльзуется USART, но используется 2 пина (вход и выход)
    //#define OW_TWO_PINS

    #ifdef UART_AS_OneWire
    #define USART_BAUDRATE_57600 (((F_CPU / (57600 * 16UL))) — 1)
    #define USART_BAUDRATE_115200 (((F_CPU / (115200 * 16UL))) — 1)
    #define USART_BAUDRATE_9600 (((F_CPU / (9600 * 16UL))) — 1)
    #else
    #include
    #define OW_DDR DDRB
    #define OW_PORT PORTB
    #define OW_PIN PINB
    #ifndef OW_TWO_PINS //если используется один пин, укажите его номер
    #define OW_BIT 7
    #else // если используются 2 пина, укажите их номера
    #define OW_BIT_OUT 1
    #define OW_BIT_IN 0
    #endif
    #endif
    я сделал так….. подскажите плиз..,с уважением)

  • Kibermaster

    все правильно.
    А как вы проверяете?

  • maxlenin1979

    в main.c покачто добавил

    timerDelayInit();
    nDevices = search_ow_devices(); // ищем все устройства
    и в протеусе смотрю ммм..ну вообщем буферы в которых должны быть ром коды,а так же попробовал посмотреть активность ослогрофом на pin 7 port B и в общем не чего не там не там,таймер 0 более не где не использован avr studio 4.18

  • maxlenin1979

    тоесть строку timerDelayInit(); закоментить или удалить а частота задана в свойсвах проекта 8 мгц я правильно вас понял?

  • maxlenin1979

    мне очень не удобно вас отвлекать но может комуто еще пригодится,а может гдето как то еще инициализировать порт к которому подключены датчики

  • maxlenin1979

    ммм а каким образом это сделать я может плохо искал но не нашёл ваших координатов

  • maxlenin1979

    тоесть вот на эту почту?admin@kibermaster.net

  • maxlenin1979

    Большое спасибо всё работает! проблема была в оптимизации

  • Доброго дня, можно вопрос — как в протеусе Вы проверяете
    работу по двум пинам?

  • отбой вопроса сори посмотрел вложенный архив, недавно обновили! «Доброго дня, можно вопрос — как в протеусе Вы проверяете
    работу по двум пинам?»

  • maxlenin1979

    в шпротеусе вообще есть замчательная вещь!! и2с дебуггер))

  • Vitaliyli

    Что-то как-то не то… Прикладываю ключ от домофона Метаком универсальный, читает и показывает нормально (01 FF FF FF FF FF FF 2F). А вот если я прикладываю другие ключики от домофона, то показывает множество устройств и код из семи FF и CRC, то же самое будет, если закоротить на землю вход. В чем может быть причина?

  • zoomerland

    Пробовал подключать и 3 и 4 способами, один и несколько датчиков ds18b20, всегда находит 0 устройств (((.
    Питание не паразитное.
    Код пишу и компилирую в Atmel Studio 6.
    Подскажите пожалуйста где может быть ошибка.

  • Joberr

    Огромнейшее спасибо автору за чудо-библиотеку.
    Применил к своему устройству — работает на ура, но все-таки нашел глюк в конвертировании температуры. В файле ds18x20.c написал так:
    themp[2] = data[0]&0xf;
    themp[2] *= 0.625;//дробная часть будет от 0 до 9
    if (data[1]>0xFB){
    themp[2] = 10-themp[2];//при минусовой тоже глюк
    themp[1] = 127-themp[1];
    themp[0] = ‘-‘;

  • Алексей Новак

    Проблема так же как и у zoomerland
    Настроил под Atmel Studio 6, себе вставил только поиск устройств. При компиляции в протеусе пин даже не дёргается. Всегда найдено 0 устройств. Железо будет готов через неделю-полторы, поэтому пока проверяю только в протеусе.
    Может есть какой-то нюанс совместимости кода.

    • Kibermaster

      если скомпилировалось без ошибок, то вообще то, должно работать. Возможно, вы схему в протеусе не правильно собрали? Попробуйте с одним устройством на шине

      • Алексей Новак

        Компилируется без ошибок и предупреждений.
        Есть только лог.0 длительностью 60мкс. и всё. Он при каждой попытке найти устройства.
        Как delay.h завязан на формировании задержек? У меня подключён стандартный delay.h и указана частота 8МГц. Ну в протеусе соответственно указано что контроллер тактируется от 8МГц.

  • a.v.solovev

    Не работало сначало в Avre 5. долго мучался пока не разобрался с delay.h . очень чувствительна к задержкам.

  • Unfortunately

    Скачал архив, сразу же запустил в Proteus’е. РАБОТАЕТ!!!
    Открыл проект в AVR Studio 4 и, не меняя код, скомпилировал. Возвращаюсь в Proteus — «Найдено 0 устройств». Что я сделал не так?)

  • alsh

    Я попытался перенести ваш код на at90usb162, однако как я понял там нет U2X. Возможно ли переделать Ваш код чтобы он заработал на этом камне?

  • ua3gbv

    Здравствуйте. Скажите пожалуйста, «Так же, если используете эмуляцию 1-wire через USART, то обязательно устанавливайте не только DDR пина TX, а и PORT, иначе обмен на шине будет запускаться максимум в 30% случаев.» — в каком месте это делается?
    Если здесь:
    #ifdef UART_AS_OneWire
    #define USART_BAUDRATE_57600 (((F_CPU / (57600 * 16UL))) — 1)
    #define USART_BAUDRATE_115200 (((F_CPU / (115200 * 16UL))) — 1)
    #define USART_BAUDRATE_9600 (((F_CPU / (9600 * 16UL))) — 1)
    #else
    #include
    #define OW_DDR DDRD
    #define OW_PORT PORTD
    #define OW_PIN PIND
    #ifndef OW_TWO_PINS
    #define OW_BIT 1
    #else
    #define OW_BIT_OUT 1
    #define OW_BIT_IN 0
    #endif
    #endif
    то то, что касается пинов в случае использования USART не используется же…
    Ни как не удается запустить (

  • Skaarj

    Здравствуйте. Помогите пожалуйста разобраться. Собрал проект в Winavr, используется один пин, 8 мгц, запустил на atmega8 — работает как положено. Но мне нужно это все запустить на atmega88, я пересобрал для это мк, подключил к соответствующему пину — устройств не находит, в процедуре OW_Reset переменная status получает значение 0x08, а должен быть, как я понял, ноль. Где может крыться проблема? Спасибо!

  • Kibermaster

    думаю, что из-за такой малой частоты не корректно работают микросекундные задержки. Сделай через UART

  • Skaarj

    Скажите пожалуйста, как быть с atmega64 при работе через USART? У него в регистре UCSRnC нету бита URSEL. Спасибо.

  • alex

    Подскажите, надо ли делать какой-то сброс состояния датчика после измерения? Вычитываю данные ds18b20 в цикле и с большой долей вероятности через раз в data[0] находится 0xff. Пауза 1с в цикле не помогла.

    Еще интересует почему на схеме в протеусе используются два пина PB0 и PB1 в статье только PB0? Дело в том что на одном пине у меня не завелся датчик, а на двух и с OW_TWO_PINS завелся, но пока что с проблемами (см выше).

    • Kibermaster

      На схемах изображено несколько вариантов подключения, в протеусе — один с них (не помню какой).
      Советую вам использовать код из этой статьи, если заведется, то переносите его в ваш проект.
      А эта пауза 1с у вас между запуском измерения и считыванием данных?

  • Rostislaw

    Здравствуйте, искал адекватную библиотеку для работы по 1-wire, ваша понравилась очень, но запустить никак не выходит. Работаю сразу в железе.
    Инициализация:
    // Максимальное количество устройств на шине
    #define MAXDEVICES 8

    // Если для эмуляции шины используется USART
    //#define UART_AS_OneWire

    // Если для эмуляции 1-wire не спольльзуется USART, но используется 2 пина (вход и выход)
    //#define OW_TWO_PINS

    #ifdef UART_AS_OneWire
    #define USART_BAUDRATE_57600 (((F_CPU / (57600 * 16UL))) — 1)
    #define USART_BAUDRATE_115200 (((F_CPU / (115200 * 16UL))) — 1)
    #define USART_BAUDRATE_9600 (((F_CPU / (9600 * 16UL))) — 1)
    #else
    #include
    #define OW_DDR DDRA
    #define OW_PORT PORTA
    #define OW_PIN PINA
    #ifndef OW_TWO_PINS //если используется один пин, укажите его номер
    #define OW_BIT 0
    #else // если используются 2 пина, укажите их номера
    #define OW_BIT_OUT
    #define OW_BIT_IN
    #endif
    #endif

    частота проинициализирована как #define F_CPU 8000000UL

    Ссылка на архив с проектом: https://dl.dropboxusercontent.com/u/34620857/MQ.rar
    Заранее спасибо!

  • va_st

    void DS18x20_ConvertToThemperature(unsigned char* data, unsigned char* themp)
    {
    unsigned int tmp = 0;
    if ((data[0]==0x00)&&(data[1]==0x00)){
    themp[0] = ‘ ‘;
    }
    else if(data[1]>0xFB){
    themp[0] = ‘-‘;
    tmp = ((unsigned int)data[1]<>8;
    }
    else themp[0] = ‘+’;
    //Store temperature integer digits and decimal digits
    themp[1] = ((data[1]&7)<>4);
    //Store decimal digits
    themp[2] = (data[0]&15);
    themp[2] = (themp[2]<<1) + (themp[2]<>4);
    }
    подправил,при минусовых значениях разница в 1 была

  • va_st

    void DS18x20_ConvertToThemperature(unsigned char* data, unsigned char* themp)
    {
    unsigned int tmp = 0;
    if ((data[0]==0x00)&&(data[1]==0x00)){
    themp[0] = ' ';
    }
    else if(data[1]>0xFB){
    themp[0] = '-';
    tmp = ((unsigned int)data[1]<>8;
    }
    else themp[0] = '+';
    //Store temperature integer digits and decimal digits
    themp[1] = ((data[1]&7)<>4);
    //Store decimal digits
    themp[2] = (data[0]&15);
    themp[2] = (themp[2]<<1) + (themp[2]<>4);
    }

  • va_st

    чет херня с отображением=)

  • Ace Ventura

    Подскажите пожалуйста, использую Вашу библиотеку через USART, работает все довольно стабильно и хорошо. Теперь возник вопрос, подключения питания к датчику не отдельным проводом +5В,а брать питание от линии данных, как это возможно реализовать?
    Спасибо.

  • Ace Ventura

    Может возможно после передачи запроса на запуск измерения подтягивать 1 на ножку, чтобы по линии данных шли 5В, а по достижению 750мс читать?

  • Kibermaster

    наверно, никак, можете разве что в ноге DQ подключить осциллограф и посмотреть, есть ли высокий уровень во время измерения.

  • Какие файлы нужно добавить в свой проект (Atmel studio 6) для использования библиотеки. Какими функциями пользоваться?

  • RusikOk

    есть библиотека для работы с DS2413?
    какие вообще у вас есть библиотеки по даласу кроме DS18x20?

  • Скажите как обрабатывать данные с двух датчиков DS18B20 подключенных к одной шине?

  • Антон

    Здравствуйте!Возникает странная проблема,при подключении микроконтроллера к компу с помощью преобразователя FT232 и открытии порта из значимых данных приходит только серийный номер,а вместо значения температуры символ ‘?’.Тестил только на железе,МК AtMega32.Такая же история наблюдалась с датчиком SHT75,но с другой программой.Помогите,пожалуйста,разобраться,в чем может быть проблема такого поведения.

    • Kibermaster

      Попробовать другой преобразователь. Я вообще FT232 не применяю из-за его глюков, вместо него применяю CP2102

      • Антон

        Он у меня на PinBoard-e стоит,в будущем буду пускать через ENC28J60 сигнал от датчиков по сети,пока хотел отладить по uart-у,попроще думал будет.Спасибо за ответ,попробую сразу через сеть,т.к. cp2102 в наличии нет,а enc уже на плате и работает(тестил udp),может так что путное выйдет!

  • ky

    Для начала хочу сказать спасибо за лаконичную и функциональную библиотеку, аналоги этими качествами не блещут =)

    У меня небольшая проблема:
    в протеусе UART-режим работает крайне нестабильно, при поиске устройств на шине с двумя датчиками часто либо зависает ( while(!CheckBit(UCSRA, T/RXC)) ), либо не находит ни одного (OW_DATA_ERR), либо находит один. Иногда срабатывает как надо. В софтварном режиме всё работает отлично. У вас случаем нет мыслей по поводу того, в чём может быть затык?

    Заранее признаетелен.

  • Skaarj

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

    • Kibermaster

      85 — это значение темепратуры при инициализации. Тоесть, если подать питание и считать, не запустив измерение, будет получено 85

      • Skaarj

        Мне не понятно почему оно считывается в таком случае

        // работа с устройствами 1-wire
        void sensors(void){

        timerDelayInit();
        nDevices = search_ow_devices(); // ищем все устройства

        for (unsigned char i=0; i<nDevices; i++){ // теперь сортируем устройства и запрашиваем данные
        // узнать устройство можно по его групповому коду, который расположен в первом байте адресса
        switch (owDevicesIDs[i][0]){
        case OW_DS18B20_FAMILY_CODE: { // если найден термодатчик DS18B20
        DS18x20_StartMeasure(owDevicesIDs[i]); // запускаем измерение
        timerDelayMs(800); // ждем минимум 750 мс, пока конвертируется температура
        // _delay_ms(800);
        unsigned char data[2]; // переменная для хранения старшего и младшего байта данных
        DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные
        float themperature = DS18x20_ConvertToThemperatureFl(data); // преобразовываем температуру в человекопонятный вид
        temper[0+i]=themperature;
        break;
        }
        }
        }
        }

        а если использовать _delay_ms(800); вместо timerDelayMs(800); и timerDelayInit(); все нормально

        Не судите строго, я новичок)

  • Skaarj

    Если использовать _delay_ms вместо timerDelayMs все нормально, для чего был добавлен timerDelayMs?

  • Skaarj

    У меня еще один вопрос, как выполнить быстрое прерывание цикла с запуском процедуры считывания температуры. Я разрешаю прерывание по кнопке, но оно срабатывает с третьего раза.

  • sasha_1973

    Доброго Здоровья!

    Kibermaster!
    Если дляВас не сильно обременительно, не могли-бы Вы пересобрать пример с использованием AVR Studio 4.19 с задействованным вариантом работы с 1Ware по USART?

    • Kibermaster

      А что если вы сами это сделаете?

      • sasha_1973

        Дело в том, что я пишу в среде Bascom, с «Си» не знаком абсолютно. Единственное, что стоит, так это AVR Studio 4.19, да и то, только, как программатор.

        Прошу прощения за безпокойство, уже не надо. Написал реализацию работы сам, согласно документации «#AN124 (Using a UART to Implement a 1-Wire Bus Master)».

        Если Вас не сильно затруднит, алгоритм поиска ID устройств больше 1? Что-то этот момент никак не хочет поддаваться. Принимаю всё время «1», хотя в то-же время, поиск и чтение одного устройства, работает без проблем.

  • Artemizus

    Вопрос может показаться глупым, но прошу простить, я начинающий.
    DS18x20_ReadData(owDevicesIDs[i], data); // считываем данные
    float t = DS18x20_ConvertToThemperatureFl(data); // преобразовываем температуру в человекопонятный вид
    printf(": %3.2f C", t);

    Если не ошибся, переменная t и есть значение температуры. Это значение нужно вывести на LCD дисплей с помощью функции lcd_string(0x93, ); Как это можно осуществить?

  • Artemizus

    Спасибо! Правильно понял, что это перевод из float в char? Правда на дисплей все-равно не выводится, черные квадраты вместо значений (остальные слова и символы выводятся нормально).

  • Vasiliy

    Перевел Вашу библиотеку в CodeVisionAVR. Эмуляция USARTом. Схема 2. Запуск измерения DS18x20_StartMeasure, программная задержка 750 мс — тогда работает. Если запуск измерения делаю по прерыванию INT1 (запуск от внешнего таймера 1Гц) — перестает работать. Другие функции в прерывании тоже перестают обрабатываться. Идея — раз в секунду запускать измерение (не надо ждать 750 мс, пока конвертируется температура), а потом вывод на LCD. Подкажите, пожалуйста, в чем может быть дело.

  • energaton

    Замечательная библиотека, отлично работает. Но подключил датчик DS18B20 с паразитным питанием и не работает. Пробовал ардуиновскую бибилиотеку, работает. Что нужно поменять в библиотеке?

  • kirill345677

    Добрый день. Большое спасибо вам за библиотеку.

    У меня такая проблема при подключении.

    Подключаюсь методом 3 (одна ножка МК работает в качестве и входа, и выхода). Питание не паразитное. Найдено 1 устройство, как и ожидалось, но вот вместо температуры возвращается пустое значение:

    ———- Found 1 devices ———-
    28 61 4A AB 06 00 00 52 — Thermometer DS18B20: ? C

    Можете ли подсказать, в чем может быть причина?
    Спасибо.

  • Vasiliy

    В функции search_ow_devices выполняем поиск устройств пока diff != OW_LAST_DEVICE && sensors_count < MAXDEVICES. При этом OW_LAST_DEVICE всегда = 0, соответственно и вся правая часть всегда = 0? Я правильно понял?
    Проблема — находит только одно устройство…

  • Vasiliy

    Так в чем смысл такого кода?

  • Vasiliy

    Читал, и не раз. И на разных языках..
    Хочется понять этот код. Он несколько шире чем DS18B20.

  • Vasiliy

    А Вы за основу что брали? Какой AppNote?

    • Kibermaster

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

  • Vasiliy

    Через USART у меня тоже все работает. Теперь пробую через DS2482-100. Возникли проблемы, стал подробно изучать код. Появились дополнительные вопросы. Сами как думаете, какая идея заложена в diff != OW_LAST_DEVICE && sensors_count < MAXDEVICES ?

  • Vasiliy

    Совершенно бы согласился. Но OW_LAST_DEVICE константа…

  • Vasiliy

    Тогда условие цикла сокращается до diff != 0.
    diff — номер бита последнего несоответствия (от 64 до 1). Ниже 2, а тем более = 0, diff как бы и не может… И цикл получается бесконечным. Но на деле он завершатся. Как не пойму.

  • Nokrul

    Подскажите почему при компиляции Вашего проекта все нормально работает, но переношу Ваш код к себе в проект ругается на delay.c не определен F_CPU, в этом файле пишу F_CPU 8000000UL компилируется но не работает пишет foud 0 device в консоле протеуса? Может где то нужно глобально объявить я новичек подскажите пожалуйста?

  • bashsat

    Здравствуйте! Не могу вывести доли градусов на семисегментный индикатор. Целые числа выводятся правильно. Пробовал так: raz4 = ((temp & 0x0F)*625/1000);

  • krasdok

    У меня atmega32 макетная плата+lcd1602. Нужно прикрутить датчик ds18b20. Пишу на С в Atmel Studio 4. Но как-то все не получается. Очень нужна помощь!!! У кого есть рабочий пример на С??? Что-то я на этом датчике затормозился. Пример куча в интернете, но что-то не как работать их заставить не могу.
    Нужно помощь….

Leave a Reply