Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Преобразовать данные с DS18B20 в строку printf
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Pilot134
Здравствуйте.
Сразу хочу извиниться что для многих мой вопрос покажется примитивным, но всё же.
Считал я температуру с термометра DS18B20 в 2 регистра temp1 (char) и temp2 (char) .
Младшая тетрада temp1 и старшая тетрада temp2 имеют значение целой части температуры.
Младшая тетрада temp2 имеет дробную часть температуры.
Я хочу строчкой printf("...") вывести в уарт МК данные чтобы у меня показывало температуру в формате 25.4
Голову сломал не знаю как сделать sad.gif
Помогите пожалуйста. Понятно что вопрос дилетанта.
Работаю в CodeVisionAVR. МК atmega8.
Спасибо.
megajohn
все домой ушли, так что если вечер свободен то можете этот кусок подправить для вывода дробной части

Код
#ifdef DS18B20
    #define DS18X20_SHIFT 4
#endif


lsb = OneWireReadByte( mask );
msb = OneWireReadByte( mask );
s16 curr_temper_cels = (msb << 8) + lsb;
if( curr_temper_cels & (1 << 15) )
{
curr_temper_cels = -curr_temper_cels;
curr_temper_cels = (curr_temper_cels * 10) >> DS18X20_SHIFT;
curr_temper_cels = -curr_temper_cels; //  Restore sign.
}
else
{
curr_temper_cels = (curr_temper_cels * 10) >> DS18X20_SHIFT;
}

printf( "temper=%d", curr_temper_cels  );
adnega
Цитата(Pilot134 @ Oct 2 2013, 18:52) *
Здравствуйте.
Сразу хочу извиниться что для многих мой вопрос покажется примитивным, но всё же.
Считал я температуру с термометра DS18B20 в 2 регистра temp1 (char) и temp2 (char) .
Младшая тетрада temp1 и старшая тетрада temp2 имеют значение целой части температуры.
Младшая тетрада temp2 имеет дробную часть температуры.
Я хочу строчкой printf("...") вывести в уарт МК данные чтобы у меня показывало температуру в формате 25.4
Голову сломал не знаю как сделать sad.gif
Помогите пожалуйста. Понятно что вопрос дилетанта.
Работаю в CodeVisionAVR. МК atmega8.
Спасибо.

printf("temp=%2x.%d", temp1, temp2);

Но что делать с отрицательной температурой?
Pilot134
Цитата(adnega @ Oct 2 2013, 21:24) *
printf("temp=%2x.%d", temp1, temp2);

До отрицательной ещё не добрался.
Вставил Ваш вариант и не заработало sad.gif

Цитата(megajohn @ Oct 2 2013, 21:18) *
все домой ушли, так что если вечер свободен то можете этот кусок подправить для вывода дробной части

Код
#ifdef DS18B20
    #define DS18X20_SHIFT 4
#endif


lsb = OneWireReadByte( mask );
msb = OneWireReadByte( mask );
s16 curr_temper_cels = (msb << 8) + lsb;
if( curr_temper_cels & (1 << 15) )
{
curr_temper_cels = -curr_temper_cels;
curr_temper_cels = (curr_temper_cels * 10) >> DS18X20_SHIFT;
curr_temper_cels = -curr_temper_cels; //  Restore sign.
}
else
{
curr_temper_cels = (curr_temper_cels * 10) >> DS18X20_SHIFT;
}

printf( "temper=%d", curr_temper_cels  );


Посмотрел код и у меня вопрос.
Строчка:
s16 curr_temper_cels = (msb << 8) + lsb; - переменная формата sig int curr_temper_cels.
Мы в неё записываем старший байт (temp1) сдвинутый 8 раз влево и прибавляем младший байт.
___
Строчка:
curr_temper_cels = (curr_temper_cels * 10) >> DS18X20_SHIFT; - берёт переменную curr_temper_cels и умножает её на 10, сдвигает 4-е раза вправо и вновь вписывает в переменную curr_temper_cels
Правильно я понимаю? Спасибо.
adnega
Цитата(Pilot134 @ Oct 2 2013, 19:36) *
До отрицательной ещё не добрался.
Вставил Ваш вариант и не заработало sad.gif

