Всё по DS18(B/S)20.

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Аватара пользователя
levaclaus
Потрогал лапой паяльник
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Re: Всё по DS18(B/S)20.

Сообщение levaclaus »

Аlex писал(а):В 18B20 младшие 4 бита - дробное значение температуры. И без разницы, какое разрешение установлено. 4 бита - это 16. Отсюда, чтобы получить реальную температуру, значение нужно делить на 16.

вот картинка из датащита
ds18b20.JPG
(81.71 КБ) 356 скачиваний


Целое число не нужно делить. Делить нужно только дробную часть. Если эта дробная часть нужна...
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение WiseLord »

Я в своих проектах делаю чуть проще - не делю, а, скорее, умножаю.

Как уже сказано, просто забрав два байта из памяти, мы получаем уже готовое для работы значение температуры. Правда, умноженное на 16 (или на 2 в случае DS18S20).

Чтобы получить целое значение достаточно просто его разделить на 16 (2). Это просто сдвиг на 4 (1) позиции вправо. Тут всё понятно

Чтобы получить дробное значение, можно что-то мутить с 4 битами. А можно поступить проще - сначала умножить на 10, затем уже делить на 16 (2). Упростив, сводим это к умножению на 5 и сдвигу на 3 (для DS18B20) или без сдвига (для DS18S20). Результат - целое число, выражающее температуру в десятых долях градуса. Ну а при выводе на экран просто нужно точку не забыть поставить в нужном месте. И никакой возни с float/double и раздувающегося от этого кода.

Код: Выделить всё

int16_t ds18x20GetTemp(uint8_t num)
{
   int16_t ret = devs[num].temp * 5;

   if (devs[num].id[0] == 0x28) // DS18B20 has 8X better resolution
      ret /= 8;

   // Return value is in 0.1°C units
   return ret;
}
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение ARV »

levaclaus писал(а):Целое число не нужно делить.
возьмите калькулятор Windows, включите его в режим программиста и убедитесь, что описанное мною ранее полностью верно. делить нужно. то, что деление на 16 можно заменить сдвигом на 4, сути не меняет.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Zhuk72
Сверлит текстолит когтями
Сообщения: 1231
Зарегистрирован: Ср янв 29, 2014 08:41:31
Откуда: Баку
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение Zhuk72 »

Я вообще считаю максимальное разрешение В варианта датчика избыточным, учитывая его собственную погрешность и тот факт, что его вроде бы не используют в медицинских целях. Потому и ставлю 9-битное разрешение в его конфиг-регистре. Шага в 0.5 вполне достаточно на мой взгляд.
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
Аватара пользователя
levaclaus
Потрогал лапой паяльник
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Re: Всё по DS18(B/S)20.

Сообщение levaclaus »

ARV писал(а):
levaclaus писал(а):Целое число не нужно делить.
возьмите калькулятор Windows, включите его в режим программиста и убедитесь, что описанное мною ранее полностью верно. делить нужно. то, что деление на 16 можно заменить сдвигом на 4, сути не меняет.

Отличный пример с калькулятором. Ок, откройте калькулятор и введите в него биты с 4 по 11 из таблицы ниже (с 4 по 9 хранится целая часть, откиньте четыре младших бита, я спецом красным выделил) и переведите в 10-тичную систему. Опа, оказывается все сошлось с таблицей. И ненужен не флоат, не интеджер. Достаточно signed char (максимально до 127 градусов).
111 1101 = 125
000 1010 = 10

Теперь, если нужен десятичный знак после запятой, то тогда нужно делить только биты с 0 по 3. В результате получится что-то вроде temp с целым значением и temp10 с дробной частью. Но это же проще и меньше места займет чем гонять float + развивает понимание откуда ноги в ds18_20 растут.
Последний раз редактировалось levaclaus Сб янв 07, 2017 20:31:15, всего редактировалось 1 раз.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение WiseLord »

откройте калькулятор и введите в него биты с 4 по 9 из таблицы ниже
Это-то так (хотя, вернее, с 4 по 11). Но всё равно, чтобы выделить этот байт, без промежуточных вычислений не обойтись. Самое простое - сдвинуть на 4 16-битное число (reg[0] и reg[1] - это байты температуры).

Код: Выделить всё

int16_t temp = *(int16_t*)reg;
temp *= 10;
temp /= 16; // результат в десятых долях градуса

Хотя можно и без 16-битных чисел, чем-то типа такого обойтись, но вряд ли это лучше и компактнее по коду:

Код: Выделить всё

int8_t temp = __builtin_avr_swap((reg[0] & 0x0F) | (reg[1] & 0xF0)); // выделили целую часть из 4..11 битов
uint8_t temp10 = (reg[1] & 0x0F) * 10 / 16; // выделили дробную часть
if (temp < 0)
  temp10 = 10 - temp10; // пересчитали для отрицательных температур
