Страница 1 из 4
DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Вт дек 23, 2025 18:49:52
Mursik
Возник вопрос по сабжу (решил быстренько слепить термометр на 7-сегментном индикаторе). Если с целыми положительными температурами вопросов не возникло (сдвинул результат преобразования на 4 бита вправо) и получил градусы.
То с отрицательными появились непонятки.
Обычно на форумах вижу преобразование из отрицательных значений через побитовую инверсию с добавлением единицы к результату. Вроде как работает в протеусе, хотя при некоторых значениях получается на 1 больше почему то.
Но главная непоянтка с долями градуса.
ИИ в гугле советует сделать всё просто:
int16_t raw_temp = (raw_data_byte2 << 8 ) | raw_data_byte1; // Combine bytes
float temp_C = (float)raw_temp / 16.0; // For 12-bit (0.0625)
Получаем результат с плавающей точкой. Но мне не хотелось бы к плавучке приходить из за сложностей потом на разряды индикатора её выдёргивать.
А инверсия побитовая с добавлением единицы у меня почему то даёт не тот результат..
Как правильно тот скратчпад 16 бит преобразовать из отрицательных температур?

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Вт дек 23, 2025 19:57:00
JackSmith
Код: Выделить всё
uint16_t temp=ds18b20_read();
uint16_t frac= ((temp & (uint16_t)0x0f)*10)/16;
temp >>= 4;
frac - дробная часть, tmp - целая часть, для отрицательных температур очищайте знаковые старшие биты.
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Вт дек 23, 2025 20:29:44
АлександрЛ
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 00:09:22
BOB51
Под ассемблером там проблем нет.
Вроде и под Си ардуиняче чего то было...

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 04:05:39
AlexS4
а там вроде старший байт заполнен раскопированным битом знака обзовем unsigned char h_raw
а младший байт (unsigned char l_raw) это само значение signed c младшим битом ценой в 0.5C
по сути это означает что если загрузить это в signed int16 и разделить на 2
то знак будет знаком, а модуль будет модулем. а младший выдвинутый бит если задвинуть с младшей стороны в char и умножить на 5 - дробной частью.
а если хотим модуль на коленке без abs() и прочей высшей математики

, а с простейшей аля asm,
то примерно так думаю сойдет:
Код: Выделить всё
unsigned char h_raw, l_raw, sign, tempmodule,tempdecimals;
sign=h_raw & 01 ; // 0 -> +C 1 -> -C
tempdecimals=(l_raw & 01)* 5 ; // xxx.0C or xxx.5C
if(sign) l_raw= 0xFF - l_raw ; //below zero C. so, negative to absolute value conversion
tempmodule=l_raw >> 1 ; //integer part С
ну понятно что там всего 2 или 3 переменные (регистра) нужны,
остальные для наглядности исключительно..
не проверял, если накосячил скандачка спросони

... вобщем настоящий кот поленится пинать

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 06:22:13
akl
Как вариант. Проверяется принятый результат, знак запоминается. Если отрицательный, конвертируется. Умножается на 10 и сдвигом делится на 16. К полученному результату прибавляется значение флага C для правильного округления.
Спойлер
Код: Выделить всё
; Считанные данные находятся в R11:R12
; ZH=0
LCD_CONVERT:
CBI ACSR,MINUS ; очистить признак минусового результата
CLR R10
TST R11
BRPL GO_PLUS
COM R11
COM R12
ADC R12,ZH
ADC R11,ZH
SBI ACSR,MINUS ; установить признак минусового результата
GO_PLUS:
RCALL MULT10
;R10,R11,R12 результат старший-младший
LSR R10
ROR R11
ROR R12
LSR R10
ROR R11
ROR R12
LSR R10
ROR R11
ROR R12
LSR R10
ROR R11
ROR R12
; разделить полученное значение на 16, чтобы
; получить десятичный эквивалент результата
ADC R12,ZH
ADC R11,ZH
ADC R10,ZH ; округление результата
RCALL KALK1
RET
;************************************************
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 10:31:01
Mursik
Короче, психонул и решил начать с ..протеуса. Думаю, а вдруг это он мне мозг выносит?
Решил выплёвывать в терминал получаемые два байта скратчпада температуры.
24,6 - 0x0188
24,5 - 0x0188
24,4 - 0x0180
24,3 - 0x0180
24,2 - 0x0180
24,1 - 0x0180
24,0 - 0x0180
Код: Выделить всё
write_byte(0xCC); //skip ROM
write_byte(0xBE); //read scratch
Tmp1 = read_byte();
Tmp2 = read_byte();
putc(0xAA);
putc(0xAA);
putc(Tmp2);
putc(Tmp1);
putc(0xCC);
Короче, выходит моделька DS18b20 дробную часть как то странно выдаёт.

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 10:47:20
linux_rulezz
У него ж точность ±1.5℃ в расширенном диапазоне температур, а воспроизводимость ±0.5℃. Зачем вообще пытаться из этого УГ пытаться получить температуру?
Возьмите уж NTC…
Добавлено after 1 minute 27 seconds:
Mursik, а это точно B, а не S?
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 11:08:36
roman.com
а в чём собственно вопрос ?
для начала как обычно смотрим даташит...
видим что при отрицательных температурах получаем отрицательное число (единица в первом разряде).
а далее всё как обычно... работа со знаковыми переменными...
//DEC -0...-2.147.483.648 | 0...2.147.483.647
//HEX -80 00 00 00...ff ff ff ff | 0...7f.ff.ff.ff
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 11:16:14
Novice user
[uquote="Mursik",url="/forum/viewtopic.php?p=4774723#p4774723"]выходит моделька DS18b20 дробную часть как то странно выдаёт.

