Полная версия этой страницы:
DS18B20 + Mega помогите !
belenkoff
Nov 7 2006, 10:44
Доброго времени суток!
Столокнулся с проблемой, при положительной температуре - все нормально, как только ниже нуля - выдает непонятное значение..
void ShowTemp(void)
{
char i;
float temp;
isfloat=1;
temperature=ds18b20_temperature(&rom_code[0][0]);
if (temperature!=-9999)
{
if (temperature>=0) {
temp = temperature;
if (temperature>=1000) {isfloat =0; temp = temperature/10;} //
i=0;
while (temp>=10)
{
temp=temp-10;
i++;
};
if (i>9) i=0; //****
buff1[1]=i;
buff3[1]=i;
i=0;
while (temp>=1)
{
temp=temp-1;
i++;
};
buff1[2]=i;
buff3[2]=i;
i=0;
while (temp>=0.1)
{
temp=temp-0.1;
i++;
};
buff1[3]=i;
buff3[3]=i;
i=0;
while (temp>=0.01)
{
temp=temp-0.01;
i++;
};
buff1[4]=i;
buff3[4]=i;
}
else
{
isfloat=0;
temp = -temperature/10; // /10;
i=0;
while (temp>=10)
{
temp=temp-10;
i++;
};
buff1[1]=i;
buff3[1]=i;
i=0;
while (temp>=1)
{
temp=temp-1;
i++;
};
buff1[2]=i;
buff3[2]=i;
i=0;
while (temp>=0.1)
{
temp=temp-0.1;
i++;
};
buff1[3]=i;
buff3[3]=i;
i=0;
while (temp>=0.01)
{
temp=temp-0.01;
i++;
};
buff1[4]=i;
buff3[4]=i;
}
}
}
Цитата(belenkoff @ Nov 7 2006, 12:44)

