Страница 33 из 59
Re: Всё по DS18(B/S)20.
Добавлено: Ср май 07, 2014 12:24:10
ibiza11
Прошу прощения, что вмешиваюсь. Посмотрел Ваш проект термометра. У Вас в ds18b20.h все в куче, по правилам файл .h не должен содержать реализации функций и объявление переменных.
Если этот ds18b20.h будет добавлен в несколько модулей - при компиляции появится ошибка.
Re: Всё по DS18(B/S)20.
Добавлено: Сб май 17, 2014 14:36:17
WoodCat
Возникли сложности при обработке температуры с ds18b20 в модели протеуса, подскажите плз, может кто сталкивался.
Эффект проявляется при отрицательных температурах с долями градуса.
Допустим, на датчике стоит -1, тогда младший бит приходящий с датчика 1111 0000, все верно. Выставляю на датчике температуру -1.1, младший бит становится 1110 1111, дробная часть (правая половина байта) правильная, но при этом изменяется и значение целой части температуры в левой половине байта, после пересчета получится уже не 1 а 2.
Точно так же и с другими температурами, если стоит любое целое значение, -5, -10, какое угодно, все верно. Но добавляем любое значение в десятые и значение самой температуры увеличивается на 1. Это баг протеуса? Или фича, смысла которой я не понял?
Re: Всё по DS18(B/S)20.
Добавлено: Сб май 17, 2014 16:19:53
a_skr
Все правильно. Цена младшего разряда = 1/16 градуса. Т.е. с датчика получаете результат в градусах, умноженный на 16.
-1.1 * 16 = -17.6, дробная часть откидывается.
-17 в двоичном виде = 1111 1111 1110 1111 (16 бит)
Для проверки: -17 / 16 = -1.0625
Конечно, учитываем ошибки округления, т.к. -1.1 точно передать не получится, следующее значение будет -1,125 (1111 1111 1110 1110).
Никакие единицы градусов не теряются и не прибавляются.
Re: Всё по DS18(B/S)20.
Добавлено: Вс май 18, 2014 02:58:08
WoodCat
Вроде бы все логично.
Но в таком случае, это означает что все выложенные в сети алгоритмы пересчета значений 18b20 страдают этим косяком и все реализованные на их основе термометры при отрицательной температуре и не круглых ее значениях врут на градус вниз?
Алгоритмов я нашел много, на разных языках и для разных платформ, везде они одинаковые:
1. Читаем младший и старший байты, допустим пусть они будут байт1 и байт2
2. четыре младших бита байта1 - значение десятых долей, выносятся в отдельную переменную
3. четыре старших бита байта2 - признак отрицательной температуры, он тоже выносится отдельно
4. оставшиеся значения объединяются в один байт, младшие биты байта2 становятся старшими битами итоговой переменной, старшие биты байта1 младшими ее битами
5. в случае если температура отрицательна, итоговая переменная инвертируется и к ней прибавляется единица.
Или я чего-то не понимаю?
Re: Всё по DS18(B/S)20.
Добавлено: Вс май 18, 2014 10:17:22
uldemir
Не понимаете. Это - стандартное представление чисел со знаком. И если не выдумывать отсебятину, то всё работает совершенно верно. Для инвертирования знака числа надо выполнить инверсию всех бит числа и прибавить единицу к младшему разряду. Для проверки можете провести проверку для 0:
0000 0000 0000
инвертируем:
1111 1111 1111
прибавляем 1:
0000 0000 0000
Как видите ноль нулём и остался.
Еще пример - температура "минус 1/16 градуса":
1111 1111 1111
инвертируем:
0000 0000 0000
прибавляем 1:
0000 0000 0001 - получили +1/16
Re: Всё по DS18(B/S)20.
Добавлено: Вс май 18, 2014 11:19:28
Леонид Иванович
WoodCat писал(а):все выложенные в сети алгоритмы пересчета значений 18b20 страдают этим косяком
А какая задача? Получить представление температуры в десятых градуса?
Код: Выделить всё
uint8_t tl = OwpRead();
uint8_t th = OwpRead();
int16_t temp = 10 * (tl | (th << 8)) / 16;
Re: Всё по DS18(B/S)20.
Добавлено: Вс май 18, 2014 13:46:00
WoodCat
uldemir писал(а):Не понимаете. Это - стандартное представление чисел со знаком. И если не выдумывать отсебятину, то всё работает совершенно верно.
Вот с этим я как раз не спорю, меня смущает не то что 1+1=2 а реализация найденных мной алгоритмов