[/uquote]
Проверил у себя,шаг в свойствах DS18B20 поставил 0,0625,работает норм,вот снижал от 24,5 до 23,9 с шагом 0,0625

А здесь снижаю с -0,0625 до -0,625

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 11:33:20
Mursik
Продолбался с протеусом (v9), плюнул, стал из даташита ту таблицу тупо в программе подсовывать вместо полученного с датчика значения - получил заданные значения.
Стало быть моделька в протеусе врёт.

На опцию "granularity" в настойках модель не реагирует - выдаёт сильно грубый шаг.
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 11:56:48
BOB51
Первое действие
temp=(~temp)+1
разделяем старшую часть и младшие 4 бита (включено 12 разрядное преобразование)
temp_h = temp >> 4
temp_l = temp & 0x000f
далее декодирование целой части в код сегментов целых
Записать коды сегментов "минус" и "запятая" в соответствующие знакоместа дисплея
Получить значение дробной части в целых числах исходя из веса разрядов в ранее выделенной младшей тетраде данных
бит 3 = 5000
бит 2 = 2500
бит 1 = 1250
бит 0 = 625
далее обработать получившийся результат для вывода в раздел индикатора, выделенный для дробной части.
Воть как то так ...

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 12:16:31
Аlex
Блин, вы серьёзно ?
Если на Сях, то всё очень просто. Тупо берём и считываем с датчика 2 байта в знаковую переменную. И всё, получаем температуру с необходимым разрешением и знаком.
Для перевода в градусы, просто делим значение на 16 (для "B", разрешение 0.0625) или на 2 (для "S", разрешение 0.5).
Всё.
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 12:34:42
Mursik
[uquote="Аlex",url="/forum/viewtopic.php?p=4774764#p4774764"]Для перевода в градусы, просто делим значение на 16 (для "B", разрешение 0.0625) или на 2 (для "S", разрешение 0.5).
Всё.[/uquote]
Беда такого деления в плавучем результате. Если куда printf() плевать оно конечно само разгребет, но если ручками на 7-сегментный индикатор раскладывать, тут тут геморно с флоат воевать

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 12:37:19
BOB51
Алгоритм со времён ассемблера однако.
Где там быстро математику сделать?
Заодно и в сегментный код перекинуть проще.

Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Ср дек 24, 2025 12:45:56
Novice user
Вот в баском,переменные только Т=два байта,остальные один байт,проверил в протеусе.
Код: Выделить всё
Byte0 = 1wread() ' Читаем нулевой байт
Byte1 = 1wread() ' Читаем первый байт
Print HEX(Byte1);HEX(Byte0)
If Byte1 > 248 Then ' Проверка на отрицательность температуры
Byte0 = &HFF - Byte0
Byte1 = &HFF - Byte1
Byte0 = 1+ Byte0
Sign = "-"
End If
T = Byte1*16 ' Сдвигаем первый байт вправо на 4 бита (2*2*2*2=16)
T1 = Byte0/16 ' Сдвигаем нулевой байт влево на 4 бита (2*2*2*2=16)
t1=t1+t 'Целая часть
t=Byte0 And 15 'дробная часть
t=10*t 'умножаем на 10 и делим на 16
t=t/16
print t1;".";t
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Пт дек 26, 2025 14:21:05
Аlex
Mursik писал(а):Беда такого деления в плавучем результате.
Что такое "Плавучий результат" ? Поясните.
Mursik писал(а):тут геморно с флоат воевать
Зачем тут флоат нужен ? Все операции можно делать с целыми числами.
PS: В чём вообще проблема, не могу понять ? Вам же градусник уже отдаёт готовую температуру, умноженную на разрешение (2 или 16).
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Пт дек 26, 2025 15:36:38
akl
[uquote="Аlex",url="/forum/viewtopic.php?p=4774764#p4774764"]Тупо берём и считываем с датчика 2 байта в знаковую переменную. И всё, получаем температуру с необходимым разрешением и знаком.
Для перевода в градусы, просто делим значение на 16 (для "B", разрешение 0.0625)...
Всё.[/uquote]Потеряли дробную часть.
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Пт дек 26, 2025 17:23:11
Аlex
akl писал(а):Потеряли дробную часть.
Ну, так, умножаем на 10, 100 (или сколько нужно), а потом делим. И получаем фиксированную точку.
Всё же элементарно...
Re: DS18b20 мороз с разрешением 0,1 градуса
Добавлено: Пт дек 26, 2025 17:53:32
Thinnnfor
Код: Выделить всё
aaa (unsigned char dev) // функция считывания t с датчика номер(dev) и вывод значения
// на лсд с отбросом незначащих нулей (до запятой)
{
tem=ds18b20_temperature(&ee_code[dev][0])*10; //считываем и умножаем на 10
if (tem<0) // если показание отрицательное
{
lcd_putsf("-"); //выводим "-" на лсд
tem=-tem; //инвертируем показание
}
if (tem<1260) {
if (tem>=1000) goto la1;
if (tem>=100) goto la2; // отброс незначащих нулей
goto la3 ; // тоже отброс незначащих нулей
la1: lcd_putchar(tem/1000+48); // сотни
la2: lcd_putchar(tem%1000/100+48); // десятки
la3: lcd_putchar((tem%100)/10+48); // единицы
lcd_putchar(44); // запятая
lcd_putchar(tem%10+48); // десятые градуса
lcd_putchar(223); // градус °
lcd_putsf("C "); //C цельсия
}
else lcd_putsf("Err ");// если t<1260 выводим на лсд
// иначе выводим "Err" (ошибка)
}
Добавлено after 1 minute 6 seconds:
signed int tem;