Последний раз редактировалось WiseLord Сб янв 07, 2017 20:37:34, всего редактировалось 1 раз.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение ARV »

levaclaus писал(а):И ненужен не флоат, не интеджер. Достаточно signed char (максимально до 127 градусов)
ок, давайте ваш вариант кода в студию! сравним, будет ли он проще, чем мой *temp / 16 :)))

исходные данные: в массиве buf лежат полученные из датчика 9 байтов, CRC проверили - все верно. теперь пишите ваш код, который из двух char-ов buf[0] и buf[1] извлечет температуру в целых градусах, особенно, если температура отрицательная.

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

Мой уютный бложик... заходите!
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение Аlex »

levaclaus писал(а):вот картинка из датащита
ds18b20.JPG


Целое число не нужно делить. Делить нужно только дробную часть. Если эта дробная часть нужна...
Как не нужно ? Посмотрите внимательнее на картинку :facepalm:
Делить нужно и целую и дробную части.

Вообще, я всегда храню температуру в int'е с фиксированной точкой после первого разряда (умноженную на 10). Пихаем оба байта в int-переменную, умножаем на 10 и делим на 16. и никаких проблем.
Пример выше у WiseLord'а.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение WiseLord »

ARV: я чуть выше написал, как это предположительно выглядело бы в случае двух char-ов. Смотрится плохо, но вряд ли можно компактнее сделать по коду. С 16-бит числом проще всего, тем более что первые два байта массива фактически и есть это готовое 16-бит число.

В примере я приведение типа указателя использовал. Хотя у себя предпочитаю union и struct:

Код: Выделить всё

#define DS18X20_SCRATCH_LEN   9
#define DS18X20_ID_LEN        8

typedef union {
   int16_t temp;
   struct {
      uint8_t sp[DS18X20_SCRATCH_LEN];
      uint8_t id[DS18X20_ID_LEN];
   };
} ds18x20Dev;

Тут для датчика все нужные данные легко хранятся - и его ID, и скрэтчпад, и автоматическое приведение первых байтов в in16 температуру.
Аватара пользователя
levaclaus
Потрогал лапой паяльник
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Re: Всё по DS18(B/S)20.

Сообщение levaclaus »

в temp10 не может быть отрицательной температуры. В этом то и фишка, и прелесть работы с целой и дробной частью порознь. Дополнительный код распространяется только на целую часть, а дробная в прямом. Все согласно датащиту.
Вот код, рабочий. Главный офигенный + экономия места. Если знак после запятой убрать, места ещё больше окажется. Сейчас прога весит 822 байта. С оригинальной библиотекой более 1,5 кбайта.

Код: Выделить всё

signed char temp=0;
unsigned char temp_10=0;

signed char ds18b20_temperature(void)
    {
    unsigned char LSB,MSB;
    w1_init();   
    w1_write(0xCC);
    w1_write(0xBE);
    LSB=w1_read();   
    MSB=w1_read();
    temp_10=LSB;
    w1_init();   
    w1_write(0xCC);
    w1_write(0x44);
    delay_ms(800); //если 1f то убрать
    return ((MSB<<4)&0xf0) | ((LSB>>4)&0x0f);
    }
   
void ds_init(void)
    {
    w1_init();
    w1_write(0x4e);   
    w1_write(0x64); //100
    w1_write(0xD8);
    w1_write(0x7f);    //1f
    delay_ms(15);
    }

temp = ds18b20_temperature();

        d2=temp/10; // десятки
        d3=temp%10; // единицы
        d4=(temp_10&0x0f)*10/16; //знак после запятой

Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение ARV »

WiseLord писал(а):я чуть выше написал, как это предположительно выглядело бы
у меня нет сомнений в вашей квалификации, и свой вопрос я адресовал не вам :beer:

levaclaus писал(а):Дополнительный код распространяется только на целую часть, а дробная в прямом.
:facepalm: вы сами-то понимаете, какую ахинею вы несете? вы по своей табличке-то проверьте, которую приводили в начале странички...

levaclaus писал(а):Все согласно датащиту
очень далеко не все: как минимум, вы не считываете весь scratchpad и не проверяете CRC принятых данных. одно это полностью противоречит даташиту.