Re: Всё по DS18(B/S)20.
Добавлено: Сб июн 07, 2014 00:33:51
triest
Есть код на асме, в Proteus работает превосходно. А в железе не хочет. Подключаю как с паразитным питанием.
В протеусе работает нормально, а STK500 выдает зашкал.
Частота в протеусе 4Мгц, у стк500 3,68 (для прошивки пересчитал).
В чем проблема не понимаю
Re: Всё по DS18(B/S)20.
Добавлено: Сб июн 07, 2014 00:40:11
WoodCat
А если в протеусе поставить 3,68 - работает?
Я на своем небогатом опыте уже успел столкнуться с тем что 1-wire порой бывает критична к задержкам.
PS Жаль не 3,62, для круглости

Re: Всё по DS18(B/S)20.
Добавлено: Сб июн 07, 2014 01:17:33
triest
WoodCat писал(а):А если в протеусе поставить 3,68 - работает?
Я на своем небогатом опыте уже успел столкнуться с тем что 1-wire порой бывает критична к задержкам.
PS Жаль не 3,62, для круглости

Не выставить. Только 2 и 4мГц.

Re: Всё по DS18(B/S)20.
Добавлено: Сб июн 07, 2014 01:29:24
WoodCat
Жаль. Перед тем как писать, специально попробовал на Pic, позволяет и 3.62 и 3.68.
А STM не пробовал, мал еще, не дорос

Re: Всё по DS18(B/S)20.
Добавлено: Чт июн 12, 2014 00:27:39
triest
WoodCat писал(а):Жаль. Перед тем как писать, специально попробовал на Pic, позволяет и 3.62 и 3.68.
А STM не пробовал, мал еще, не дорос

