Работа с шиной 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 обязательно вешайте на него. Как же будем подключать устройства? Я использую
Код
Скачайте прикрепленные файлы и откройте 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. Вопросы в комментариях.
Статья понравилась
ОтветитьУдалитьединсвенное не нашел в ней упоминания про среду прогаммирования вот и гадаю... вроде WinAvr?
угадали:). Точней в связки AVR Studio 4 + AVR Toolchain
ОтветитьУдалитьДоброго времени суток)Очень понравилась мне ваша статья)но...есть но..не как у меня датчики не ищутся...ну вообщем не чего не происходит))ткините мея носом есле не сложно что я нетак делаю))юарты все заняты так что эмуляция их отпадает))тоесть закоментил как указано выше) пин изменил на 7 ...и тишина
ОтветитьУдалитьможет это звучит нагло)) но всётаки попрошу используется ATMEGA 128 порт В7 тоесть один пин и именно этот если не трудно подскажите дефайны
ОтветитьУдалитьа про порт не забыли? что именно вы закомментировали в исходнике?
ОтветитьУдалить// Если для эмуляции шины используется 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
я сделал так..... подскажите плиз..,с уважением)
все правильно.
ОтветитьУдалитьА как вы проверяете?
в main.c покачто добавил
ОтветитьУдалитьtimerDelayInit();
nDevices = search_ow_devices(); // ищем все устройства
и в протеусе смотрю ммм..ну вообщем буферы в которых должны быть ром коды,а так же попробовал посмотреть активность ослогрофом на pin 7 port B и в общем не чего не там не там,таймер 0 более не где не использован avr studio 4.18
здесь таймер 0 не нужен вообще.
ОтветитьУдалитьЕсли вы правильно задали частоту, то это глюки протекса
тоесть строку timerDelayInit(); закоментить или удалить а частота задана в свойсвах проекта 8 мгц я правильно вас понял?
ОтветитьУдалитьмне очень не удобно вас отвлекать но может комуто еще пригодится,а может гдето как то еще инициализировать порт к которому подключены датчики
ОтветитьУдалитьскиньте полностью ваш проект
ОтветитьУдалитьммм а каким образом это сделать я может плохо искал но не нашёл ваших координатов
ОтветитьУдалитьтоесть вот на эту почту?admin@kibermaster.net
ОтветитьУдалитьБольшое спасибо всё работает! проблема была в оптимизации
ОтветитьУдалитьДоброго дня, можно вопрос - как в протеусе Вы проверяете
ОтветитьУдалитьработу по двум пинам?
отбой вопроса сори посмотрел вложенный архив, недавно обновили! "Доброго дня, можно вопрос — как в протеусе Вы проверяете
ОтветитьУдалитьработу по двум пинам?"
в шпротеусе вообще есть замчательная вещь!! и2с дебуггер))
ОтветитьУдалитьЧто-то как-то не то... Прикладываю ключ от домофона Метаком универсальный, читает и показывает нормально (01 FF FF FF FF FF FF 2F). А вот если я прикладываю другие ключики от домофона, то показывает множество устройств и код из семи FF и CRC, то же самое будет, если закоротить на землю вход. В чем может быть причина?
ОтветитьУдалитьНаверно, им нужно паразитное питание, а эта прошивка его не обеспечивает.
ОтветитьУдалитьПробовал подключать и 3 и 4 способами, один и несколько датчиков ds18b20, всегда находит 0 устройств (((.
ОтветитьУдалитьПитание не паразитное.
Код пишу и компилирую в Atmel Studio 6.
Подскажите пожалуйста где может быть ошибка.
а прошивку настраивали для конкретного способа?
ОтветитьУдалитьДа, настраивал. Может из-за того что меня ATMega16A и библиотека просто не знает этого микроконтроллера?
ОтветитьУдалитьэто обычная атмега16
ОтветитьУдалитьОгромнейшее спасибо автору за чудо-библиотеку.
ОтветитьУдалитьПрименил к своему устройству - работает на ура, но все-таки нашел глюк в конвертировании температуры. В файле 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 устройств. Железо будет готов через неделю-полторы, поэтому пока проверяю только в протеусе.
Может есть какой-то нюанс совместимости кода.
если скомпилировалось без ошибок, то вообще то, должно работать. Возможно, вы схему в протеусе не правильно собрали? Попробуйте с одним устройством на шине
ОтветитьУдалитьНе работало сначало в Avre 5. долго мучался пока не разобрался с delay.h . очень чувствительна к задержкам.
ОтветитьУдалитьКомпилируется без ошибок и предупреждений.
ОтветитьУдалитьЕсть только лог.0 длительностью 60мкс. и всё. Он при каждой попытке найти устройства.
Как delay.h завязан на формировании задержек? У меня подключён стандартный delay.h и указана частота 8МГц. Ну в протеусе соответственно указано что контроллер тактируется от 8МГц.
получается, что ведущий формирует ресет (устанавливает 0 на 60 мкс), но термодатчик не отвечает, значит проблемы в нем
ОтветитьУдалитьСкачал архив, сразу же запустил в Proteus'е. РАБОТАЕТ!!!
ОтветитьУдалитьОткрыл проект в AVR Studio 4 и, не меняя код, скомпилировал. Возвращаюсь в Proteus -- "Найдено 0 устройств". Что я сделал не так?)
а что используется в качестве компилятора? Winavr или тулчейн?
ОтветитьУдалитьAVR Toolchain
ОтветитьУдалитьЗАРАБОТАЛО!!! :)
ОтветитьУдалитьРешение:
- снёс Toolchain
- скачал свежую версию с офф.сайта
- установил
Я попытался перенести ваш код на at90usb162, однако как я понял там нет U2X. Возможно ли переделать Ваш код чтобы он заработал на этом камне?
ОтветитьУдалитьпо-мойму, у этого МК нужно указывать U2X0.
ОтветитьУдалитьPS: несколько лет назад работал и ним, проблем там было много, советую применить другой МК
К сожалению такого регистра там нет.
ОтветитьУдалитьлучше возьмите другой мк)) Кстати, at90usb162 не поддерживался WinAVR и хз, поддерживается ли сейчас тулчейном
ОтветитьУдалитьпроги компилятся
ОтветитьУдалитьда оно и у меня компилилось, только не работало, даже мигание светодиодом
ОтветитьУдалитьЗдравствуйте. Скажите пожалуйста, "Так же, если используете эмуляцию 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 не используется же...
Ни как не удается запустить (
Здесь: DDRD = 0b00000010; PORTD = 0b00000000;
ОтветитьУдалитьУвы, не помогло =( Здесь
ОтветитьУдалитьchar DS18x20_StartMeasure(void)
{
//Reset, skip ROM and start temperature conversion
if (!OW_Reset()) return 0;
функция сброса возвращает ноль, хотя и сам датчик и усилятор на мосфетах работают - проверено на USB-UART адаптере. Да и на анализаторе видно, что МК формирует сброс, датчик присутствие обозначает.
Покажите код инициализации и укажите МК и частоту
ОтветитьУдалитьВ main`е так:
ОтветитьУдалить#define XTAL 8000000L
#define baudrate 9600L
#define bauddivider (XTAL/(16*baudrate)-1)
#define HI(x) ((x)>>8)
#define LO(x) ((x)& 0xFF)
UBRRL = LO(bauddivider);
UBRRH = HI(bauddivider);
UCSRA = 0;
UCSRB = 1<<TXEN;
UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1;
Частота, соответственно 8 МГц, atmega16.
а инит ножек МК? Кстати, каким способом подключен 1-wire?
ОтветитьУдалитьНожки - как вы и подсказали, сразу за uart`ом - DDRD = 0b00000010; PORTD = 0b00000010; (при PORTD = 0b00000000 картина та же) Подключил по схеме с полевиками, по трем проводам, только BSS138 использовал.
ОтветитьУдалитьподключите по второй схеме (переделывать не много) и добейтесь стабильной работы. Советую для этого использовать код из статьи
ОтветитьУдалитьУвы, все варианты пробовал, видно не судьба. Буду свой вариант пилить, спасибо за то, что ответили! =)
ОтветитьУдалитьЗдравствуйте. Помогите пожалуйста разобраться. Собрал проект в Winavr, используется один пин, 8 мгц, запустил на atmega8 - работает как положено. Но мне нужно это все запустить на atmega88, я пересобрал для это мк, подключил к соответствующему пину - устройств не находит, в процедуре OW_Reset переменная status получает значение 0x08, а должен быть, как я понял, ноль. Где может крыться проблема? Спасибо!
ОтветитьУдалитьа какие регистры поменяли?
ОтветитьУдалитьСейчас сконфигурировано так:
ОтветитьУдалить//#define UART_AS_OneWire
//#define OW_TWO_PINS
#define OW_DDR DDRB
#define OW_PORT PORTB
#define OW_PIN PINB
#define OW_BIT 3
DDRB = 0b00000000; PORTB = 0b00000000;
DDRC = 0b00000000; PORTC = 0b00000000;
DDRD = 0b00000000; PORTD = 0b00000000;
Я где-то что-то упустил?
а подключение по какой схеме?
ОтветитьУдалитьПо третьему способу, только к пину PB3, два датчика DS18B20, на atmega8 все отлично работает, меняю в Makefile на atmega88, в протеусе меняю мк, ставлю частоту, подключаю так же - не работают. Где-то что-то не правильно делаю?
ОтветитьУдалитьЕсли не ошибаюсь, то в 88 есть фьюз, который делит частоту на 8 и по умолчанию он включен
ОтветитьУдалитьСпасибо, не внимательность... Скажите, а можно это все запустить на 1 Мгц ?
ОтветитьУдалитьможно, только смысла не вижу.
ОтветитьУдалитьУ меня есть проект, который работает на 1 Мгц, хотелось бы этот код туда добавить. Там сейчас есть работа по 1-wire, но только с одним устройством. Это очень сложно? UART мне не нужен
ОтветитьУдалитьпопробуй, должно работать
ОтветитьУдалитьЕсли ставлю в Makefile F_CPU = 1000000, компилирую, в мк ставлю деление на 8, данных не получаю, сейчас попробую сравнить дебагом..
ОтветитьУдалитьСрабатывает тут
ОтветитьУдалитьif( diff == OW_DATA_ERR ) break;
думаю, что из-за такой малой частоты не корректно работают микросекундные задержки. Сделай через UART
ОтветитьУдалитьВ проекте, в который я хочу добавить этот код, UART уже занят, там много чего занято. А почему задержки могут не корректно работать? ведь util/delay.h работает в зависимости от F_CPU . Спасибо.
ОтветитьУдалитькак раз он работает зависимо от F_CPU. При такой малой частоте мк просто не успевает сделать задержку.
ОтветитьУдалитьСкажите пожалуйста, как быть с atmega64 при работе через USART? У него в регистре UCSRnC нету бита URSEL. Спасибо.
ОтветитьУдалитьа где, собственно, вы увидели использование бита URSEL?
ОтветитьУдалитьvoid USART_init()
ОтветитьУдалить{
// Set baud rate
UBRRH = 0;
UBRRL = 51;
UCSRA = 0;
// Enable receiver and transmitter
UCSRB = (1<<TXEN);
// Set frame format
UCSRC = (1<<UCSZ1) | (1<<UCSZ0) | (1<<URSEL);
}
Если используете USART в качестве 1wire, то это функция вовсе не нужна
ОтветитьУдалитьСпасибо, убрал, запустил на Atmega64, через USART0, способ 2, 8 Мгц. Добавил проверку в цикл. Порты сконфигурированы так: DDRF = 0b00000010; PORTF = 0b00000000; Оставил два датчика температуры DS18B20. Тестирую в Протеусе. Через некоторое, всегда разное, время программа виснет на строке while(!CheckBit(UCSR0A, RXC)); в процедуре OW_ReadBit, а в протеусе, в этов время, иногда падает ошибка (AVR USART 0) RX Frame Error. В чем может быть проблема? Еще раз спасибо.
ОтветитьУдалитьтакое случается когда датчик не отвечает. Попробуйте на реальном устройстве
ОтветитьУдалитьИногда виснет на while(!CheckBit(UCSR0A, RXC)) OthersTasks(); в процедуре OW_WriteBit без ошибок в протеусе. С чем это может быть связано?
ОтветитьУдалитья сказать не могу, так как нужно протестировать на реальном устройстве. Попробуйте еще отключить сторожевой таймер
ОтветитьУдалитьПодскажите, надо ли делать какой-то сброс состояния датчика после измерения? Вычитываю данные ds18b20 в цикле и с большой долей вероятности через раз в data[0] находится 0xff. Пауза 1с в цикле не помогла.
ОтветитьУдалитьЕще интересует почему на схеме в протеусе используются два пина PB0 и PB1 в статье только PB0? Дело в том что на одном пине у меня не завелся датчик, а на двух и с OW_TWO_PINS завелся, но пока что с проблемами (см выше).
На схемах изображено несколько вариантов подключения, в протеусе - один с них (не помню какой).
ОтветитьУдалитьСоветую вам использовать код из этой статьи, если заведется, то переносите его в ваш проект.
А эта пауза 1с у вас между запуском измерения и считыванием данных?
Код точно такой же, за исключением за исключением датчика, подключен у другому порту, поэтому в openwire.h поставил
ОтветитьУдалить#define OW_DDR DDRC
#define OW_PORT PORTC
#define OW_PIN PINC
1с это пауза перед следующим измерением (в конце бесконечного цикла), а между запуском и считыванием как и в статье 800мс.
а каким из вышеперечисленных способов подключен 1wire?
ОтветитьУдалитьВот так
ОтветитьУдалитьhttp://imageshack.us/a/img27/6406/lsst.png
Если использовать классическую схему с одним проводом и резистор 4К7 на "+", то датчик не находится (#define OW_TWO_PINS комментировал).
В протеусе только в самом начале проскакивает 0xff.
Такс, а частота мк у вас какая?
ОтветитьУдалитьOW_BIT_OUT и OW_BIT_IN указаны?
F_CPU = 8000000
ОтветитьУдалитьВ SinaProg выставил Fuses: Int. 8MHz
#define OW_TWO_PINS
#define OW_DDR DDRC
#define OW_PORT PORTC
#define OW_PIN PINC
#define OW_BIT_OUT 1
#define OW_BIT_IN 0
а в самом протеусе в настройках мк установили частоту 8мгц?
ОтветитьУдалитьДа, (0100) Int. RC 8MHz
ОтветитьУдалитьНа всякий случай вот тут весь проект : http://yadi.sk/d/2d5P-zz28zMXV
Вроде все правильно. Попробуйте DS18x20_StartMeasureAddressed(owDevicesIDs[i]); заменить на DS18x20_StartMeasure();
ОтветитьУдалитьЯ спать, если что, завтра отвечу.
Спасибо, попробую.
ОтветитьУдалитьВ общем ситуация с DS18x20_StartMeasure() не изменилась.
ОтветитьУдалитьПопробую еще раз пересмотреть схему, возможно что-то упустил. Если не получится - придется использовать в качестве датчика температуры термистор :)
В любом случае спасибо большое за помощь!
Вроде победил, проблема была в использовании прерываний для динамической индикации (о чем собственно и написано в статье.)
ОтветитьУдалитьРешилось вешаньем датчика на USART. По крайней мере теперь в протеусе нет глюков. Осталось проверить на макете.
Еще раз спасибо!
Здравствуйте, искал адекватную библиотеку для работы по 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
Заранее спасибо!
а что не работает?
ОтветитьУдалитьНе находит устройства, хотя на шину повесил 3 штуки, на осцилографе на шине меандр, низкий уровень - 60 мкс, высокий - 580 мкс, по коду проследить не удалось причину этого явления, вроде все правильно
ОтветитьУдалитьРешил проблему. у меня 6.1 студия и для адекватной работы нужно было сделать глобальный дефайн опорной частоты процессора, иначе onewire либа думала что частота 1мгц.
ОтветитьУдалить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 была
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);
}
чет херня с отображением=)
ОтветитьУдалитьпочему?
ОтветитьУдалитьПодскажите пожалуйста, использую Вашу библиотеку через USART, работает все довольно стабильно и хорошо. Теперь возник вопрос, подключения питания к датчику не отдельным проводом +5В,а брать питание от линии данных, как это возможно реализовать?
ОтветитьУдалитьСпасибо.
Может возможно после передачи запроса на запуск измерения подтягивать 1 на ножку, чтобы по линии данных шли 5В, а по достижению 750мс читать?
ОтветитьУдалитьнасколько помню, так и нужно делать, посмотрите в даташите.
ОтветитьУдалитьда, но сама библиотека будет работать? Т.е используя USART я могу после подачи запроса на измерение перевести ногу (RX) в 1 (как в даташите написанно не познее чем 10мс), подождать 750мс, перевести обратно и читать данные?
ОтветитьУдалитьнужно просто передавать ноли в порт.
ОтветитьУдалитьможно пожалуйста поподробнее?
ОтветитьУдалитьПробовал проверить работу в протеус, но незнаю там как не подключи они читаются, даже если Vss и GND не подключать.
для того, чтобы питать устройство через DQ, нужно чтобы он был постоянно в высоком уровне, для этого нужно посылать OW_WriteByte(0xFF).
ОтветитьУдалитьКак часто посылать? А не легче просто поставить на время задержи по измерению темп порт в 1, чем посылать постоянно OW_WriteByte(0xFF).
ОтветитьУдалитьСпасибо
Смотрю в протеусе, у меня и так выходит что после получения и всех монипуляций, все время на DQ подается 5в, ну т.е порт в 1 стоит.
ОтветитьУдалитьможно, но для этого нужно отключить usart
ОтветитьУдалитьАга, а если будем слать команду постоянно OW_WriteByte(0xFF), как часто ее слать?
ОтветитьУдалитьПодскажите, для чего именно OW_WriteByte(0xFF).
Спасибо
постоянно слать, пока идет измерение. Для чего она, писал выше
ОтветитьУдалитьАга, понял. Будем слать. А не подскажите еще пожалуйста, как в протеусе можно проверить работу через паразитное питание? то при отключении GND и Vss всеравно все работает, они как я понял питаются через скрытое питание как на МК например.
ОтветитьУдалитьнаверно, никак, можете разве что в ноге DQ подключить осциллограф и посмотреть, есть ли высокий уровень во время измерения.
ОтветитьУдалитьСпасибо. Пока попробовать в живую нет возможности, нахожусь не дома, а вот протеус и его осциллограф показывает что после получения и отправки команд, нога находиться в 1, и поступает 4,999вольта
ОтветитьУдалитьтогда должно работать
ОтветитьУдалитьс отображением кода на сайте, не знаю почему)
ОтветитьУдалитьКакие файлы нужно добавить в свой проект (Atmel studio 6) для использования библиотеки. Какими функциями пользоваться?
ОтветитьУдалитьесть библиотека для работы с DS2413?
ОтветитьУдалитькакие вообще у вас есть библиотеки по даласу кроме DS18x20?
Скажите как обрабатывать данные с двух датчиков DS18B20 подключенных к одной шине?
ОтветитьУдалитьDS18x20_ReadData(ID, data);
ОтветитьУдалитьЗдравствуйте!Возникает странная проблема,при подключении микроконтроллера к компу с помощью преобразователя FT232 и открытии порта из значимых данных приходит только серийный номер,а вместо значения температуры символ '?'.Тестил только на железе,МК AtMega32.Такая же история наблюдалась с датчиком SHT75,но с другой программой.Помогите,пожалуйста,разобраться,в чем может быть проблема такого поведения.
ОтветитьУдалитьПопробовать другой преобразователь. Я вообще FT232 не применяю из-за его глюков, вместо него применяю CP2102
ОтветитьУдалитьОн у меня на PinBoard-e стоит,в будущем буду пускать через ENC28J60 сигнал от датчиков по сети,пока хотел отладить по uart-у,попроще думал будет.Спасибо за ответ,попробую сразу через сеть,т.к. cp2102 в наличии нет,а enc уже на плате и работает(тестил udp),может так что путное выйдет!
ОтветитьУдалитьДля начала хочу сказать спасибо за лаконичную и функциональную библиотеку, аналоги этими качествами не блещут =)
ОтветитьУдалитьУ меня небольшая проблема:
в протеусе UART-режим работает крайне нестабильно, при поиске устройств на шине с двумя датчиками часто либо зависает ( while(!CheckBit(UCSRA, T/RXC)) ), либо не находит ни одного (OW_DATA_ERR), либо находит один. Иногда срабатывает как надо. В софтварном режиме всё работает отлично. У вас случаем нет мыслей по поводу того, в чём может быть затык?
Заранее признаетелен.
поторопился я с выводами, в софтварном режиме тоже нестабильно :( не виснет, но находит от нуля о двух
ОтветитьУдалитья тебе больше скажу. в железе оно тоже не хило так сбоит )
ОтветитьУдалитьА версия протеуса какая? И как вы проверяли в UART режиме?
ОтветитьУдалитьАналогичная проблема, в Proteus 7.10 SP0, в режиме UART виснет на ( while(!CheckBit(UCSRA, RXC)) ), в обычном режиме нормально, иногда проскакивают ошибочные значения. На железе через UART пока не проверял.
ОтветитьУдалитьКак Вы проверяете в протеусе?
ОтветитьУдалитьhttp://www.evernote.com/l/AHO6M3KFQ_1KhYXaz40udSEhcxne_J9hXdQ/
ОтветитьУдалитьМеняю температуру на датчиках, слежу за изменениями до тех пор пока они не перестанут обновляться
Получается, глюк протеуста, так как у меня нормально работает.
ОтветитьУдалитьВ реальном устройстве я ставлю резистор не 4,7, а 2,2К. А если использую подключение через транзисторы, как в первом варианте, то вместо 4,7К ставлю 1,5К. У меня так работает не меньше сотни устройств.
Проверил на железе через UARТ, вроде всё отлично!
ОтветитьУдалитьВзял последний код из прикрепленного архива, у меня почему-то первое значение считывается 85, а потом правильное. С обоих датчиков.
ОтветитьУдалитьЕсли использовать _delay_ms вместо timerDelayMs все нормально, для чего был добавлен timerDelayMs?
ОтветитьУдалить85 - это значение темепратуры при инициализации. Тоесть, если подать питание и считать, не запустив измерение, будет получено 85
ОтветитьУдалитьДля задержки с помощью таймера, чтобы во время задержки можно было что то делать.
ОтветитьУдалитьМне не понятно почему оно считывается в таком случае
ОтветитьУдалить// работа с устройствами 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(); все нормально
Не судите строго, я новичок)
понял, потому, что timerDelayMs не работает у меня
ОтветитьУдалитьУ меня еще один вопрос, как выполнить быстрое прерывание цикла с запуском процедуры считывания температуры. Я разрешаю прерывание по кнопке, но оно срабатывает с третьего раза.
ОтветитьУдалитьЭтого лучше не делать, так как считывание занимает довольно продолжительное время.
ОтветитьУдалитьНо считывание температуры не главная функция моего устройства, должен ведь быть способ прервать цикл, пусть даже один раз и считается не верное значение.
ОтветитьУдалитьИли лучше делать 1-wire на отдельном МК и связать их по какому-либо протоколу?
ОтветитьУдалитьПодскажите пожалуйста как лучше сделать.
ОтветитьУдалитьТоже Proteus 7.10 SP0. Проверить не получается нормально, ибо инициализация проходит раз из пяти.
ОтветитьУдалитьПочему нельзя постоянно измерять температуру? Запускаешь измерение, затем 750 мсек тупишь в цикле, выполняя остальные задачи, потом читаешь измерения и так по кругу. Моментально получить текущее реальное значение температуры все равно не получится из-за температурной инертности датчика (если ты его греешь не газовой горелкой).
ОтветитьУдалитьРебят, не знаю, что у вас там сбоит, но у меня работает нормально. Правда, я всегда использую подключение через 2 транзистора и резистор на 1,5К.
ОтветитьУдалитьДоброго Здоровья!
ОтветитьУдалитьKibermaster!
Если дляВас не сильно обременительно, не могли-бы Вы пересобрать пример с использованием AVR Studio 4.19 с задействованным вариантом работы с 1Ware по USART?
А что если вы сами это сделаете?
ОтветитьУдалитьДело в том, что я пишу в среде Bascom, с "Си" не знаком абсолютно. Единственное, что стоит, так это AVR Studio 4.19, да и то, только, как программатор.
ОтветитьУдалитьПрошу прощения за безпокойство, уже не надо. Написал реализацию работы сам, согласно документации "#AN124 (Using a UART to Implement a 1-Wire Bus Master)".
Если Вас не сильно затруднит, алгоритм поиска ID устройств больше 1? Что-то этот момент никак не хочет поддаваться. Принимаю всё время "1", хотя в то-же время, поиск и чтение одного устройства, работает без проблем.
Вопрос может показаться глупым, но прошу простить, я начинающий.
ОтветитьУдалитьDS18x20_ReadData(owDevicesIDs[i], data); // считываем данные
float t = DS18x20_ConvertToThemperatureFl(data); // преобразовываем температуру в человекопонятный вид
printf(": %3.2f C", t);
Если не ошибся, переменная t и есть значение температуры. Это значение нужно вывести на LCD дисплей с помощью функции lcd_string(0x93, ); Как это можно осуществить?
Вместо последней строки:
ОтветитьУдалитьchar str[20];
sprintf(str, "t = %3.2f C", t);
lcd_string(0x93, str);
Спасибо! Правильно понял, что это перевод из float в char? Правда на дисплей все-равно не выводится, черные квадраты вместо значений (остальные слова и символы выводятся нормально).
ОтветитьУдалитьэто переводит число в строку, почему на дисплее не видно - смотрите функцию lcd_string
ОтветитьУдалитьПеревел Вашу библиотеку в CodeVisionAVR. Эмуляция USARTом. Схема 2. Запуск измерения DS18x20_StartMeasure, программная задержка 750 мс - тогда работает. Если запуск измерения делаю по прерыванию INT1 (запуск от внешнего таймера 1Гц) - перестает работать. Другие функции в прерывании тоже перестают обрабатываться. Идея - раз в секунду запускать измерение (не надо ждать 750 мс, пока конвертируется температура), а потом вывод на LCD. Подкажите, пожалуйста, в чем может быть дело.
ОтветитьУдалитьВ функции запуска измерения есть цикл while, для ожидания приема данных, поэтому использовать функцию в прерывании нельзя
ОтветитьУдалитьЗамечательная библиотека, отлично работает. Но подключил датчик DS18B20 с паразитным питанием и не работает. Пробовал ардуиновскую бибилиотеку, работает. Что нужно поменять в библиотеке?
ОтветитьУдалитьВо время измерения надо отправлять датчику положительный уровень на линии, чтобы ему было от чего питаться.
ОтветитьУдалитьДобрый день. Большое спасибо вам за библиотеку.
ОтветитьУдалитьУ меня такая проблема при подключении.
Подключаюсь методом 3 (одна ножка МК работает в качестве и входа, и выхода). Питание не паразитное. Найдено 1 устройство, как и ожидалось, но вот вместо температуры возвращается пустое значение:
---------- Found 1 devices ----------
28 61 4A AB 06 00 00 52 - Thermometer DS18B20: ? C
Можете ли подсказать, в чем может быть причина?
Спасибо.
Поправка. Возвращается не пустое значение. Сделал вывод первых 2х байтов, вот что получилось:
ОтветитьУдалить28 FF C5 1B A3 15 03 F7 - Thermometer DS18B20: data[0]: cd, data[1]: 1
28 FF C5 1B A3 15 03 F7 - Thermometer DS18B20: data[0]: cd, data[1]: 1
28 FF C5 1B A3 15 03 F7 - Thermometer DS18B20: data[0]: cc, data[1]: 1
28 FF C5 1B A3 15 03 F7 - Thermometer DS18B20: data[0]: cc, data[1]: 1
28 FF C5 1B A3 15 03 F7 - Thermometer DS18B20: data[0]: cc, data[1]: 1
Проблема решена. Причина в printf. См. http://www.avrfreaks.net/forum/problems-float-printf-solved
ОтветитьУдалитьВ функции search_ow_devices выполняем поиск устройств пока diff != OW_LAST_DEVICE && sensors_count < MAXDEVICES. При этом OW_LAST_DEVICE всегда = 0, соответственно и вся правая часть всегда = 0? Я правильно понял?
ОтветитьУдалитьПроблема - находит только одно устройство...
Как я понимаю, если 0, значит нового устройства не найдено.
ОтветитьУдалитьТак в чем смысл такого кода?
ОтветитьУдалитьПочитайте доку на DS18B20, многое станет ясно)))
ОтветитьУдалитьPS: есть на русском.
Читал, и не раз. И на разных языках..
ОтветитьУдалитьХочется понять этот код. Он несколько шире чем DS18B20.
А Вы за основу что брали? Какой AppNote?
ОтветитьУдалитьЭто было лет 5 назад, я уже не помню))).
ОтветитьУдалитьДанный код использую во всех твоих разработках, где есть OW, там поиск всегда происходил без сбоев со стороны программной части
Через USART у меня тоже все работает. Теперь пробую через DS2482-100. Возникли проблемы, стал подробно изучать код. Появились дополнительные вопросы. Сами как думаете, какая идея заложена в diff != OW_LAST_DEVICE && sensors_count < MAXDEVICES ?
ОтветитьУдалитьsensors_count < MAXDEVICES думаю, понятно))).
ОтветитьУдалитьdiff != OW_LAST_DEVICE нужен для обнаружения последнего найденного устройства.
Совершенно бы согласился. Но OW_LAST_DEVICE константа...
ОтветитьУдалитьЯ в курсе, и если diff равно 0 (этой константе), то новых устройств не обнаружено и цикл завершается
ОтветитьУдалитьТогда условие цикла сокращается до diff != 0.
ОтветитьУдалитьdiff - номер бита последнего несоответствия (от 64 до 1). Ниже 2, а тем более = 0, diff как бы и не может... И цикл получается бесконечным. Но на деле он завершатся. Как не пойму.
Подскажите почему при компиляции Вашего проекта все нормально работает, но переношу Ваш код к себе в проект ругается на delay.c не определен F_CPU, в этом файле пишу F_CPU 8000000UL компилируется но не работает пишет foud 0 device в консоле протеуса? Может где то нужно глобально объявить я новичек подскажите пожалуйста?
ОтветитьУдалитьF_CPU надо определить в настройках проекта
ОтветитьУдалитьЗдравствуйте! Не могу вывести доли градусов на семисегментный индикатор. Целые числа выводятся правильно. Пробовал так: raz4 = ((temp & 0x0F)*625/1000);
ОтветитьУдалитьПожалуйста, подскажите формулу?
ОтветитьУдалитьhttp://www.codenet.ru/progr/cpp/sprd/modf.php (не пробовал).
ОтветитьУдалитьУ меня atmega32 макетная плата+lcd1602. Нужно прикрутить датчик ds18b20. Пишу на С в Atmel Studio 4. Но как-то все не получается. Очень нужна помощь!!! У кого есть рабочий пример на С??? Что-то я на этом датчике затормозился. Пример куча в интернете, но что-то не как работать их заставить не могу.
ОтветитьУдалитьНужно помощь....
В статье как раз рабочий пример на си)))
ОтветитьУдалитьМожно по поподробней, это значение взамен owDevicesIDs[i] ?
ОтветитьУдалитьЗдесь хранится id датчиков.
ОтветитьУдалитьДоброго Здоровья!
ОтветитьУдалитьЕсли Вам не сильно затруднительно, не могли бы Вы пересобрать исходники с USART вариантом работы с Ds18b20.
Спасибо!
А здесь случайно не ошибка у Вас:
ОтветитьУдалить#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 DDRC
#define OW_PORT PORTC
#define OW_PIN PINC
#ifndef OW_TWO_PINS //если используется один пин, укажите его номер
#define OW_BIT 0
#else // если используются 2 пина, укажите их номера
#define OW_BIT_OUT 1
#define OW_BIT_IN 0
#endif
#endif
Если задан макрос #define OW_TWO_PINS то мы используем 2 пина, для интерфейса 1-wire, так же,
а у вас написано:
#ifndef OW_TWO_PINS //если используется один пин, укажите его номер
#define OW_BIT 0
#else // если используются 2 пина, укажите их номера
#define OW_BIT_OUT 1
#define OW_BIT_IN 0
#endif
то есть если есть макрос #ifndef OW_TWO_PINS то задаётся номер пина контроллера на котором будет 1-wire, а должны задавать если есть этот макрос не один, а два пина, а одни задавать если этого макроса нет.
Может должно быть вот так:
#ifndef OW_TWO_PINS //если используется один пин, укажите его номер
#define OW_BIT_OUT 1
#define OW_BIT_IN 0
#else // если используются 2 пина, укажите их номера
#define OW_BIT 0
#endif
Великодушно простите, там написано #ifndef всё верно!
ОтветитьУдалить