А тут работает http://codepad.org/eTaPDzDX
А в чем неработоспособность заключается?
printf("Hello World") работает?
Pilot134
Цитата(adnega @ Oct 2 2013, 21:43) *
printf("Hello World") работает?

Это работает sm.gif
Вопрос в том чтобы преобразовать значение с термометра DS18B20 в строчку printf("...") и чтобы температура выводилась в виде 25.6
Я считал температуру с датчика DS18B20 и она содержится в 2-х байтах. В старшем (temp1) и младшем (temp2).
Я уже научился выводить целую часть температуры:
Код
temperatura = ((temp1)<<4)|(temp2>>4);
printf("temp = %d C\r\n",temperatura);

и вижу на компе текст (комп с микроконтроллером общаются по усарту)
temp = 26 С
А вот с дробной частью пока проблема sad.gif
Отрицательные температуры ещё не делал sm.gif

Цитата(adnega @ Oct 2 2013, 21:43) *
А тут работает http://codepad.org/eTaPDzDX

sm.gif
там то работает.
Дело в том что у термометра DS18B20 температура считывается определённым образом.
Как видно из скрина старший байт только в младшей тетраде содержит значения целой части температуры.
А младший - старшая тетрада содержит также целую часть, а младшая тетрада младшего байта содержит только лишь дробную часть.
Спасибо что отозвались!
adnega
Цитата(Pilot134 @ Oct 2 2013, 20:00) *
Дело в том что у термометра DS18B20 температура считывается определённым образом.

Как температура выдается DS18B20 и то, как описали Вы в первом посте вещи, мягко говоря, не эквивалентные.
Попробуйте так: http://codepad.org/oKLnmEul
Pilot134
Цитата(adnega @ Oct 2 2013, 22:39) *
Как температура выдается DS18B20 и то, как описали Вы в первом посте вещи, мягко говоря, не эквивалентные.

Виноват sad.gif
Цитата(adnega @ Oct 2 2013, 22:39) *
Попробуйте так: http://codepad.org/oKLnmEul

Спасибо! То что нужно rolleyes.gif
Pilot134
Очень сильно извиняюсь!
Но появился ещё один вопрос - как можно перевести двоично-десятичное число в двоичное.
Причём двоично-десятичное содержит 3 значящих тетрады.
Т.е. число типа int 0000 0011 0100 0101 (2dec) нужно преоборазовать в int 0000 0001 0101 1001 (Bin)
где 0000 0011 0100 0101 - число 0345 двоично-десятичное
а 0000 0001 0101 1001 - двоичное число 345.
Спасибо.
Палыч
Цитата(Pilot134 @ Oct 4 2013, 20:16) *
Но появился ещё один вопрос - как можно перевести двоично-десятичное число в двоичное.
Причём двоично-десятичное содержит 3 значящих тетрады.

Так - как этому учат в школе: первую тетраду умножаем на 100, складываем со второй тетрадой умноженной на 10, и всё это складываем с третьей тетрадой...
ARV
ну почему у всех мода такая - побайтно интерпретировать температуру DS18x20?! ведь в описании вполне доступно написано, что 2 первых байта представляют температуру в дополнительном двоичном коде в долях градуса! то есть вам надо 2 байта рассматривать как обычный int (16-битный, естественно!) - и будет вам температура со знаком! только поделить на разрешающую способность предварительно, т.е. если режим датчика для 9-битной температуры, то разрешающая способность 0,5 градуса, т.е. двухбайтное число типа int надо поделить на 2.
Pilot134
Цитата(Палыч @ Oct 4 2013, 22:33) *
Так - как этому учат в школе: первую тетраду умножаем на 100, складываем со второй тетрадой умноженной на 10, и всё это складываем с третьей тетрадой...