....
Обалдеть. Это уже словами описать нельзя.
Уже похоже в школах
совсем ничему не учат, о программировании вообще уже и речь не идет :-(
Код
#define DS18X20_FRACCONV 625
// meas - то, что с датчика считали (два байта приведенные к signed int)
// dcel - температура в десятых долях градуса c округлением, естественно
if( meas < 0 ) // Subzero
dcel = ((meas*DS18X20_FRACCONV)-500)/1000;
else
dcel = ((meas*DS18X20_FRACCONV)+500)/1000;
printf( "Temp:%+i.%i", dcel / 10, mod(dcel % 10) );
haker_fox
Nov 7 2006, 11:18
Скачайте
этот исходник (под IAR) и проанализируйте его внимательно.
Цитата(haker_fox @ Nov 7 2006, 13:18)

проанализируйте его внимательно.
Наверное имелось ввиду, что нужно читать между строк, поскльку в исходнике начисто отсутствует
преобразование полученного числа в температуру, в чем собственно и была 'проблема'.
haker_fox
Nov 7 2006, 11:41
Цитата(zltigo @ Nov 7 2006, 19:32)

Цитата(haker_fox @ Nov 7 2006, 13:18)

проанализируйте его внимательно.
Наверное имелось ввиду, что нужно читать между строк, поскльку в исходнике начисто отсутствует
преобразование полученного числа в температуру, в чем собственно и была 'проблема'.
Действительно

прошу прощения, но я не нарочно. Дело было давно и я почему-то был уверен, что в этом коде есть необходимая информация....
belenkoff
Nov 7 2006, 11:42
Цитата(zltigo @ Nov 7 2006, 14:32)

Цитата(haker_fox @ Nov 7 2006, 13:18)

проанализируйте его внимательно.
Наверное имелось ввиду, что нужно читать между строк, поскльку в исходнике начисто отсутствует
преобразование полученного числа в температуру, в чем собственно и была 'проблема'.
Я ползовался стандартной библиотечной функцией
float ds18b20_temperature(unsigned char *addr)
{
unsigned char resolution;
if (ds18b20_read_spd(addr)==0) return -9999;
resolution=(__ds18b20_scratch_pad.conf_register>>5) & 3;
if (ds18b20_select(addr)==0) return -9999;
w1_write(0x44);
delay_ms(conv_delay[resolution]);
if (ds18b20_read_spd(addr)==0) return -9999;
w1_init();
return (*((int *) &__ds18b20_scratch_pad.temp_lsb) & bit_mask[resolution])*0.0625;
}
Цитата(belenkoff @ Nov 7 2006, 13:42)

Я ползовался стандартной библиотечной функцией
1. Стандарнтых (определенных а стандартых С библиотеках) не существуе
2. Можете переадресовать часть комплиментов писателям того, что Вы называете "стандартной",
но ведь и голову на плечах тоже надо иметь, прежде, чем что-то кем-то написанное и 'нахаляву'
выложенное.
belenkoff
Nov 7 2006, 13:12
Дык и пытаюсь думать, но за первую неделю в Сях как то думается с трудом ... особенно PRINTF() и др.
В данной ситуации как поступить? Перейти на опрос другим способом или както выйти из положения с помощью хитромудрых математических манипуляций ??
Та, та, белый, белый, совсем карячий!
Поступить можно так, - пойти на сайт первоисточника - Atmel в раздел
Application Notes, найти там AVR318, - там и описание и код на С для IAR. Можно проявить настойчивость, и сходить на сайт Dallasa, вы не поверите,- там тоже полно информации о том, как работать с 1-Wire интерфейсом.
Цитата(belenkoff @ Nov 7 2006, 15:12)

Перейти на опрос другим способом
О господи! Причем тут 'опрос'! Вы на что 'жаловались' - на бред при минусе, так неудивительно,
ибо в преобразованиии очевидно (раз положительную температуру получаете нормальную) значения
написано такое
количество бреда, что и смотреть нечего.
Цитата
или както выйти из положения с помощью хитромудрых математических манипуляций ??
Ну
НЕТ совсем НЕТ никаких хитромудрых операций. Пример без хитромудростей, глупостей и плавучки привел, какие проблемы?
Цитата
первую неделю в Сях
Причем тут C, если для начала с элементарной арифметикой проблемы нешуточные.
Возьмите кусок бумаги и напишите как хотите сделать преобразование а уж потом пишите, хоть
на чем. Если нет мысли как сие сделать вообще, то чегоуж тут на языки пенять.
А "непонятное значение" это как?
_______________
Непонятно, как температура с DS18B20 может быть больше 1000 градусов?
Вроде ж не больше 125. Поэтому вряд ли это выполнится когда либо:
Код
if (temperature>=1000) {isfloat =0; temp = temperature/10;} //
И при положительных температурах останется всегда не деленным на 10.
А при отрицательной температуре у Вас всегда делится на 10:
Код
if (temperature>=0) {
temp = temperature;
if (temperature>=1000) {isfloat =0; temp = temperature/10;} //
...
}
else
{
isfloat=0;
temp = -temperature/10; // /10;
...
Может не надо делить на 10?
______________
Александр
2006 11 08
Ну что вы ругаете человека
Просто помогите
на самом деле здесь все просто
Надо объявить переменную
signed short ValueTermo; - двухбайтовое число со знаком
затем побайтно из массиса полученного с датчика
положить в него значение температуры
например так
ValueTermo=Buf_Mlan[1]*256+Buf_Mlan[0];
если нужно только целое значение
то просто делим на 16
если желаем иметь знаки после запятой
просто присваиваем ValueTermo переменной float
и тоже делим на 16
в итоге в С работаем с температурой со знаком
Удачи всем
belenkoff
Nov 12 2006, 20:04
Спасибо всем за помощь!
void ShowTemp(void)
{
char i;
float temp;
unsigned int tt;
unsigned long TV;
bit Sign;
tt=ds18b20_temperature(&rom_code[0][0])/0.0625;
if (tt!=-9999)
{
if((tt & 0xf800) == 0xf800){
TV=~tt; TV&=0x0000ffff; TV++; Sign=1;}
else {TV=tt; TV&=0x0000ffff; Sign=0;}
if (Sign)
{
isfloat=0;
temperature=(TV-COEF)*0.0625; //COEF - число прогрешности, если вдруг чего
} else
{
isfloat=1;
temperature=(TV+COEF)*0.0625;
}
if (temperature<0) temperature=-temperature;
temp = temperature;
//********************
i=0;
while (temp>=10)
{
temp=temp-10;
i++;
};
buff1[1]=i;
buff3[1]=i;
i=0;
while (temp>=1)
{
temp=temp-1;
i++;
};
buff1[2]=i;
buff3[2]=i;
i=0;
while (temp>=0.1)
{
temp=temp-0.1;
i++;
};
buff1[3]=i;
buff3[3]=i;
i=0;
while (temp>=0.01)
{
temp=temp-0.01;
i++;
};
buff1[4]=i;
buff3[4]=i;
}
}
Жаль, что некоторые "ВЕЛИКИЕ" очень уж любят "чайников"
Может подскажете, как вместо такой ужасной процедуры разложения значения температуры использовать PRINF
zltigo
Nov 12 2006, 20:56
Цитата(belenkoff @ Nov 12 2006, 22:04)

Может подскажете, как вместо такой ужасной процедуры разложения значения температуры использовать PRINF
А зачем этот 'шедевр' еще раз постить?
В первом-же посте написал. Код мой реальный. Весь этот ужас действительно заменяется несколькими строчками.
Причем ужас вызван отнюдь не использованием или не использованием printf() ( или sprintf() - это намек) - ....printf() это не более, чем последний необязательный штрих...
Цитата
Жаль, что некоторые "ВЕЛИКИЕ" очень уж любят "чайников"
Если это булыжник в мой огород, то я реально не люблю "ламеров", к "чайникам" отношусь спокойно и стараюсь помогать. Что впрочем не мешает
-называть вещи своими именами.
-не заниматься чрезмерным разжевыванием.
КСПшник
Nov 13 2006, 08:40
На самом деле здесь все просто. Температура читается из ОЗУ 18B20. Причем сама температура содержится в первых двух байтах (мл. байт по мл. адресу). Так вот, считывать эту температуру необходимо в двухбайтовую переменную (например, unsigned short). Далее, анализируете старший бит этой переменной, он всегда (вне зависимости от разрядности преобразования) говорит о знаке температуры (0 - положительная, 1 - отрицательная). Так вот, если отрицательная, то сама значащая часть (см. даташит), зависящая от заданной разрядности преобразования (по умолчанию - 12 разр.), дается в инверсном коде. Т.е. вам необходимо, при 1 в старшем разряде побитово инвертировать значение температуры, предварительно запомнив "-". Удачи.
Может приведенное ниже не столь красиво, ибо отсутствуют в выражении "всякие" там 1000, -9999 .. и другие десятичные цЫфры, зато давольно-таки оптимально, если глянуть в ассемблерный листинг:
Код
if (buf[1] > 0x0F)
temperature = 0xFF00;
else
temperature = 0;
temperature = temperature | (buf[0] >> 3) | (buf[1] << 5);
WriteOutTemp(temperature);
...
...
#pragma optimize=2
void WriteOutTemp(int temperature)
{
unsigned char nHalf = 0;
temperature = temperature >> 1;
if (SREG_C == 1)
nHalf = 5;
printf("T=%d.%d\r\n", temperature, nHalf);
}
С точностью один знак после запятой работает изумительно. А где printf, там и на индикатор вывести просто
Andy Great
Nov 13 2006, 11:29
Вопрос по той же конфигурации. Пытаюсь использовать паразитное питание, при частоте опроса до 5сек выдает завышенные показания (85 град вместо 26 комнатных). ЦРЦ в норме. Свыше 5сек в основном выдает часто нормально. Резистор по питанию 3к, паразитное питание на ноге включаю. Как только подключаю питание на 3ю ногу - все ОК. Разрядность пока не менял. ПОЧЕМУ?
Да, использую DS1822, DS18B20 пока не пробовал.
P.S.: Отвечаю сам себе. Разрядность ничего не меняет, надо ногу питания привязать к земле, как в даташите. Похоже, иначе неуверенное определение паразитного питания. При паразитном питании и 9бит преобразовании 100мс недостаточно для завершения оного, 200мс достаточно.
signed char tt;
//ds18b20_select(0);
//w1_search(0xf0,0);
ds18b20_init(0,-35,35,DS18B20_9BIT_RES);
tt=ds18b20_temperature(0);
=========================
использую библиотеки CodeVision/
tt=-15 всегда...
что не так ?
Цитата(simsim @ Mar 4 2007, 15:09)

signed char tt;
//ds18b20_select(0);
//w1_search(0xf0,0);
ds18b20_init(0,-35,35,DS18B20_9BIT_RES);
tt=ds18b20_temperature(0);
=========================
использую библиотеки CodeVision/
tt=-15 всегда...
что не так ?
9 бит не влезают в char
Решил наконец код привести - пример из Delphi (был под рукой), кому надо тот переведёт и на C и на ассемблер:
var
TH_TEMPERATURE:Byte;
TL_TEMPERATURE:Byte;
INT_TEMPERATURE:WORD;
SIGN:WORD;
TEMPERATURE:REAL;
собственно сама процедура:
TL_TEMPERATURE:=FT_In_Buffer[8];
TH_TEMPERATURE:=FT_In_Buffer[9];
INT_TEMPERATURE:=TH_TEMPERATURE*256+TL_TEMPERATURE;
SIGN:=INT_TEMPERATURE and $8000;
if SIGN=0 then
begin
TEMPERATURE:=INT_TEMPERATURE*0.0625;
end
else
begin
TEMPERATURE:=-(not(INT_TEMPERATURE)+1)*0.0625;
end;
Label1.Caption:=FloatToStrF(TEMPERATURE,ffFixed,6,4)
Принцип:
Определяем старший бит в двух байтах накладывая маску (SIGN:=INT_TEMPERATURE and $8000). Если SIGN равен нулю значит температура положительна - ничего не делаем умножаем и готово.
Иначе SIGN=$8000 (или 0x8000) температура отрицательна - берём инверсию, прибавляем единицу (что-то здесь связано с дополнительным кодом что ли), умножаем, добавляем минус и готово.
У меня работает - удачи!
P.S - В Windows есть очень хорошая программа - Калькулятор (calc.exe) - В инженерном виде позволяет проверить многие вещи.
Цитата(VXDRV @ Mar 5 2007, 11:40)

Решил наконец код привести
Прочитайте
наконец пост номер 3.
Цитата(zltigo @ Mar 5 2007, 13:20)

Цитата(VXDRV @ Mar 5 2007, 11:40)

Решил наконец код привести
Прочитайте
наконец пост номер 3.
У меня просто входная величина не приведена к signed int.
Тем не менее вариант имеет право на существование.
Цитата(VXDRV @ Mar 5 2007, 09:40)

Решил наконец код привести - пример из Delphi (был под рукой), кому надо тот переведёт и на C и на ассемблер:
var
TH_TEMPERATURE:Byte;
TL_TEMPERATURE:Byte;
INT_TEMPERATURE:WORD;
SIGN:WORD;
TEMPERATURE:REAL;
собственно сама процедура:
TL_TEMPERATURE:=FT_In_Buffer[8];
TH_TEMPERATURE:=FT_In_Buffer[9];
INT_TEMPERATURE:=TH_TEMPERATURE*256+TL_TEMPERATURE;
SIGN:=INT_TEMPERATURE and $8000;
if SIGN=0 then
begin
TEMPERATURE:=INT_TEMPERATURE*0.0625;
end
else
begin
TEMPERATURE:=-(not(INT_TEMPERATURE)+1)*0.0625;
end;
Label1.Caption:=FloatToStrF(TEMPERATURE,ffFixed,6,4)
Принцип:
Определяем старший бит в двух байтах накладывая маску (SIGN:=INT_TEMPERATURE and $8000). Если SIGN равен нулю значит температура положительна - ничего не делаем умножаем и готово.
Иначе SIGN=$8000 (или 0x8000) температура отрицательна - берём инверсию, прибавляем единицу (что-то здесь связано с дополнительным кодом что ли), умножаем, добавляем минус и готово.
У меня работает - удачи!
P.S - В Windows есть очень хорошая программа - Калькулятор (calc.exe) - В инженерном виде позволяет проверить многие вещи.
Не пойму, зачем такие сложности? Почему нельзя вот так?
Код
TL_TEMPERATURE:=FT_In_Buffer[8];
TH_TEMPERATURE:=FT_In_Buffer[9];
INT_TEMPERATURE:=TH_TEMPERATURE*256+TL_TEMPERATURE;
TEMPERATURE:=INT_TEMPERATURE*0.0625;
Ну будет переменная TEMPERATURE отрицательной, ну и что? Принтф или FloatToStrF точно так же её напечатает, как и положительную, только со знаком минус.
Naksojin
Mar 6 2007, 18:52
Я когда-то вот так делал....
unsigned char Check_Minus (unsigned char in_data)
{
if ((in_data & 0x80) != 0)
{
display.minus = ON;
return (~in_data + 1);
}
else
{
display.minus = OFF;
return in_data;
}
}
Вариантов много.
Для преобразования в формат с фиксированной запятой (1 знак после запятой) я исп. такую ф-ю :
Код
int16_t ds1w_12bit_to_celsius(uint16_t value)
{uint8_t uc1;
uc1 = (value>>8) & 0x80; //запомнить знак числа
if (uc1) value = 0-value; //если нужно, проинвертировать
value = (value>>1) + (value>>3); //скорректировать
if (uc1) value = 0-value; //восстановить знак
return(value);
}
Рома_С
Mar 10 2007, 23:25
Помогите мне пожалуйста, тоже проблемы с отрицательной температурой правда только пробовал я это в Proteuse 6,9 SP3, пока нет возможности попробовать на реальных термодатчиках в протеусе он мне как бы измеряет отрицательную температуру но показывает вместо -1 число 4095, вместо -2 число 4094, вместо -3 число 4093 и так далие. В чем же дело, все это я сделал из примера в CodeVision для ds18b20, или это Протеус глючит, или это я так глючу

. Как мне сделать, чтобы минусовая температура отображалась как надо в десятичном виде, и как можно отобразить на дисплее hd44780 температуру в двоичном виде ибо значение температуры в ds18b20 занимает два байта. Как это все сделать в CodeVision.
Заранее спасибо.
Цитата(Рома_С @ Mar 10 2007, 20:25)

Помогите мне пожалуйста, тоже проблемы с отрицательной температурой правда только пробовал я это в Proteuse 6,9 SP3, пока нет возможности попробовать на реальных термодатчиках в протеусе он мне как бы измеряет отрицательную температуру но показывает вместо -1 число 4095, вместо -2 число 4094, вместо -3 число 4093 и так далие. В чем же дело, все это я сделал из примера в CodeVision для ds18b20, или это Протеус глючит, или это я так глючу

. Как мне сделать, чтобы минусовая температура отображалась как надо в десятичном виде, и как можно отобразить на дисплее hd44780 температуру в двоичном виде ибо значение температуры в ds18b20 занимает два байта. Как это все сделать в CodeVision.
Так и должно быть, никто никого не глючит. Минус единица (-1) представлена в дополнительном коде. Чтобы получить положительное число, надо проинвертировать каждый бит и к результату добавить 1.
Для -1 будет так: 4095=0xFFF, инв(0хFFF)+1=1. Для -2 будет так: 4094=0xFFE, инв(0хFFE)+1=2. И т.д.
Отсюда следует простой алгоритм: проверяете 11 бит числа, если он равен 1, значит число отрицательное. Получаете дополнение, это одна команда NEG Rx.
Преобразование в символьную форму можно осуществить разными путями. Один из них следующий. Поскольку весь диапазон 16-битных чисел со знаком лежит от -32768 до +32767, то надо определить 5 цифр. Старшая цифра, десятков тысяч может быть 0, 1, 2 или 3. Вычитаете из числа значение 10000 столько раз, чтобы число стало меньше 10000. Количество вычитаний вам даст цифру десятков тысяч. Затем из остатка вычитаете 1000 подобным образом, затем 100 и 10. Последний остаток даст вам количество единиц в числе.
Рома_С
Mar 11 2007, 18:17
А если нужно чтобы температура отображалась сточностю -0,1 или даже -0,05 то как из float сделать стринг?
Дискретность 0,0625 если вы посмотрите DATA_SHEET. Предлагаю вариант вообще без float - (господин GM - может к этому шёл) полученные два байта приводите к INT с корекцией знака (знак запоминаете во флаге каком нибудь) и умножаете на 625 результат - long int
Например 0x01 - типа старший байт 0x40 младший - в общем 0x140 * 625=200000. Ставим запятую после двадцать на самом индикаторе затем рисуем "дробную" часть получаем 20,0000 С. Алгоритм вычисления десятков сотен и т.д. приведён постом выше.
zltigo
Mar 12 2007, 02:33
Цитата(Рома_С @ Mar 11 2007, 17:17)

А если нужно чтобы температура отображалась сточностю -0,1 или даже -0,05 то как из float сделать стринг?
Рома! ну почитайте хот ЭТУ ветку с начала!
Цитата(Рома_С @ Mar 11 2007, 15:17)

А если нужно чтобы температура отображалась сточностью -0,1 или даже -0,05 то как из float сделать стринг?
Не путайте представление с фиксированной точкой (0.05) и с плавающей (5*10^-2).
Цитата(VXDRV @ Mar 11 2007, 21:39)

Дискретность 0,0625 если вы посмотрите DATA_SHEET. Предлагаю вариант вообще без float - (господин GM - может к этому шёл) полученные два байта приводите к INT с корекцией знака (знак запоминаете во флаге каком нибудь) и умножаете на 625 результат - long int
Может и шёл(:-), но больше сосредоточился на преобразовании. Всё правильно вы говорите, могу только развить вашу тему для лучшего понимания. В результате чтения датчика получается двухбайтное число вида YYYYY c ценой одного разряда 0.0625 градуса. Искомые градусы Цельсия получаются умножением YYYYY*0.0625 = YYYYY*625/10000=ZZZZZZZZ/10000. Естественно, деление на 10000 производить не обязательно, достаточно передвинуть запятую на четыре разряда влево. Соответственно, надо преобразовать в символьный вид не два байта, а четыре. Идеологию преобразования, на которой я заострял внимание, автор уже знает.
OlegIvanov
Mar 12 2007, 08:37
[/quote]
Причем тут C, если для начала с элементарной арифметикой проблемы нешуточные.
Возьмите кусок бумаги и напишите как хотите сделать преобразование а уж потом пишите, хоть
на чем. Если нет мысли как сие сделать вообще, то чегоуж тут на языки пенять.
[/quote]
Рома_С
Mar 13 2007, 19:48
Свершилось чудо. E меня все получилось как я хотел. Я сделал как написал
КСПшник в посте №16. Я просто не знал в что можно поместить 2 байта. С преобразованиями я разобрался. Спасибо всем за помощь Вы мне здорово помогли можно даже сказать заставили
З.Ы. Все "Великие" были когдато "чайниками". Respect.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.