PDA

Просмотр полной версии : Программа для цифрового датчика температуры DALLAS 18B20



UR4QBP
29.06.2008, 12:59
Решил попробовать использовать датчик температуры фирмы DALLAS 18В20 с микроконтроллером ATmega8. Для начала задача проста: как считывать информацию о температуре из датчика по 1-Wire линии? Даташит у меня есть. Кто работал с подобными датчиками прошу помощи!

ua9xbi
29.06.2008, 17:07
Решил попробовать использовать датчик температуры фирмы DALLAS 18В20 с микроконтроллером ATmega8. Для начала задача проста: как считывать информацию о температуре из датчика по 1-Wire линии? Даташит у меня есть. Кто работал с подобными датчиками прошу помощи!

Добрый день.
Работа с этим датчиком хорошо описана во 2-й книге Н.И Заеца "Радиолюбительские клонструкции на PIC - микроконтроллерах" страница 109. Алгоритм разжеван подробно.
Есть упоминание в книге М.С. Голубцова "Микроконтроллеры AVR от простого к сложному и ссылка на автора программы Алексея Кургузова
kurguzov@unact.ru (программа многоточечный термометр есть на диске к этой книге)
Вот описание алгоритма из книги Заеца.

UR4QBP
29.06.2008, 17:47
Добрый день.
Работа с этим датчиком хорошо описана во 2-й книге Н.И Заеца "Радиолюбительские клонструкции на PIC - микроконтроллерах" страница 109. Алгоритм разжеван подробно.
Есть упоминание в книге М.С. Голубцова "Микроконтроллеры AVR от простого к сложному и ссылка на автора программы Алексея Кургузова
kurguzov@unact.ru (программа многоточечный термометр есть на диске к этой книге)
Вот описание алгоритма из книги Заеца.
Сначала создав тему, я совсем забыл о CodeVisionAVR!!! Ведь в визарде есть кодегенератор в котором именно указан этот датчик температуры. Программа сама сгенерирует код для датчика, сейчас на работе, проверить не могу. Тем не менее спасибо за файлы.

ut1wpr
29.06.2008, 19:43
Добрый день.
Работа с этим датчиком хорошо описана во 2-й книге Н.И Заеца "Радиолюбительские клонструкции на PIC - микроконтроллерах" страница 109. Алгоритм разжеван подробно.
Есть упоминание в книге М.С. Голубцова "Микроконтроллеры AVR от простого к сложному и ссылка на автора программы Алексея Кургузова
kurguzov@unact.ru (программа многоточечный термометр есть на диске к этой книге)
Вот описание алгоритма из книги Заеца.
Сначала создав тему, я совсем забыл о CodeVisionAVR!!! Ведь в визарде есть кодегенератор в котором именно указан этот датчик температуры. Программа сама сгенерирует код для датчика, сейчас на работе, проверить не могу. Тем не менее спасибо за файлы.
Вот и все! Конец обучению...
А что будет, если у КоудВижн не найдется нужного "генератора" под иную задачу? Перейдем к другому компайлеру или, все-таки, учить бум? :-)

UR4QBP
29.06.2008, 21:54
А что будет, если у КоудВижн не найдется нужного "генератора" под иную задачу? Перейдем к другому компайлеру или, все-таки, учить бум? :-)
Моя задача: считать данные из датчика... Бум пробовать... Не найдется нужного генератора будем изучать... а смысл делать то что уже сделано!?

UN9GW
29.06.2008, 23:26
//******************** ******************** ******************** *****************
//поиск подключённых датчиков и их количество
//******************** ******************** ******************** *****************
devices=w1_search(0x f0,rom_code);
sprintf(lcd_buffer,"%02u DS18B20\nDevice detected",devices);
lcd_puts(lcd_buffer) ;

float temperature; // переменная для температуры

// в цикле измеряем температуру
// и выводим на LCD
// с небольшой паузой