Спасибо!
Pilot134
Только пожалуйста не ругайтесь. Но что-то немного не понял sad.gif
У устройства есть вывод значений температуры (порог) на дисплей.
Кнопками я могу редактировать это значение и вписываю (например) цифры 26,5. Всего 3 цифры.
Мне нужно чтобы при достижении этой температуры включалось реле и сигнализировало (т.е. сравнивать значения на дисплее с показаниями с термометра).
Соответственно у меня есть переменные zifr_1 = 0x02, zifr_2 = 0x06, zifr_3 = 0x05 (двоично-десятичный код)
У термометра DS18B20 этой температуре соответствует код 0000 0001 1010 1000 (двоичный код)
Как я могу перейти в одинаковую систему единиц для их сравнения?
Я сначала думал что нужно:
0x02(hex) * 100(dec) = 0b1100 1000
+
0x06(hex) * 10(dec) = 0b0011 1100
+
0b00000101
= 1 0000 1001
Что ни как не равно показаниям термометра (0000 0001 1010 1000).
Зашёл в тупик smile3046.gif
Помогите пожалуйста.
megajohn
приведите результаты к одному 16битному BCD
типо так
0000 AAAA BBBB CCCC где температора AB,C и

Палыч
Цитата(Pilot134 @ Oct 7 2013, 11:10) *
Зашёл в тупик smile3046.gif
Помогите пожалуйста.

1. Пусть у нас есть три цифры: А - десятки единиц, В - единицы, С - десятые доли
2. Следует получить двоичное число, где запятая стоит перед четвертым разрядом (т.е. умноженное на 16 = 2 в степени 4) - см. документацию на м/с.
3. Из А,В и С получаем число АВС, выраженное в десятых долях (т.е. 10 раз большее чем есть на самом деле):
А*100 + В*10 + С
4. Вспоминаем (см.п2), что нам нужно число, умноженное на 16
(А*100 + В*10 + С) * 16
5. У нас же было число увеличенное в 10 раз (см.п3), поэтому делим на 10:
(А*100 + В*10 + С) * 16 / 10
Pilot134
Цитата(megajohn @ Oct 7 2013, 13:43) *
приведите результаты к одному 16битному BCD
типо так
0000 AAAA BBBB CCCC где температора AB,C и

Интересный вариант.
Температуре 26,5 град. соответствует код 0000 0001 1010 1000
Откидываем дробную часть останется 0000 0000 0001 1010
Как из него получить двоично-десятичный код? Т.е. AAAA BBBB?
Как округлить до десятых дробную часть показаний термометра уже мне подсказали выше (будет СССС).
Т.е. впринципе можно действительно сравнить числа в двоично-десяичном формате (0000 АААА ВВВВ СССС).
Вот только подскажите пожалуйста перевод из двоичного в двоично-десятичный код (из 0001 1010 получить 0010 0110).
Спасибо!
Палыч
Цитата(Pilot134 @ Oct 7 2013, 12:11) *
Вот только подскажите пожалуйста перевод из двоичного в двоично-десятичный код (из 0001 1010 получить 0010 0110).

Блин! Вы, что? В школе не учились?
Обозначим Ваше число 0001 1010 как Х:
АААА= Х /10
а остаток от деления - вторая тетрада
ВВВВ= Х % 10
Pilot134
Цитата(Палыч @ Oct 7 2013, 14:50) *
Блин! Вы, что? В школе не учились?
Обозначим Ваше число 0001 1010 как Х:
АААА= Х /10
а остаток от деления - вторая тетрада
ВВВВ= Х % 10

Уважаемый Палыч.
В школе учился.
К сожалению я не очень силён в си sad.gif о чём очень сожалею и извиняюсь что спрашиваю ерунду.
Теперь знаю!
Что целую часть от деления пишем АААА = Х /10;
Остаток ВВВВ= Х % 10;
Вам огромное Спасибо! rolleyes.gif
Палыч
Цитата(Pilot134 @ Oct 7 2013, 14:49) *
К сожалению я не очень силён в си

