1-Wire. Работа с DS18B20. Использование двух датчиков. Часть 4
24/09/2011 - 12:07
Pavel Bobkov
Введение
Одно из преимуществ 1-Wire интерфейса заключается в том, что он позволяет организовать сеть из нескольких устройств. До сих пор мы не использовали эту возможность и рассматривали работу только с одним датчиком. Мы разобрались, как подключить Atmel`овскую библиотеку к проекту, как в DS18B20 запустить преобразование температуры, как считывать ее и выводить на дисплей. Настало время перейти к следующему этапу работы – коммуникация с несколькими датчиками на одной 1-Wire шине.
Получение адресов датчиков
Каждый датчик DS18B20 имеет 64-ех разрядный серийный номер, который используется для его адресации на шине. Для получения адресов 1-Wire устройств существует команда SEARCH ROM (0xf0). Процедура выглядит следующим образом.
Микроконтроллер выполняет инициализацию 1-Wire устройств и посылает команду SEARCH ROM, которая инициирует цикл чтения 64 разрядного кода. Затем он формирует на 1-Wire шине два тайм слота чтения, в течение которых датчики DS18B20 должны выдать первый бит своего адреса и его инвертированное значение.
Если испускаемый бит адреса у всех датчиков один и тот же, например, единица, тогда в первый тайм слот микроконтроллер примет единицу, а во второй ноль.
Если испускаемый бит адреса у одного или нескольких датчиков отличается, например, у первого датчика бит – единица, у второго – ноль, тогда в оба тайм слота микроконтроллер примет ноль. Почему? Потому что датчики подключены к шине по схеме монтажного И, а значит логический ноль «перетянет» логические единицы.
Если на шине активных устройств нет - микроконтроллер в оба тайм слота примет единицу.
В ситуации, когда микроконтроллер принимает два нуля, возникает неоднозначность – непонятно у каких датчиков DS18B20 преданный бит адреса ноль, а у каких единица. Чтобы устранить эту неоднозначность микроконтроллер должен ответить датчикам, с какими из них он будет продолжать работу. Для этого он выставляет на шине соответствующий бит — ноль или единицу. Датчики, у которых переданный бит соответствует выставленному, продолжат работу, остальные замолчат (станут не активными) до следующего сигнала сброса.
Далее процедура повторяется еще 63 раза: формирование первого тайм слота чтения, чтение состояние шины, формирование второго тайм слота чтения, чтение состояния шины, ответ подчиненным устройствам.
После завершения цикла чтения 64 разрядного кода, микроконтроллер будет знать адрес одного датчика DS18B20. Для получения следующего адреса, нужно снова запустить цикл чтения, но на этот раз в случае неоднозначности выставить другой бит.
Сколько датчиков подключено к шине, столько раз и нужно провести описанную процедуру.
Обращение к датчику
Когда адреса датчиков получены, микроконтроллер может индивидуально обращаться к любому из них. Для этого используется команда MATCH_ROM (0x55).
Последовательность работы будет выглядеть так:
- инициализация
- выдача команды MATCH ROM
- выдача 64 разрядного адреса датчика
- выдача функциональной команды
Описание функций библиотеки
Функции, выполняющие поиск адресов и адресацию 1-Wire устройств, расположены в файле OWIHighLevelFunctions.с. Некоторые из функций я модифицировал.
unsigned char OWI_SearchRom(unsigned char * bitPattern, unsigned char lastDeviation, unsigned char pin)
Назначение: Получение адреса одного 1-Wire устройства.
Посылает команду SEARCH ROM, получает адрес одного 1-Wire устройства и сохраняет его в массиве.
Принимает:
unsigned char * bitPattern – указатель на массив, в который будет сохраняться адрес
unsigned char lastDeviation – номер бита, на котором возникла неоднозначность
unsigned char pin – пин, к которому подключена шина
Возвращает: номер бита, на котором возникла неоднозначность
Пример:
#define BUS OWI_PIN_7
unsigned char id1[8];
unsigned char id2[8];
unsigned char lastDeviation = 0;
….
//получение первого адреса
lastDeviation = OWI_SearchRom(id1, lastDeviation, BUS);
//получение второго адреса
OWI_SearchRom(id1, lastDeviation, BUS);
unsigned char OWI_SearchDevices(OWI_device * devices, unsigned char numDevices, unsigned char pin, unsigned char *num)
Назначение: Получение адресов 1-Wire устройств.
Посылает команду SEARCH ROM, получает адреса нескольких 1-Wire устройств, сохраняет их и проверяет контрольную сумму каждого адреса.
Принимает:
OWI_device * devices – указатель на структуру, в который будет сохраняться адрес
Структура определена в файле OWIHighLevelFunctions.h
typedef struct
{
unsigned char id[8]; //!< The 64 bit identifier.
} OWI_device;
unsigned char numDevices – количество 1-Wire устройств, подключенных к шине
unsigned char pin – пин, к которому подключена шина
unsigned char *num – указатель на переменную, в которой сохраняется количество найденных 1-Wire устройств прошедших проверку
Возвращает: код ошибки.
SEARCH_SUCCESSFUL (0x00) - ошибок нет
SEARCH_CRC_ERROR (0x01) - ошибка CRC в одном из адресов
Пример:
#define BUS OWI_PIN_7
//количество устройств на 1-Wire
#define MAX_DEVICES 0x02
//массив структур для хранения адресов
OWI_device allDevices[MAX_DEVICES];
int main( void )
{
unsigned char num = 0;
num = 0;
OWI_SearchDevices(allDevices, MAX_DEVICES, BUS, &num);
…..
void OWI_MatchRom(unsigned char * romValue, unsigned char pin)
Назначение: адресация 1-Wire устройства.
Посылает команду MATCH ROM и выдает на шину адрес.
Принимает:
romValue – указатель на массив в котором храниться адрес 1-Wire устройства
unsigned char pin – пин, к которому подключена шина
Возвращает: -
Пример:
#define BUS OWI_PIN_7
#define DS18B20_CONVERT_T 0x44
unsigned char id[8];
….
/*подаем сигнал сброса
адресуем нужный датчик
запускаем команду преобразования*/
OWI_DetectPresence(BUS);
OWI_MatchRom(id, BUS);
OWI_SendByte(DS18B20_CONVERT_T , BUS);
Тестовый проект для AVR
Для демонстрации использования двух датчиков DS18B20 на одной шине, я написал учебный проект. Суть его в следующем.
Микроконтроллер выполняет процедуру поиска адресов датчиков. Если найдены два датчики и полученные адреса прошли проверку контрольной суммы, выставляется флаг и процедура поиска больше не повторяется.
Микроконтроллер запускает температурное преобразование первого датчика, считывает значение температуры и проверяет контрольную сумму. Если ошибок нет, температура отображается на дисплее, если обнаружена ошибка, на дисплее пишется, что датчик не найден и микроконтроллер выставляет флаг для повторного запуска процедуры поиска адресов. Далее те же самые действия повторяется со вторым датчиком.
Если какой-то из датчиков отключается от сети – микроконтроллер отображает это на дисплее.
Разжевывать код нет смысла – в нем достаточно комментариев. Единственное, что отмечу, перед функцией main нужно объявить массив структур, в котором будут храниться адреса датчиков.
Comments
Исключительно на AVR такое сделать не получиться. Если добавить внешний счетчик или использовать ПЛИС, то можно.
Я давно пользуюсь твоими библиотеками и примерами работы с несколькими 1-wire датчиками. Сейчас на LCD дисплее поочередно получаю по радиоканалу уличную температуру и температуру в пристройке.
А как организован радиоканал?
Есть тут одна вещь, которую я не могу объяснить. Проекты для IAR, WinAVR работают в Протеусе при частоте МК - 8 МГц, а на 16 МГц не работает. Хотя в железе заложено именно 16. Проект для CodeVision работает на 16 МГц, а на 8 МГц не работает.
Проекты в Протеусе я выкладываю для наглядности и всех его тонкостей не знаю. Я склонен больше доверять железу, а не симулятору. В железе все проект работают.
Пробовал так:
OWI_DetectPrese nce(BUS);
OWI_MatchRom(al lDevices[0].id, BUS);
OWI_SendByte(DS 18B20_WRITE_SCR ATCHPAD, BUS);
OWI_SendByte(0, BUS);
OWI_SendByte(0, BUS);
OWI_SendByte(0x1F, BUS); не работает
Но у меня возникла проблема: после компиляции Вашего проекта и прошивки новым HEX в Proteus не видит датчиков. Никаких изменений в программу не вносил. С тем HEX, который идёт в архиве - всё нормально.
P.S. если в папку common_files не записать compilers.h, то вылетает с фатальной ошибкой.
Code:
POWER_ON_1W();
Не?__delay_ms(1000);
POWER_OFF_1W();
Кстати UARTBitFunction s.c в проект можно и не включать, коль не используем.
Возник другой вопрос:как привести значение температуры к адекватному виду, чтобы можно было сравнить с константой? Сразу говорю, что я сейчас копаюсь в коде из папки примеров CodeVisionAVR, а не отсюда. Там при выводе используется такой код:
for (i=0;i
Вот код:
int main( void ){
unsigned int temperature[] = {0,0};
unsigned char searchFlag = SEARCH_SENSORS;
unsigned char crcFlag = 0;
unsigned char num = 0;
unsigned char i;
// Timer/Counter 0 initialization
// clkI/O/64 (From prescaler)
TCCR0B = (0
Попробывал вот так:
void DS18B20_PrintID (OWI_device * devices)
{
for (u08 j = 0; j < 8; j++){ Int2_LCD(devices[0].id[j])}
}
........
в коде программы вызываю так
........
DS18B20_PrintTemperature(temperature);
_delay_ms(500);
clear_LCD();
DS18B20_PrintID(allDevices);
И на экране получаю следующее значение как адрес датчика:
40 B6 C7 I1 03 00 00 39
Но этот датчик не входит в семейство (0х28). Кто подскажет в чем ошибка.
Рказывается это в 10чной системе счисления, а их еще надо в 16ричное представить.
С такими параметрами не получится использовать avr, необходимо что-то более скоростное.
http://tymbys.blogspot.ru/2013/04/avr-atmega16.html?m=1
Функция CVAVR w1_search возвращает кол-во устройств а также заполняет двумерный массив 9-байтовыми ROM-кодами каждого устройства(хотя почему 9 а не 8 не понимаю) из которых 8бит-CRC, 48бит-серийный номер и 8бит-код семейства (в данном случае DS18B20’s: 28h). Хотелось бы иметь функцию которая может преобразовать наш двоичный ROM код в строку или массив шестнадцатеричн ых символов(или кодов). Другими словами BINtoHEX. Таким образом можно будет идентифицироват ь конкретное устройство.
Набросал код который проверяет (идентифицирует ) датчик на принадлежность к семейству и выводит ROM код в шестнадцатеричн ом представлении на экран для наглядности. А также при отключении датчика выводит соответствующую надпись
Code:
while (1)
{
while(!w1_init()) //функция наличия/отсутсвия подключенного датчика
{
lcd_clear();
delay_ms(1000);
lcd_putsf(" no 1-Wire\n devises");
delay_ms(1000);
}
w1_search(0xf0,rom_codes);
if(rom_codes[0]==0x28) lcd_putsf("DS1820 "); //принадлежность к семейству h28
for(i=0;i<9;i++)
{
a=rom_codes>>4;
if(a>9) lcd_putchar(a+0x37);
else lcd_putchar(a+0x30); // 28 9A E7 69 02 00 00 A7 01
// 9 байт разделенных на тетрады
a=rom_codes&0x0f; // вывод в 16ричном представлении
if(a>9) lcd_putchar(a+0x37);
else lcd_putchar(a+0x30);
//lcd_putchar(' '); // вставка пробелов для наглядности
}
}
Короче на экране будет такой вывод 28 9A E7 69 02 00 00 A7 01 Видно что число 28 подтверждает что мы имеем дело с DS18B20
блин узкое окно для написания сообщений, невозможно отформатировать . Просьба к автору сайта чтото с этим сделать!!
Суть такова, заказал из китая датчик ds18b20 во влаге защиты, по описанию было напсиано, что это действительно ds18b20. на деле не работает (есть готовая программа, по данным примерам для данного датчика, который работает (датчики приобретены в мск), а с китайскими ни в какую. Пытаюсь сообразить код для чтения и вывода адреса датчика на экран, но ни в какую не получается. В программировани и не силён, изучаю сам, по обственным идеям. Может у кого есть такое? Учусь под atmel studio 6.2.
Проверь правильно ли указан define F_CPU. Тут указана частота, на которой должен работать камень. + проверяй фьюзы.
При работе с этим сенсором, очень важны временные задержки (_delay_ms) которые завязаны на F_CPU.
В железе еще не собирал , пока все в протеусе . Как я понял (_delay_ms) нужны только для работы индикатора , задержки же для работы датчика формирует сама библиотека , своей функцией , исходя из частоты камня . Да я меняю значение F_CPU с 16000000 на 8000000 , индикатор работает , но датчики не находит , заковыка где то в формуле функции задержки __delay_cycles( var)
#define CPU_FREQUENCY 16.000
файл OWIPolled.h
тут надо тоже изменить на 8.00 (но не менее 2х, если мне не изменяет память)
для работы протокола тоже используются временные задержки _delay_ms. Они описаны как
__delay_cycles().
#define CPU_FREQUENCY 8.000
датчики и перестают определятся1. Косяк библиотеки (такое встречается у библиотек от разработчиков)
2. Либо косяк протеуса.
Вообще протеус, довольно сложная штука. В модели, что выложена тут не очень много реальных элементов, что не позволяет производить симуляцию в реальном времени + не правильно указаны подтягивающие резисторы. Если поставить резюки из цифровых моделей, то пропадёт ошибка, о не возможно симуляции в реальном времени.
Если хочется моделировать, то как вариант Вам обходной путь.
Частота МК 8 МГц (если это важно, например ШИМ, АЦП и т.д), а частота датчиков 16.000, работает.
PS критично ли использование DS18B20? Можно использовать датчик DHT22. Он в обращении проще ( две команды (инициализация и чтение)) + он ещё измеряет влажность. Цена вопроса, 100р на алиэкспрес.
С одним датчиком ds18b20 делал термометр , все работало на ура . Самое главное знаний маловато в этой области , что то понимаю или кажется что понимаю , а что то совсем плохо . ))
make your point. You obviously know what youre talking about,
why waste your intelligence on just posting videos
to your blog when you could be giving us something enlightening to read?
Here is my weblog; premium natural garcinia cambogia reviews: http://vps-1157818-21410.manage.myhosting.com/node/2046308
#define OWI_DELAY_OFFSE T_CYCLES 13
в файлеOWIPolled.h с 13 на 7 , Протеус заработал , датчики стали определятся при выставленной частоте камня 8МГц Code:
#define CPU_FREQUENCY 8.000
Пробовал менять OWI_DELAY_OFFSE T_CYCLES работает только при значениях от 4 до 7 включительно , но это всё касается только работы Протеуса , как будет в железе пока неизвестно , соберу на макетке проверю ...
of area . Exploring in Yahoo I eventually stumbled upon this web site.
Studying this information So i am glad to convey that
I've an incredibly just right uncanny feeling I
discovered just what I needed. I most definitely will make certain to don?t put out
of your mind this web site and give it a look regularly.
Also visit my website :: Erecteen Testosterone: http://elsetat.com/?option=com_k2&view=itemlist&task=user&id=72571
https://drive.google.com/file/d/0B_j8VHf6GGn0M0NLLTBkbTJVNWs/view?usp=sharing
Your writing style is witty, keep up the good work!
Also visit my web page Garcinia Cambogia
Burn Reviews: http://partsmasteroverseas.com/?option=com_k2&view=itemlist&task=user&id=241277
Feel free to surf to my weblog ... life garcinia: http://citecmbscommunity.org/component/k2/itemlist/user/160077
But wanna remark on few general things, The web site style is ideal, the articles is really great : D.
Good job, cheers
Feel free to surf to my web blog; zippy loans: http://villanuevamontano.edu.mx/?option=com_k2&view=itemlist&task=user&id=491627
в предыдущей статье нашел такое решение:
#define RES_9BIT 0x1f
#define RES_10BIT 0x3f
#define RES_11BIT 0x5f
#define RES_12BIT 0x7f
#define DS18B20_WRITE_S CRATCHPAD 0x4e
...
//подаем команду
OWI_SendByte(DS18B20_WRITE_S CRATCHPAD, BUS);
//передаем Th, Tl и конфигурационны й регистр
OWI_SendByte(0, BUS);
OWI_SendByte(0, BUS);
OWI_SendByte(RES_9BIT, BUS);
но что то не соображу как его применить, как делал -- 1.ставил дефайны
2.#define DS18B20_WRITE_S CRATCHPAD 0x4e уже есть
3.до цикла ставлю ://подаем команду
OWI_SendByte(DS18B20_WRITE_S CRATCHPAD, BUS);
//передаем Th, Tl и конфигурационны й регистр
OWI_SendByte(0, BUS);
OWI_SendByte(0, BUS);
OWI_SendByte(RES_9BIT, BUS);
4. в цикле тоже пробовал без изменений
правильно ли я применял данный вариант?
Проблема в следующем соединяю два проекта часы и термометр. возникает неприятный глюк через каждые две-три секунды секунда проскакивает сразу на две вперед.
RSS feed for comments to this post