Все заработало. Над было во фьюзах 2 мГц выставить.
Re: Всё по DS18(B/S)20.
Добавлено: Вс июн 22, 2014 09:05:40
Freerider
Изучаю датчик ds18b20 не получается команда копировать из озу в пзу 0x48.Вот програмка.
OWI_DetectPresence(BUS);//959 мкс
OWI_SendByte(OWI_ROM_SKIP, BUS);// 576 мкс команда 0xcc только для 1 датчика
// пропуск rom
OWI_SendByte(DS18B20_WRITE_SCRATCHPAD ,BUS);//3334 мкс
OWI_SendByte(27 ,BUS);//3334 мкс Отсылаем TH
OWI_SendByte(25 ,BUS);//3334 мкс TL
OWI_SendByte(127 ,BUS);//3334 мкс байт конфигурации
OWI_SendByte(DS18B20_COPY_SCRATCHPAD,BUS); // Вот и сама команда 0x48
Теперь считываем из ПЗУ в ОЗУ Командой 0xB8
OWI_DetectPresence(BUS);//959 мкс
OWI_SendByte(OWI_ROM_SKIP, BUS);
OWI_SendByte(DS18B20_RECALL_E, BUS);// Команда 0xB8
while (!OWI_ReadBit(BUS)); //ждем пока перезапишет
while(1){
/*подаем сигнал сброса
команду пропуска ROM
команду - чтение внутренней памяти
затем считываем внутреннюю память датчика в массив*/
OWI_DetectPresence(BUS);
OWI_SendByte(OWI_ROM_SKIP, BUS);
OWI_SendByte(DS18B20_READ_SCRATCHPAD, BUS);
for(char z=0;z<10;z++)
{
scratchpad[z] = OWI_ReceiveByte(BUS);
};
};
При этом в массив scratchpad записывается в байт TH=0 TL=0 и байт конф.=95 .Это то что у меня было в самом датчике изначально.
Все проганяю с в AVR Studio с помощью Jtag-Ice на atmege 16
Re: Всё по DS18(B/S)20.
Добавлено: Вс июн 22, 2014 09:35:50
uldemir
Изучайте внимательно диаграммы. Откуда контроллер знает, что "вот и сама команда", что это команда??????????
Freerider писал(а):OWI_DetectPresence(BUS);//959 мкс
OWI_SendByte(OWI_ROM_SKIP, BUS);// 576 мкс команда 0xcc только для 1 датчика
// пропуск rom
OWI_SendByte(DS18B20_WRITE_SCRATCHPAD ,BUS);//3334 мкс
OWI_SendByte(27 ,BUS);//3334 мкс Отсылаем TH
OWI_SendByte(25 ,BUS);//3334 мкс TL
OWI_SendByte(127 ,BUS);//3334 мкс байт конфигурации
--- тут надо вставить снова сброс шины и команды выбора устройства
OWI_DetectPresence(BUS);//959 мкс
OWI_SendByte(OWI_ROM_SKIP, BUS);// 576 мкс команда 0xcc только для 1 датчика
// пропуск rom
OWI_SendByte(DS18B20_COPY_SCRATCHPAD,BUS); // Вот и сама команда 0x48
Ну и не забудьте правильно дождаться выполнения этой команды (или читая статус при нормальном питании, или устанавливая strong pullup выдерживать определенное время указанное в даташите)
Re: Всё по DS18(B/S)20.
Добавлено: Вс июн 22, 2014 09:49:44
Freerider
Да заработало поставил в програмке
OWI_SendByte(DS18B20_WRITE_SCRATCHPAD ,BUS);//3334 мкс
OWI_SendByte(27 ,BUS);//3334 мкс
OWI_SendByte(25 ,BUS);//3334 мкс
OWI_SendByte(127 ,BUS);//3334 мкс
OWI_DetectPresence(BUS);//959 мкс
OWI_SendByte(OWI_ROM_SKIP, BUS);
OWI_SendByte(DS18B20_COPY_SCRATCHPAD, BUS);
Но самое интересное это я щас начал писать в IARe ,а до этого использовал cvavr так вот там в библиотеке есть функция инициализации этого датчика где отстутствует повторный сигнал сброса и пропуска Rom вот функция сия
unsigned char ds18b20_init(unsigned char *addr,signed char temp_low,signed char temp_high,
unsigned char resolution)
{
if (ds18b20_select(addr)==0) return 0;
resolution=(resolution<<5) | 0x1f;
w1_write(0x4e);
w1_write(temp_high);
w1_write(temp_low);
w1_write(resolution);
if (ds18b20_read_spd(addr)==0) return 0;
if ((__ds18b20_scratch_pad.temp_low!=temp_low) ||
(__ds18b20_scratch_pad.temp_high!=temp_high) ||
(__ds18b20_scratch_pad.conf_register!=resolution)) return 0;
if (ds18b20_select(addr)==0) return 0;
w1_write(0x48);
delay_ms(15);
return w1_init();
}
Re: Всё по DS18(B/S)20.
Добавлено: Вс июн 22, 2014 09:57:41
uldemir
Не знаю, что там у них за функции, я предпочитаю разбираться с низким уровнем. Поэтому 13-14 станицы даташита в руки и изучать диаграммы. Любое обращение к устройству 1-wire начинается со сброса шины, затем выбора устройства: read-rom, match-rom или skip-rom (с соответсвующими сопутствующими действиями), и даём команду с необходимыми аргументами. После чего датчик больше ничего не воспринимает, пока снова не произойдёт сброс шины и команда выбора датчика не укажет пальцем, что это к нему относится. Всё остальное - игнорируется.
Re: Всё по DS18(B/S)20.
Добавлено: Пт июл 11, 2014 10:58:46
kk042fjv
Добрый день!
Подскажите почему периодически на ЖК высвечивается температура на втором датчике -9999?
Код: Выделить всё
sprintf(lcd_buf, "%.1f\xdfC", ds18b20_temperature(&ds18b20_rom_codes[0][0]));
lcd_gotoxy(0,0);
lcd_puts(lcd_buf);
sprintf(lcd_buf, "%.1f\xdfC", ds18b20_temperature(&ds18b20_rom_codes[1][0]));
lcd_gotoxy(0,1);
lcd_puts(lcd_buf);
Re: Всё по DS18(B/S)20.
Добавлено: Сб июл 12, 2014 08:30:53
uk8amk
Для CVAVR это значит, что глючит сенсор или ошибка на шине.
Может быть следствием:
*плохого контакта
*длинного или неудачно выбранного кабеля
*неправильной последовательности команд обращения к датчику
*невыдерживания временных интервалов
и т.д.
Re: Всё по DS18(B/S)20.
Добавлено: Вт сен 16, 2014 13:55:45
Gudd-Head
Кто-нибудь работал с сабжем или другим 1-Wire с тактовой МК 128 кГц (собака)?
1 такт получается 7.8 мкс, а в даташитах рисуют что хорошо бы считать данные до 15 мкс...
Re: Всё по DS18(B/S)20.
Добавлено: Чт сен 25, 2014 16:38:30
sanyo.95
Здравствуйте. Извините если данный вопрос уже обсуждался. Пишу типа термостат: Atmega8, ds18b20. Я новичок и довольно долго мучился чтобы заставить программу хоть как-то работать. Проблема заключается в том что периодически на индикаторе появляется число 83, пока на индикаторе 83 на PORTC.5 - единица, потом опять показывает норм. температуру, PORTC.5=0 и опять 83..... Точность нужна до 1 градуса. Еще очень плохо производить настройку, а конкретно добавлять или отнимать temper_down, temper_up - после нажатия на кнопку изменения на индикатор доходят как то долго, хотя переключение между режимами происходит мгновенно.
Исходник:
Спойлер
Код: Выделить всё
#include <mega8.h>
#include <delay.h>
#include <1wire.h>
#include <ds18b20.h>
static flash unsigned char display[]= // масив для индикатора
{
(~0b11000000), // 0
(~0b11111001), // 1
(~0b10100100), // 2
(~0b10110000), // 3
(~0b10011001), // 4
(~0b10010010), // 5
(~0b10000010), // 6
(~0b11111000), // 7
(~0b10000000), // 8
(~0b10010000) // 9
};
int temper,temper_down,temper_up,temp[2],temp_down[2],temp_up[2];
char i=0,rezhim=0;
bit butt1,butt2,butt3; // биты для кнопок
//////////////////ФУНКЦИЯ ДЕЛЕНИЯ ТЕМПЕРАТУРЫ////////////
void del_temp()
{
temper=ds18b20_temperature(0);
temp[0]= temper/10; // реальная температура
temp[1]= temper%10;
temp_down[0]= temper_down/10; // нижний порог
temp_down[1]= temper_down%10;
temp_up[0]= temper_up/10; // верхний порог
temp_up[1]= temper_up%10;
delay_ms(1500);
}
////////////// ОПРОС КНОПОК ///////////////
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
TCNT1H=0x00;
TCNT1L=0x00;
if(PINB.4==0&&butt1==0)
{
rezhim++;
butt1=1;
if(rezhim>=3) rezhim=0;
}
if(PINB.4==1) butt1=0;
if(rezhim==0) PORTC.3=1; // РЕАЛЬНАЯ ТЕМПЕРАТУРА //
else PORTC.3=0;
if(rezhim==1) // НИЖНИЙ ПОРОГ //
{
PORTC.2=1;
if(PINB.2==0&&butt2==0)
{
temper_down++;
butt2=1;
}
if(PINB.2==1) butt2=0;
if(PINB.3==0&&butt3==0)
{
temper_down--;
butt3=1;
}
if(PINB.3==1) butt3=0;
}
else PORTC.2=0;
if(rezhim==2) // ВЕРХНИЙ ПОРОГ //
{
PORTC.4=1;
if(PINB.2==0&&butt2==0)
{
temper_up++;
butt2=1;
}
if(PINB.2==1) butt2=0;
if(PINB.3==0&&butt3==0)
{
temper_up--;
butt3=1;
}
if(PINB.3==1) butt3=0;
}
else PORTC.4=0;
}
/////////ДИНАМИЧЕСКАЯ ИНДИКАЦИЯ////////////
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTC &= ~(1<<i);
i++;
if(i>=2) i=0;
if(rezhim==0)
{
PORTD=display[temp[i]];
PORTC|=(1<<i);
}
if(rezhim==1)
{
PORTD=display[temp_down[i]];
PORTC|=(1<<i);
}
if(rezhim==2)
{
PORTD=display[temp_up[i]];
PORTC|=(1<<i);
}
}
void main(void)
{
PORTB=0x1C;
DDRB=0x00;
PORTC=0x00;
DDRC=0x1F;
PORTD=0x00;
DDRD=0x7F;
TCCR1A=0x00;
TCCR1B=0x05;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x4E;
OCR1BH=0x00;
OCR1BL=0x00;
// TC0
TCCR0=0x03;
TCNT0=0x00;
TIMSK=0x11;
w1_init();
#asm("sei")
while (1)
{
del_temp(); // вызов функции деления
if(temper<=temper_down) PORTC.5=1; // условия управления нагрузкой
if(temper>=temper_up) PORTC.5=0;
};
}
Буду очень благодарен если будут еще какие то замечания по коду, хочется писать максимально "правильно".