вот картинка из датащита Целое число не нужно делить. Делить нужно только дробную часть. Если эта дробная часть нужна...Аlex писал(а):В 18B20 младшие 4 бита - дробное значение температуры. И без разницы, какое разрешение установлено. 4 бита - это 16. Отсюда, чтобы получить реальную температуру, значение нужно делить на 16.
Всё по DS18(B/S)20.
- levaclaus
- Потрогал лапой паяльник
- Сообщения: 302
- Зарегистрирован: Пн янв 07, 2008 16:56:28
- Откуда: Минск
Re: Всё по DS18(B/S)20.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Всё по DS18(B/S)20.
Я в своих проектах делаю чуть проще - не делю, а, скорее, умножаю.
Как уже сказано, просто забрав два байта из памяти, мы получаем уже готовое для работы значение температуры. Правда, умноженное на 16 (или на 2 в случае DS18S20).
Чтобы получить целое значение достаточно просто его разделить на 16 (2). Это просто сдвиг на 4 (1) позиции вправо. Тут всё понятно
Чтобы получить дробное значение, можно что-то мутить с 4 битами. А можно поступить проще - сначала умножить на 10, затем уже делить на 16 (2). Упростив, сводим это к умножению на 5 и сдвигу на 3 (для DS18B20) или без сдвига (для DS18S20). Результат - целое число, выражающее температуру в десятых долях градуса. Ну а при выводе на экран просто нужно точку не забыть поставить в нужном месте. И никакой возни с float/double и раздувающегося от этого кода.
Как уже сказано, просто забрав два байта из памяти, мы получаем уже готовое для работы значение температуры. Правда, умноженное на 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.
возьмите калькулятор Windows, включите его в режим программиста и убедитесь, что описанное мною ранее полностью верно. делить нужно. то, что деление на 16 можно заменить сдвигом на 4, сути не меняет.levaclaus писал(а):Целое число не нужно делить.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Всё по DS18(B/S)20.
Я вообще считаю максимальное разрешение В варианта датчика избыточным, учитывая его собственную погрешность и тот факт, что его вроде бы не используют в медицинских целях. Потому и ставлю 9-битное разрешение в его конфиг-регистре. Шага в 0.5 вполне достаточно на мой взгляд.
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
- levaclaus
- Потрогал лапой паяльник
- Сообщения: 302
- Зарегистрирован: Пн янв 07, 2008 16:56:28
- Откуда: Минск
Re: Всё по DS18(B/S)20.
Отличный пример с калькулятором. Ок, откройте калькулятор и введите в него биты с 4 по 11 из таблицы ниже (с 4 по 9 хранится целая часть, откиньте четыре младших бита, я спецом красным выделил) и переведите в 10-тичную систему. Опа, оказывается все сошлось с таблицей. И ненужен не флоат, не интеджер. Достаточно signed char (максимально до 127 градусов).ARV писал(а):возьмите калькулятор Windows, включите его в режим программиста и убедитесь, что описанное мною ранее полностью верно. делить нужно. то, что деление на 16 можно заменить сдвигом на 4, сути не меняет.levaclaus писал(а):Целое число не нужно делить.
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.
Это-то так (хотя, вернее, с 4 по 11). Но всё равно, чтобы выделить этот байт, без промежуточных вычислений не обойтись. Самое простое - сдвинуть на 4 16-битное число (reg[0] и reg[1] - это байты температуры).откройте калькулятор и введите в него биты с 4 по 9 из таблицы ниже
Код: Выделить всё
int16_t temp = *(int16_t*)reg;
temp *= 10;
temp /= 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.
ок, давайте ваш вариант кода в студию! сравним, будет ли он проще, чем мой *temp / 16levaclaus писал(а):И ненужен не флоат, не интеджер. Достаточно signed char (максимально до 127 градусов)
исходные данные: в массиве buf лежат полученные из датчика 9 байтов, CRC проверили - все верно. теперь пишите ваш код, который из двух char-ов buf[0] и buf[1] извлечет температуру в целых градусах, особенно, если температура отрицательная.
жду.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Всё по DS18(B/S)20.
Как не нужно ? Посмотрите внимательнее на картинкуlevaclaus писал(а):вот картинка из датащита Целое число не нужно делить. Делить нужно только дробную часть. Если эта дробная часть нужна...
Делить нужно и целую и дробную части.
Вообще, я всегда храню температуру в int'е с фиксированной точкой после первого разряда (умноженную на 10). Пихаем оба байта в int-переменную, умножаем на 10 и делим на 16. и никаких проблем.
Пример выше у WiseLord'а.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Всё по DS18(B/S)20.
ARV: я чуть выше написал, как это предположительно выглядело бы в случае двух char-ов. Смотрится плохо, но вряд ли можно компактнее сделать по коду. С 16-бит числом проще всего, тем более что первые два байта массива фактически и есть это готовое 16-бит число.
В примере я приведение типа указателя использовал. Хотя у себя предпочитаю union и struct:
Тут для датчика все нужные данные легко хранятся - и его ID, и скрэтчпад, и автоматическое приведение первых байтов в in16 температуру.
В примере я приведение типа указателя использовал. Хотя у себя предпочитаю 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;- levaclaus
- Потрогал лапой паяльник
- Сообщения: 302
- Зарегистрирован: Пн янв 07, 2008 16:56:28
- Откуда: Минск
Re: Всё по DS18(B/S)20.
в temp10 не может быть отрицательной температуры. В этом то и фишка, и прелесть работы с целой и дробной частью порознь. Дополнительный код распространяется только на целую часть, а дробная в прямом. Все согласно датащиту.
Вот код, рабочий. Главный офигенный + экономия места. Если знак после запятой убрать, места ещё больше окажется. Сейчас прога весит 822 байта. С оригинальной библиотекой более 1,5 кбайта.
Вот код, рабочий. Главный офигенный + экономия места. Если знак после запятой убрать, места ещё больше окажется. Сейчас прога весит 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.
у меня нет сомнений в вашей квалификации, и свой вопрос я адресовал не вамWiseLord писал(а):я чуть выше написал, как это предположительно выглядело бы
levaclaus писал(а):Дополнительный код распространяется только на целую часть, а дробная в прямом.
очень далеко не все: как минимум, вы не считываете весь scratchpad и не проверяете CRC принятых данных. одно это полностью противоречит даташиту.levaclaus писал(а):Все согласно датащиту
то есть вы продолжаете настаивать, чтоlevaclaus писал(а):Вот код, рабочий
проще и оптимальнее, чем предложенный мной вариантlevaclaus писал(а):((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
???ARV писал(а):*temp / 16
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Всё по DS18(B/S)20.
Вы очень сильно ошибаетесь. Дополнительный код распространяется на всё число, и Ваш код в плане temp10 - неверен.levaclaus писал(а):Дополнительный код распространяется только на целую часть, а дробная в прямом. Все согласно датащиту.
Даже не картинке, что Вы выкладывали:
Да, для 0,5 и -0.5 дробная часть одинаковая. Но только для такой дробной части.+10.125 0000 0000 1010 0010
-10.125 1111 1111 0101 1110
- levaclaus
- Потрогал лапой паяльник
- Сообщения: 302
- Зарегистрирован: Пн янв 07, 2008 16:56:28
- Откуда: Минск
Re: Всё по DS18(B/S)20.
для моего варианта нужно одно signed char или дваARV писал(а):
то есть вы продолжаете настаивать, чтопроще и оптимальнее, чем предложенный мной вариантlevaclaus писал(а):((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
для вашего нужен float либо integer и много много памяти для работы с ним.
Да, я наставаю, что мой вариант лучше.
Бли, точно, с дробными ошибся, но делов то.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Всё по DS18(B/S)20.
levaclaus писал(а):либо integer и много много памяти для работы с ним
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Всё по DS18(B/S)20.
Они одинаковые всего-лишь из-за совпадения. +0.5(значение = +8) и -0.5(значение = -8) имеют одинаковые 4 младших бита.WiseLord писал(а):Да, для 0,5 и -0.5 дробная часть одинаковая. Но только для такой дробной части.
levaclaus ошибается в том, что дробная часть не имеет отрицательного значения. Ещё как имеет. У оцифрованного значения "-1" (это -0.0625 градуса) дробная часть равна 1111.
Добавлено after 10 minutes 7 seconds:
А вот этот код :
Код: Выделить всё
((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)levaclaus, вы вместо выдвиганий своих мыслей за правду, взяли бы лучше бумажку с карандашиком и уделили бы этому вопросу немного времени, разрисовывая битики и байтики. И всё бы встало на свои места. Вопрос то элементарный, на уровне 5-ого класса.
- levaclaus
- Потрогал лапой паяльник
- Сообщения: 302
- Зарегистрирован: Пн янв 07, 2008 16:56:28
- Откуда: Минск
Re: Всё по DS18(B/S)20.
у меня места в контроллере 1кбайт, было бы 2, я бы не взрывал Ваш мозг.Аlex писал(а): А вот этот код :эквивалентен сдвигу обоих байтов вправо на 4 и отбрасыванию старшего байта. Что и есть обычное деление на 16, только с туевой хучей ненужных операцийКод: Выделить всё
((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
levaclaus, вы вместо выдвиганий своих мыслей за правду, взяли бы лучше бумажку с карандашиком и уделили бы этому вопросу немного времени, разрисовывая битики и байтики. И всё бы встало на свои места. Вопрос то элементарный, на уровне 5-ого класса.
В каноничном варианте, коего здесь сторонники собрались, делить на 16 предлагают 16-битное число. С таким подходом программа занимает 1,5 кбайта для варианта с float и 1,3 кбайта для варианта с integer.
Предложенный мной вариант использует два char. И теперь прога мало того что занимает 830 байт, так ещё и работает, зараза.
Сжечь еретика-Коперника, он нам тут воздух портит...
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Всё по DS18(B/S)20.
В каноничном варианте, коего здесь сторонники собрались, делить на 16 предлагают 16-битное число. С таким подходом программа занимает 1,5 кбайта для варианта с float и 1,3 кбайта для варианта с integer.
Во-первых, не делить, а сдвигать. Во вторых, даже если делить - компилятор всё равно это сделает сдвигом.
Во-первых, не делить, а сдвигать. Во вторых, даже если делить - компилятор всё равно это сделает сдвигом.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Всё по DS18(B/S)20.
это сильно... такая слава.... такая честь....levaclaus писал(а):Сжечь еретика-Коперника, он нам тут воздух портит
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Всё по DS18(B/S)20.
Я просто даже представить не могу, что вы там такого понаписали, что сдвиг 16-битной переменной занимает на 500 байт больше, чем вот такое :levaclaus писал(а):и 1,3 кбайта для варианта с integer
((MSB<<4)&0xf0) | ((LSB>>4)&0x0f)
Вы бы слова свои кодом что-ли прикрепляли. В идеале - два куска, которые вы меняете местами, получая такую разницу в использованной памяти.
Re: Всё по DS18(B/S)20.
Ну вот,подшаманил я свой градусник. Проблема вывода -9999 исчезла,т.к скинул это значение в другие переменные.Только теперь в случае обрыва шины или выхода из строя датчиков будут выводиться последние значения..Теперь чтобы вывести сигнал аварии(---- на 7-сегментниках) мне уважаемый Аlex подсказал,что нужно проверять CRC. Теперь буду кумекать как прочитать этот CRC..буду рад любой помощи по этому вопросу.. Спасибо..
- Вложения
-
- termo8.rar
- (320.33 КБ) 209 скачиваний