- posted
17 years ago
ds1821 help!!!
- posted
17 years ago
Hello, Alexander Panasovsky! You wrote in conference fido7.ru.embedded to All on Tue, 27 Dec 2005 21:58:54 +0300:
AP> Hеобходимо считать данные о температуре с датчика DS1821 AP> (именно с этого т.к. AP> он недорогой и у него нужная погрешность при измерении AP> температуры тела человека) и вывести их на ЖКИ (МЕЛТ10-Т7). AP> Проблемма состоит в вычислении температуры. Она вычисляется по AP> формуле:
AP>
AP> temperature=temp-0.5+(COUNT_PER_C-COUNT_REMAIN)/COUNT_PER_C;
AP> Число получается дробное. Точность нужна до десятых причем с AP> округлением а не с обрезанием. Я придумал вот как:
Зачем вообще считать с плавающей точкой? Умножь все на 256 и считай в целых, в конце смасштабируешь. Кстати точность у этих датчиков маловата для измерения температуры тела...
dima
- posted
17 years ago
Tue Dec 27 2005 20:58, Alexander Panasovsky wrote to All:
AP> Может ли кто нибуть придумать алгоритм получше ибо этот при компиляции AP> winavr становится жирным. Желательно бы использовать AT90S2313, но при AP> моем варианте вся программка вместе с приведенным ниже куском в него еле AP> влазит (1,9кб):((, а ее еще апгрейдить и апгрейдить... С моим вариантом AP> нужно брать мегу, но плата уже разведена для AT90S2313.
AP> Hеобходимо считать данные о температуре с датчика DS1821 (именно с этого AP> т.к. AP> он недорогой и у него нужная погрешность при измерении температуры тела AP> человека) и вывести их на ЖКИ (МЕЛТ10-Т7). Проблемма состоит в вычислении AP> температуры. Она вычисляется по формуле:
AP> temperature=temp-0.5+(COUNT_PER_C-COUNT_REMAIN)/COUNT_PER_C;
AP> Число получается дробное. Точность нужна до десятых причем с округлением AP> а не с обрезанием.
Плавающая точка нужна, в действительности, редко когда. А часть libc её реализующая имеет немерянный размер обычно. Потому и не влазит. Там ещё плавающий printf небось цепляется. Тоже тяжёлый.
Я у себя сделал так: температуру, считываемую из термометра, домножаю сразу на 256. В градусах. Так она хранится, так всё и считается. Диапазон -120 -- +120 вполне умещается в 16-разрядном int с точностью до 1/256 доли градуса. Выводится примерно так:
unsigned ta = abs(temp) + 1; /* 256*0.005 = 1.28 */ sprintf(buf, "%c%d.%2.2uC", /* знак */ (temp<0 ? '-' : '+'), /* целая часть */ ta>>8, /* дробная часть */ (100*(ta&0xff))>>8) );
Видно, что операции деления на 256 -- на самом деле сдвиги, из тяжёлых вычислений только умножение на 100. При вводе всё-таки использую плавающую точку -- разбирать вручную строки описываемые регулярными выражениями вида "^[0-9]*([.,][0-9]*)?([eE][+-]?[0-9]*)?$" нудно как-то...
Температура, считанная из термометра, преобразуется во внутренний для программы формат таким образом:
temp = \ ((((0xff00|scratch.temp_msb)<<8)|scratch.temp_lsb)<<7) - (256/4) \ + 256*(unsigned)(scratch.cpc-scratch.remain)/scratch.cpc;
где scratch описывается такой структурой:
struct scartch { UFAST temp_lsb, temp_msb, TH, TL, R0, R1, remain, cpc, crc; };
это scratch-буфер из даташита.
AP> temperature=temp-0.5+(COUNT_PER_C-COUNT_REMAIN)/COUNT_PER_C; AP> //выделяю сотни, десятки, единицы и сотые доли AP> out[6]=temperature/100; AP> out[7]=(temperature-out[6]*100)/10; AP> out[8]=temperature-out[6]*100-out[7]*10; AP> temperature=floor((temperature-out[6]*100-out[7]*10-out[8])*10+0.5); AP> out[9]=temperature; AP> //там дальше out[] ->это цифры, который выводятся на индикатор с AP> //этим проблем нет
Изобретаешь самодельный printf? В любом случае плавающую точку лучше выкинуть.
- posted
17 years ago
Wed Dec 28 2005 12:31, Kirill Frolov wrote to Alexander Panasovsky:
KF> temp = \ KF> ((((0xff00|scratch.temp_msb)<<8)|scratch.temp_lsb)<<7) - (256/4) KF> \ KF> + 256*(unsigned)(scratch.cpc-scratch.remain)/scratch.cpc;
И наверняка оно неправильно работает в области отрицательных температур.
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
Hello, Alex Gavrikov! You wrote in conference fido7.ru.embedded to Alexander Panasovsky on Thu, 29 Dec
2005 21:38:28 +0300:AG> Индикация с точностью полгpадуса - для теpмометpа туловища AG> более чем достаточно, думаю. Hет опеpаций деления и пpочих
Вообще-то обычный медицинский ртутный градусник имеет точность около 0.1 градуса и разрешение примерно вдвое выше (полделения отчетливо отсчитываются), что на этих полупроводниковых термометрах представляется проблематичным получить.
AG> жиpностей типа пpинтф.
А вот они действительно совершенно лишние, что при точности в полградуса, что половине десятой градуса.
dima
- posted
17 years ago
Wed Dec 28 2005 23:08, Alexander Panasovsky wrote to Kirill Frolov:
KF>> unsigned ta = abs(temp) + 1; /* 256*0.005 = 1.28 */ KF>> sprintf(buf, "%c%d.%2.2uC", KF>> /* знак */ (temp<0 ? '-' : '+'), KF>> /* целая часть */ ta>>8, KF>> /* дробная часть */ (100*(ta&0xff))>>8) KF>> );
AP> Большое спасибо - то что нужно. Я все таки не все понял: как происходит AP> округление, или в этом примере его нет?
round(a) == floor(a+0.5). 0.5 -- это, в действительнсти, 1.28, поэтому берётся просто единица.
AP> ЗЫ: А где можно почитать про функции printf для AVR? Буду благодарен AP> ссылке в интернете.
- posted
17 years ago
Wed Dec 28 2005 23:08, Alexander Panasovsky wrote to Kirill Frolov:
AP> ЗЫ: А где можно почитать про функции printf для AVR? Буду благодарен AP> ссылке в интернете.
Да, самодельный integer_to_string на языке C принципиально невозможно написать, если только у МК не (аппаратной) инструкции деления. У AVR начиная с каких-то есть. А иначе только в ассемблере.
- posted
17 years ago
Hello, Alexander Panasovsky! You wrote in conference fido7.ru.embedded to Dmitry Orlov on Wed, 28 Dec 2005 23:15:21
+0300:AP>>> temperature=temp-0.5+(COUNT_PER_C-COUNT_REMAIN)/COUNT_PER_C;
AP>>> Число получается дробное. Точность нужна до десятых причем с AP>>> округлением а не с обрезанием. Я придумал вот как:
DO>> Зачем вообще считать с плавающей точкой? Умножь все на 256 и DO>> считай в целых, в конце смасштабируешь. Кстати точность у DO>> этих датчиков маловата для измерения температуры тела...
AP> Тобишь сделать как я привел ниже?
AP> uint16_t temperature,COUNT_PER_C,COUNT_REMAIN; AP> uint8_t temp; AP> // AP> //считавание // AP> temperature=(uint16_t)(temp*256)-(0.5*256)+(uint16_t)((COUNT_ AP> PER_C-COUNT_REMAIN )*256)/COUNT_PER_C;
Да, в таком духе.
dima
- posted
17 years ago
Hello, Kirill Frolov! You wrote in conference fido7.ru.embedded to Alexander Panasovsky on Fri, 30 Dec
2005 09:18:38 +0000 (UTC): AP>> ЗЫ: А где можно почитать про функции printf для AVR? Буду AP>> благодарен ссылке в интернете.KF> Да, самодельный integer_to_string на языке C принципиально KF> невозможно написать, если только у МК не (аппаратной) KF> инструкции деления. У AVR начиная с каких-то есть. А иначе KF> только в ассемблере.
Не понял, какая связь С с наличием каких-то инструкций. Нет инструкции, есть функция в rtl.
dima
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
- posted
17 years ago
Hello, Alex Gavrikov! You wrote in conference fido7.ru.embedded to Dmitry Orlov on Sat, 31 Dec 2005 01:49:23
+0300:AG>>> Индикация с точностью полгpадуса - для теpмометpа туловища AG>>> более чем достаточно, думаю. Hет опеpаций деления и пpочих
DO>> Вообще-то обычный медицинский ртутный градусник имеет DO>> точность около DO>> 0.1 градуса и разрешение примерно вдвое выше (полделения DO>> отчетливо
AG> Точно. Сейчас нашел в аптечке этот девайс - 0,1 AG> гpадус/деление.
AG> Согласен, что полгpадуса туповато будет. 36,6 здоpовый AG> человек, 37,0 гpадусов уже больной.
AG> Инициатоp тpеда явно пpомахнулся с выбоpом DS1821. AG> DS1624 пpедпочтительнее.
Достичь такой _точности_ и стабильности полупроводниковым градусником врядли удастся. Замечал, что дешевые цифровые градусники показывают весьма неточно, хотя конечно безопасней ртутных.
dima