while(1)
{
temperature=ds18b20_ temperature(&rom_code[i][0]);
j='+';
if (temperature < 0)
{
j='-';
temperature=-temperature;
};
sprintf(lcd_buffer,"Temp: %c%.1f\xdfC",j,temperature);
lcd_gotoxy(0,0);
lcd_puts(lcd_buffer) ;
delay_ms(500);
{

UR4QBP
30.06.2008, 00:20
Написал прогу, подключение до 8 датчиков по линии 1-Wire. МК ATmega8, LCD BC1602, датчик температуры DS18B20. Не нравиться только дискретность отсчета 1 градус. Проект для CVAVR прилагаю.

UN9GW
30.06.2008, 00:36
У нас в блоках автоматики тоже используются DS18B20. Дискретность 0,1 градуса, хотя для большинства случаев такая точность не нужна.

ua9xbi
30.06.2008, 00:37
Не нравиться только дискретность отсчета 1 градус.
С 8-ми битной точностью так и будет. Задействуй все 12 бит с датчиков (если у тебя DS18B20) получишь точность 0,0625 град.

UR4QBP
30.06.2008, 00:42
С 8-ми битной точностью так и будет. Задействуй все 12 бит с датчиков (если у тебя DS18B20) получишь точность 0,0625 град.
Вот кусок моего кода:

/* configure each DS18B20 device for 12 bit temperature
measurement resolution */
for (i=0;i<devices;)
if (!ds18b20_init(&rom_code[i++][0],20,30,DS18B20_12BIT _RES))
{
sprintf(lcd_buffer,"Init error for\ndevice #%u",i);
lcd_clear();
lcd_puts(lcd_buffer) ;
while (1); /* stop here if init error */
};

Разве не 12 бит инициализация датчика? Или что то не правильно...

ua9xbi
30.06.2008, 01:02
НУ а где тогда 4-ре бита потерялись?

Посмотри вот здесь, такая же задача решена немного по другому:
http://www.radiokot.ru/lab/controller/18/

ЗАодно вопрос - может знает кто датчики температуры с верхним пределом 1100 - 1300 градусов. Нужно для муфельной печи. Или использовать термопару?

UN9GW
30.06.2008, 15:16
С 8-ми битной точностью так и будет. Задействуй все 12 бит с датчиков (если у тебя DS18B20) получишь точность 0,0625 град.
Вот кусок моего кода:

/* configure each DS18B20 device for 12 bit temperature
measurement resolution */
for (i=0;i<devices;)
if (!ds18b20_init(&rom_code[i++][0],20,30,DS18B20_12BIT _RES))
{
sprintf(lcd_buffer,"Init error for\ndevice #%u",i);
lcd_clear();
lcd_puts(lcd_buffer) ;
while (1); /* stop here if init error */
};

Разве не 12 бит инициализация датчика? Или что то не правильно...

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

vadim_d
30.06.2008, 21:48
ЗАодно вопрос - может знает кто датчики температуры с верхним пределом 1100 - 1300 градусов. Нужно для муфельной печи. Или использовать термопару?
Термопары J и K, не помню у какой выше температурный предел, им нужна компенсация температуры холодного спая, коррекция нелинейности немного замысловатая, даже после нее точность в 3-5 градусов - наверное Вам хватит :D

ua9xbi
30.06.2008, 23:20
Термопары J и K, не помню у какой выше температурный предел, им нужна компенсация температуры холодного спая, коррекция нелинейности немного замысловатая, даже после нее точность в 3-5 градусов - наверное Вам хватит :D
Погрешность даже 20-30 градусов устроит

AlexanderT
01.07.2008, 00:08
В таком случае надёжнее спиральные градусники из биметала.

vadim_d
01.07.2008, 00:20
Погрешность даже 20-30 градусов устроит
Николай, тогда коррекцию нелинейности можно точно не делать, а вот делать или нет компенсацию холодного спая - зависит от условий эксплуатации. В устройстве, куда писал софт, стоял AD595:
http://www.analog.com/static/imported-files/data_sheets/AD594_595.pdf

ua9xbi
01.07.2008, 08:42
Николай, тогда коррекцию нелинейности можно точно не делать, а вот делать или нет компенсацию холодного спая - зависит от условий эксплуатации. В устройстве, куда писал софт, стоял AD595:
http://www.analog.com/static/imported-files/data_sheets/AD594_595.pdf
Спасибо за подсказки, в общем разобрался.
Высокая точность там не нужна, потому как в самой муфельной печи разница температур настолько велика, что это ощущается даже по цвету разогретых стенок.

chaoba
15.07.2008, 22:38
С 8-ми битной точностью так и будет. Задействуй все 12 бит с датчиков (если у тебя DS18B20) получишь точность 0,0625 град.
Вот кусок моего кода:

/* configure each DS18B20 device for 12 bit temperature
measurement resolution */
for (i=0;i<devices;)
if (!ds18b20_init(&rom_code[i++][0],20,30,DS18B20_12BIT _RES))
{
sprintf(lcd_buffer,"Init error for\ndevice #%u",i);
lcd_clear();
lcd_puts(lcd_buffer) ;
while (1); /* stop here if init error */
};

Разве не 12 бит инициализация датчика? Или что то не правильно...
Как я понял, вы использовали функции и пример CodeVision. Я тоже сделал устройство на этой базе и тоже получил температуру в виде целых чисел и дискретностью 1Град. Умножил температуру на 10 и получил десятичные данные и дискретность 0,1Град.
Только вот насчет точности я не уверен. Держал датчик подмышкой получил 35Град. Примотал к термометру, получил 27,1, в то время, как на термометре - 28Град.

UN9GW
15.07.2008, 22:51
Умножил температуру на 10 и получил десятичные данные и дискретность 0,1Град.


Это не правильно. Датчик выводит температуру с достаточной точностью. Тип переменной, в которую выводится результат нужно объявлять как float, либо при выводе форматированного текста указывать .1f, что означает вывод значения с переменной типа float с одним знаком после запятой.

chaoba
15.07.2008, 22:52
Хотя может не все так плохо. Принес второй термометр, он показал 27Град:)

chaoba
15.07.2008, 22:54
Тип переменной у меня float. Пока не умножил на 10, на индикаторе у меня были 2 цифры ( только целые).

UN9GW
16.07.2008, 07:15
Тип переменной у меня float. Пока не умножил на 10, на индикаторе у меня были 2 цифры ( только целые).


sprintf(lcd_buffer,"Temp: %c%.1f\xdfC",j,temperature);

chaoba
16.07.2008, 07:57
Утро вечера мудренее. Проснулся и вспомнил, что у меня на это влияет моя функция динамической индикации.


void indikat()
{
unsigned int TEMP = REZULT;
unsigned char DIG_OUT = 0;
while (TEMP >= 100) // Подсчет сотен
{
TEMP -= 100;
DIG_OUT++;
}
A3 = DIG_OUT;
DIG_OUT = 0;
while (TEMP >= 10) // Подсчет десяиков
{
TEMP -= 10;
DIG_OUT++;
}
A2 = DIG_OUT;
DIG_OUT = 0;
while (TEMP >= 1) // Подсчет единиц
{
TEMP--;
DIG_OUT++;
}
A1 = DIG_OUT;
}
У меня 7-сегментные индикаторы
Т.ч сам урезал, сам подкорректировал умножением на 10. :D

RA4FOC
17.07.2008, 21:43
НУ а где тогда 4-ре бита потерялись?

Посмотри вот здесь, такая же задача решена немного по другому:
http://www.radiokot.ru/lab/controller/18/

ЗАодно вопрос - может знает кто датчики температуры с верхним пределом 1100 - 1300 градусов. Нужно для муфельной печи. Или использовать термопару?
Только термопара, датчиков со встроеным АЦП с таким верхним пределом нет.

clawham
05.05.2009, 11:52
Здравствуйте!
Интересует такой вопрос - есть ли кто рыл немного глубже чем просто использование кодгенератора?
у меня на линии 30 термометров точность конечно УХХхх....особенно при наличии корекционной решотки(ну ошибается он на -1 градус при температурах ниже нуля) главная проблема - скорость!!!
если опрашивать по очереди как это у всех сделано то я раз в минуту буду возвращяться к каждому градуснику а это недопустимо мне трубу надо контролировать летящую метр в 20 секунд экструдер! потому сделал немного залазку в голову библиотек и заставил запускать конверсию одновременно всей арраве а данные гоняются очень быстро! теперь другая проблема....ром коды большие, но у меня к МК припаян модуль на 1 мегабайт только вот проблема функция search хочет заполнять массив а мне надо как-то получать по одному ром коды и кидать его во внешнюю память....буффера МК не хватит никак сохранить 30 ромкодов :(
кто подскажет....неужели прийдёться с нуля ваять интерфейс 1 wire ?

Windk
05.05.2014, 10:06
День добрый! Вопрос возник с датчиком влажности DHT22 (ам2302), точнее с его 1-wire протоколом, схожим скорей всего с сабжем.
Вот его даташит с простым описанием:
http://meteobox.tk/files/AM2302.pdf

Здесь чуть подробней и на русском тайминги описаны.
http://diymicro.ru/eksperiment-24-datchik-vlazhnosti-dht11.html

Находил алгоритмы, да и самому по описанию не сложно реализовать, но увы, 2 дня полного ступора, из которого не пойму как сдвинуться.
Осцилл рисует пачку импульсов, могу по ним легко сам "декодировать" значения.
делаю на аттини85 в АтмелСтудио6, вот моя функция чтения, читает все что угодно, только не значения, контр сумма ессно не сходиться.
Атини85 настраивал и на 8Мгц такт и на 1Мгц, delay функцию отлаживал вначале дергая ножку с заданными таймингами, смотрел по осциллу. все точно как в аптеке, т.е. вроде как атини delay правильно отрабатывает.
Но что сделал не так и почему 85я не читает датчик, может кто помочь? (В коде опустил декодирование значений из байтов, т.к. сами считанные байты уже ошибочны)





#define F_CPU 1000000UL // 1 MHz
#include <util/delay.h>


#define SET_B(x) |= (1<<x)
#define CLR_B(x) &=~(1<<x)
#define INV_B(x) ^=(1<<x)


#define iPB PINB&(1<<port_pin) // select port pin


uint8_t bits[5];

int read_AM2302(uint8_t port_pin){
bits[0] = 0;bits[1] = 0;bits[2] = 0;bits[3] = 0;bits[4] = 0;
uint8_t cnt = 7;
uint8_t idx = 0;


PORTB = 0;
DDRB SET_B(port_pin); // line PB3 down for request
_delay_ms(25); //
DDRB CLR_B(port_pin); // PB3 as input, pull-up res sets 1 for the AM2302
_delay_us(40); // wait for response - low level from AM2302
if (iPB)
{
return 2; //break by timeout answer
}

while(!iPB);


while(iPB); // AM2302 ready for sending

for (int i=0; i<40; i++)
{
while(!iPB);
_delay_us(40);

if (iPB)
{
bits[idx] |= (1 << cnt);
while(iPB);
}
if (cnt == 0) // next byte?
{
cnt = 7; // restart at MSB
idx++; // next byte!
}
else cnt--;
}
....
}

Кулик
05.05.2014, 11:33
То ut1wpr #4.
Учить - жизнь заставит. Я давно плюнул на дрыгание ногами для реализации 1-wire. Все прекрасно делается на USART. И не надо прерывания запрещать на время передачи/приема бита.:-P

Кукин Николай Николаевич
05.05.2014, 13:39
[QUOTE=Windk;964608]День добрый! Вопрос возник с датчиком влажности DHT22 (ам2302), точнее с его 1-wire протоколом, схожим скорей всего с сабжем.
Вот его даташит с простым описанием:
http://meteobox.tk/files/AM2302.pdf
[QUOTE/]
1wire протокол на физ. уровне (тайминги и т.п.) одинаков для всех устройств, использующих 1 шину и внешнее питание.
Вот библиотека для винавра, почитайте ее, познавательно. Я ей пользуюсь, работает. Взял с arvresearch у ARV (Роман Викторович).
Список команд обмена на логическом уровне добавите свои.

Добавлено через 51 минут(ы):

Вот здесь коза:
if (iPB) { bits[idx] |= (1 << cnt); while(iPB); }

Так как первым идет младший бит, то он и должен записываться первым как младший, а не старший бит.

Кукин Николай Николаевич
05.05.2014, 16:26
Почитал даташит на датчик, там вообще все по-другому, не как в DS18B20. То есть я был неправ. Старший бит действительно идет первым, но все равно принцип декодирования неверный.

Ваш алгоритм не позволяет правильно читать данные из датчика по другой причине.

0 и 1 у датчика передается ЗА РАЗНЫЙ ВРЕМЕННОЙ ИНТЕРВАЛ.(Что-то типа ШИМ модуляции).
Поэтому нужно отслеживать временнОй промежуток каждого бита.
Это можно делать либо путем проверки логического уровня на входной ноге в цикле с инкрементирующимся счетчиком, либо запускать таймер на время анализа высокого уровня на входе. Оба алгоритма потребуют подбора либо значения цикловой задержки, либо значения счетчика таймера. Можно конечно в режиме отладки, чтобы самому не считать циклы тактового генератора, из авр студии определить длительность цикла, запустив прогу на исполнение. Будет подсчитано количество команд и время цикла.
Вы дали ссылку , чего ж не посмотрели фрагмент программы как это сделано на пике?
Сделайте “тыц” на черной строчке над фото дисплея по сцылке
http://diymicro.ru/eksperiment-24-datchik-vlazhnosti-dht11.html.

Windk
06.05.2014, 07:05
Почитал даташит на датчик, там вообще все по-другому, не как в DS18B20.

Да, я посмотрел 1wire.zip (http://www.cqham.ru/forum/attachment.php?attac hmentid=172125&d=1399283130) там не подоходит алгоритм.


0 и 1 у датчика передается ЗА РАЗНЫЙ ВРЕМЕННОЙ ИНТЕРВАЛ.(Что-то типа ШИМ модуляции).
Поэтому нужно отслеживать временнОй промежуток каждого бита.

Да, именно так.


Ваш алгоритм не позволяет правильно читать данные из датчика по другой причине.

так в том то и вопрос, по какой?! :) Я как раз тайминги все и раставил. Смотрел и алгоритм и не только этот и сделал по образу и подобию, если вкратце:
анчале передачи битов, когда дхт22 выставлет ноль, я ожидаю окончания 0:

for (int i=0; i<40; i++)
{
while(!iPB);

Как только появляется высокий уровень, я делаю задержку
_delay_us(40)
По даташиту, длительность высокого уровня до 30-35мкс - это НОЛЬ, а до 75мкс - ЕДИНИЦА
Т.е. после этой задержки я и смотрю, если все еще хай на пине - то ЕДИНИЦА и пишу ее в соот-ий бит байта bits, затем ожидаю окончания этого высокого уровня и идем вначало цикла. ожидая новый фронт.
Если на пине после задержки низкий уровень, значит НОЛЬ и просто идем в начало цикла.
Т.о. байт bits собирается из установленных битов. Тайминги реальные я контролирую осцилом, они совпадают с даташитом +-5мкс. Нпример, НОЛЬ у меня передается примерно 28-30мкс, а ЕДЕНИЦА 70 мкс (+-1мкс). На осцилле я четко вижу, как идут первые 7 бит - НОЛЬ. посл. младший - 70мкс, т.е. Единица. Но в первом считанном байте может быть все что угодно по несколько считанных единиц, откуда, не понимаю. Неправильно/Неточно у меня отрабатывает _delay_us(40) ?, проверил и это, просто дергаю ножку в 0 и 1 через указанные задержки. смотрю осциллом, все ОК. Может прерывания где какие затесались, я их не использую пока. но может где принудительно надо запрещать.. посмотрю еще. Пока вариантов больше нет.

Добавлено через 9 минут(ы):

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

#define iPB PINB&(1<<port_pin) // select port pin
...
int read_AM2302(uint8_t port_pin){
...
{
while(!iPB);

правильно ли? (port_pin у меня равен 3, т.е. PINB3)

Кукин Николай Николаевич
06.05.2014, 12:44
Windk
Несколько переделал Ваш код, так лично мне более удобно читать.

Тайминги взял по средней колонке таблицы даташита.

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

По вопросу задержки при чтении портов. Если читаем непосредственно в регистре PINB, то задержка равна 1 машинному такту (исполнение команды чтения), т.е. При 1 мГц – 1 мксек, если читаем состояние ног из PORTB, то внутри процика сначала пересылается из PINB в PORTB, а потом уже читается, тоесть минимум машинных 2 такта. При записи в порт тоже нужно время на исполнение команды посылки из регистра в порт + пересылка в PINB. Еще надо добавить аппаратные задержки в элементах порядка 1 маш такта.
Поэтому чтение непосредственно с ноги самый быстрый вариант чуть больше 1 машинного такта. На тайминги практически не влияет. А вот включенные прерывания влияют и могут сильно влиять. Поэтому если в процессе выполнения этой функции могут возникнуть аппаратные прерывания, то их обработку надо отключать на период выполнения КАЖДОЙ временной задержки. Так как при тактовой 1мГц даже если в обработчике прерывания будет исполняться порядка 10 команд, то время исполнения будет не менее 10+4=14 мксек, что уже чувствительно для этой функции.
Попробуйте, вдруг получится.

Windk
09.05.2014, 15:27
Кукин Николай Николаевич,
огромнейшее Вам спасибо, что нашли время разобраться и помочь. Ваш код пошел с пол-пинка как говориться. Стал сравнивать со своим, ведь по сути то тоже самое. Вот тут у меня ошибка крылась:

#define iPB PINB&(1<<port_pin) // select port pin

а после, в цикле ожидания, я проверяю

while(!iPB);

не правильно, надо:
while(!(iPB));

У вас скобки просто были сразу в дефин заданы. Все, читаю байты, к. сумма сходиться.
Заодно, за наводку про WDT спасибо, а то думал как сделать обработку зависания датчика...

Проект не ради развлечения делается, есть два таких датчика (в них Влажность и Температура), пока решил отработать протокол на атине, через пару-тройку недель придет UART->Bluetooth модуль, после чего, датчики уже подключу к Атмега 8, и к ней к ее УАРТу этот беспроводной модуль. Данные, по блутузу, будет слать на давно без дела валяющийся КПК, который еще отлично работает, к нему напишу ПО, - будет домашняя метеостанция с любыми желаемыми возможностями.