К языку Си ваши вопросы не имеют отношения.
Ещё в начальных классах школы дают понятие "позиционная система счисления". Коль подзабыли - погуглили бы...
ukpyr
Код
// convert 12-bit temperature data of ds18b20 to signed celsius fixed-point (with tenth)
S16 ds1w_12bit2tenth(U16 value) {
    U8 value_sign = (value >> 8) & 0x80; // remember sign of value
    if (value_sign) value = 0 - value;   // convert to absolute value
    value = (value >> 1) + (value >> 3); // convert from 12-bit to fixed point
    if (value_sign) value = 0 - value;   // restore sign of result
    return value;
}
ARV
Цитата(ukpyr @ Oct 7 2013, 17:53) *
Код
// convert 12-bit temperature data of ds18b20 to signed celsius fixed-point (with tenth)
S16 ds1w_12bit2tenth(U16 value) {
    U8 value_sign = (value >> 8) & 0x80; // remember sign of value
    if (value_sign) value = 0 - value;   // convert to absolute value
    value = (value >> 1) + (value >> 3); // convert from 12-bit to fixed point
    if (value_sign) value = 0 - value;   // restore sign of result
    return value;
}

почему-то мои сообщения как-то игнорируют... вот так надо:
Код
static char scratchpad[9]; // в этот массив считываются все регистры датчика

float temperature(void){

   int* ptr = (void*)scratchpad;

   return *ptr / 16.0; // для DS18B20 в 12-битном разрешении, для 9-битного делить на 2.0

}
ukpyr
зачем float для простейшей формулы ?
Pilot134
Цитата(ARV @ Oct 7 2013, 21:58) *
почему-то мои сообщения как-то игнорируют... вот так надо:
Код
static char scratchpad[9]; // в этот массив считываются все регистры датчика

float temperature(void){

   int* ptr = (void*)scratchpad;

   return *ptr / 16.0; // для DS18B20 в 12-битном разрешении, для 9-битного делить на 2.0

}

Я ни в коем случае ни кого не игнорирую.
Я очень Вам признателен за то что помогаете таким "спецам" как я.
Я уже эту часть сделал. Работает. Круто!!!
Спасибо ВАМ и этому замечательному форуму rolleyes.gif
Tarbal
Цитата(Палыч @ Oct 7 2013, 11:57) *
1. Пусть у нас есть три цифры: А - десятки единиц, В - единицы, С - десятые доли
2. Следует получить двоичное число, где запятая стоит перед четвертым разрядом (т.е. умноженное на 16 = 2 в степени 4) - см. документацию на м/с.
3. Из А,В и С получаем число АВС, выраженное в десятых долях (т.е. 10 раз большее чем есть на самом деле):
А*100 + В*10 + С
4. Вспоминаем (см.п2), что нам нужно число, умноженное на 16
(А*100 + В*10 + С) * 16
5. У нас же было число увеличенное в 10 раз (см.п3), поэтому делим на 10:
(А*100 + В*10 + С) * 16 / 10


надо проделать два шага:
1. разделить поля при помощи маскирования четырех младших бит и предварительного сдвига на 4 бита для единиц и на 8 для десятков. Я полагаю у вас все в одном 16 (или 32) битном числе.
2. Получив три числа надо одно умножить на 10 и сложить со вторым. Дробную часть отдельный вопрос. Неизвестно еще как она представлена. Если BCD, то наверное надо перейти к числам с плавающей запятой и поделив третье число на 10 прибавить к сумме.
Так вы получите значеное, которое можно использовать как угодно.
printf("%f", result);

Если вам только напечатать, то вместо второго шага можно сразу:
printf("%d%d,%d", val_x_10, val_x_1, val_x_0_1);

советую вам внимательно проверить как представлена дробная часть.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.