levaclaus писал(а):Вот код, рабочий
то есть вы продолжаете настаивать, что
levaclaus писал(а):((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
проще и оптимальнее, чем предложенный мной вариант
ARV писал(а):*temp / 16
??? :shock:
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение WiseLord »

levaclaus писал(а):Дополнительный код распространяется только на целую часть, а дробная в прямом. Все согласно датащиту.
Вы очень сильно ошибаетесь. Дополнительный код распространяется на всё число, и Ваш код в плане temp10 - неверен.

Даже не картинке, что Вы выкладывали:
+10.125 0000 0000 1010 0010
-10.125 1111 1111 0101 1110

Да, для 0,5 и -0.5 дробная часть одинаковая. Но только для такой дробной части.
Аватара пользователя
levaclaus
Потрогал лапой паяльник
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Re: Всё по DS18(B/S)20.

Сообщение levaclaus »

ARV писал(а):
то есть вы продолжаете настаивать, что
levaclaus писал(а):((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
проще и оптимальнее, чем предложенный мной вариант

для моего варианта нужно одно signed char или два
для вашего нужен float либо integer и много много памяти для работы с ним.

Да, я наставаю, что мой вариант лучше.

Бли, точно, с дробными ошибся, но делов то.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение ARV »

levaclaus писал(а):либо integer и много много памяти для работы с ним
:facepalm: всё, я умолкаю - посрамлен и растоптан :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение Аlex »

WiseLord писал(а):Да, для 0,5 и -0.5 дробная часть одинаковая. Но только для такой дробной части.
Они одинаковые всего-лишь из-за совпадения. +0.5(значение = +8) и -0.5(значение = -8) имеют одинаковые 4 младших бита.
levaclaus ошибается в том, что дробная часть не имеет отрицательного значения. Ещё как имеет. У оцифрованного значения "-1" (это -0.0625 градуса) дробная часть равна 1111.

Добавлено after 10 minutes 7 seconds:
А вот этот код :

Код: Выделить всё

((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
эквивалентен сдвигу обоих байтов вправо на 4 и отбрасыванию старшего байта. Что и есть обычное деление на 16, только с туевой хучей ненужных операций :facepalm:

levaclaus, вы вместо выдвиганий своих мыслей за правду, взяли бы лучше бумажку с карандашиком и уделили бы этому вопросу немного времени, разрисовывая битики и байтики. И всё бы встало на свои места. Вопрос то элементарный, на уровне 5-ого класса.
Аватара пользователя
levaclaus
Потрогал лапой паяльник
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Re: Всё по DS18(B/S)20.

Сообщение levaclaus »

Аlex писал(а):А вот этот код :

Код: Выделить всё

((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
эквивалентен сдвигу обоих байтов вправо на 4 и отбрасыванию старшего байта. Что и есть обычное деление на 16, только с туевой хучей ненужных операций :facepalm:

levaclaus, вы вместо выдвиганий своих мыслей за правду, взяли бы лучше бумажку с карандашиком и уделили бы этому вопросу немного времени, разрисовывая битики и байтики. И всё бы встало на свои места. Вопрос то элементарный, на уровне 5-ого класса.


у меня места в контроллере 1кбайт, было бы 2, я бы не взрывал Ваш мозг.
В каноничном варианте, коего здесь сторонники собрались, делить на 16 предлагают 16-битное число. С таким подходом программа занимает 1,5 кбайта для варианта с float и 1,3 кбайта для варианта с integer.
Предложенный мной вариант использует два char. И теперь прога мало того что занимает 830 байт, так ещё и работает, зараза.

Сжечь еретика-Коперника, он нам тут воздух портит... :kill:
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение WiseLord »

В каноничном варианте, коего здесь сторонники собрались, делить на 16 предлагают 16-битное число. С таким подходом программа занимает 1,5 кбайта для варианта с float и 1,3 кбайта для варианта с integer.

Во-первых, не делить, а сдвигать. Во вторых, даже если делить - компилятор всё равно это сделает сдвигом.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение ARV »

levaclaus писал(а):Сжечь еретика-Коперника, он нам тут воздух портит
это сильно... такая слава.... такая честь....
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Всё по DS18(B/S)20.

Сообщение Аlex »

levaclaus писал(а):и 1,3 кбайта для варианта с integer
Я просто даже представить не могу, что вы там такого понаписали, что сдвиг 16-битной переменной занимает на 500 байт больше, чем вот такое :
((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
:shock:
Вы бы слова свои кодом что-ли прикрепляли. В идеале - два куска, которые вы меняете местами, получая такую разницу в использованной памяти.
eduardo
Нашел транзистор. Понюхал.
Сообщения: 171
Зарегистрирован: Вс июн 17, 2012 16:32:42

Re: Всё по DS18(B/S)20.

Сообщение eduardo »

Ну вот,подшаманил я свой градусник. Проблема вывода -9999 исчезла,т.к скинул это значение в другие переменные.Только теперь в случае обрыва шины или выхода из строя датчиков будут выводиться последние значения..Теперь чтобы вывести сигнал аварии(---- на 7-сегментниках) мне уважаемый Аlex подсказал,что нужно проверять CRC. Теперь буду кумекать как прочитать этот CRC..буду рад любой помощи по этому вопросу.. Спасибо..
Вложения
termo8.rar
(320.33 КБ) 208 скачиваний
Ответить

Вернуться в «Периферия»