Страница 1 из 2
Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 10:35:33
Tom91
Доброго времени суток!
Начал осваивать DS18B20, помогите разобраться как перевести 2 байтный код в численный ASCI код LCD.
SSSS SXXX XXXX XXXX - исходный код с DS18B20
SXXX XXXX X - тот что хочу преобразовывать (биты 0,1,2 откинул), где S - показатель знака, S=0 температура положительна, S = 1 - температура отрицательна. На LCD хочу получить что-то типа SXXX,X ,где S - знак.
Только хотелось бы увидеть код на ассемблере.
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 11:10:12
Vov123
В CVAVR что-то типа этого sprintf(buf,"t%u=%i.%u\xdfC",++i,temp/10,abs(temp%10));
если температура отрицательная,будет знак - минус.
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 11:15:43
Tom91
Vov123, спасибо конечно, но с CVAVR я не работаю.
Может кто сможет объяснить на ассемблере?
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 11:36:54
Pavel V.
Я до градусов округляю, десятые не использую. Вот пример:
Код: Выделить всё
uint16_t fullTemperature = (scratchpad[1] << 8) | scratchpad[0];
if(m_Roms[i].Bytes[0] == DS18B20) {
m_Temperature[i] = (int8_t)(fullTemperature >> 4);
} else if (m_Roms[i].Bytes[0] == DS1920) {
m_Temperature[i] = (int8_t)(fullTemperature >> 1);
} else {
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 11:39:35
Хатуль_мадан
Вам нужен пример реализации или понять принцип преобразования? В свое время тоже начинал его изучение и тоже на ассемблере для термостата, очень помогло русское описание на датчик от Чернова Г. посмотреть можно тут
http://www.masterkit.ru/zip/ds18b20-rus.pdf. Там и примеры есть (тоже на ассемблере).
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 12:11:36
Tom91
Вам нужен пример реализации или понять принцип преобразования?
Всё в одном флаконе.
Итак у меня есть SXXX XXXX X (биты 11-3 для DS18B20) , где S - показатель знака, далее я разложил:
S - при 1 состоянии вывожу минус на дисплей, с этим проблем нет, остаётся
XXXX XXXX(биты 10-3) - лежит в регистре TEMP, теперь как этот ТЕМР преобразовать в численные значения LCD ??
тоесть чтобы получилось SXXX,X, так как S - это знак температуры и его вывести проблем не составит, остаётся преобразовать ТЕМР для получения численного значения в формате XXX,X Кто что предложит?
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 12:47:57
Хатуль_мадан
Ну если на пальцах, то датчик дает 12 разрядов измеряемой температуры (по умолчанию), причем 4 младших это дробная часть градуса, т.е 1/16=0,0625 дискретность замера. оставшиеся 8 разрядов (со знаком) это число соответствующее целым градусам в замере. В зависимости от того, что Вам нужно, такое количество разрядов и используете. Как реализовать, это дело вкуса каждого. Когда сам начинал изучение программирования, тоже искал свои пути решения. Вот предлагаю кусочек своей программы по Вашей задаче. Знатоков прошу не судить стого, возможно кое-что коряво, но работает.
PS:
Ну если кому интересно как, то это реализовано тут:
http://radiokot.ru/konkurs/012/
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 14:38:07
Rimsky
кое что из моего опыта
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 19:02:59
Tom91
.
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 20:29:48
stas00n
Tom91, вам нужно сначала преобразовать двоичное значение температуры в двоично-десятичное, поищите процедуры вроде bin2bcd, вот мой пример для беззнакового 8-бит целого:
Код: Выделить всё
_bin2bcd:
ldi r17,255
ldi r18,255
_calc_hundreds:
inc r18
subi r16,100
brbc sreg_c,_calc_hundreds
subi r16,156
_calc_tens:
inc r17
subi r16,10
brbc sreg_c,_calc_tens
subi r16,246
в r16 кладете двоичное значение, вызываете процедуру, из r18, r17, r16 забираете десятичные цифры. Поскольку у Вас число со знаком, то в случае если оно отрицательно (старший бит = 1), предварительно нужно взять его модуль (инвертировать и добавить единицу), а знак сохранить где-нибудь в другом регистре.
Дальше к каждой полученной двоично-десятичной цифре добавляете 0x30, получаете ASCII коды этих цифр. Дальше отправляете их на индикатор, тут уже сами разбирайтесь. Минус и запятую в виде ASCII кодов тоже отправляете в нужном месте.
Tom91 писал(а):SSSS SXXX XXXX XXXX
Вероятно, это значение лучше сперва прокрутить влево на 4 бита, чтобы старший байт был целой частью, младший - дробной (SXXXXXXX XXXX0000)
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 20:50:16
Tom91
Поскольку у Вас число со знаком, то в случае если оно отрицательно (старший бит = 1), предварительно нужно взять его модуль (инвертировать и добавить единицу), а знак сохранить где-нибудь в другом регистре.
тоесть если число отрицательное, то:
Вероятно, это значение лучше сперва прокрутить влево на 4 бита, чтобы старший байт был целой частью, младший - дробной (SXXXXXXX XXXX0000)
я старшие 4 бита даже считывать не собираюсь, а первые 3 пропускаю, S хранится отдельно
Дальше к каждой полученной двоично-десятичной цифре добавляете 0x30, получаете ASCII коды этих цифр.
непонятно почему тогда (код ниже) прибавляют не 30 ??? (исходник выше)
Код: Выделить всё
subi digit1, -48 ; подготовка к пересылке
subi digit2, -48
subi digit3, -48
subi digit4, -48
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 21:38:26
stas00n
Tom91 писал(а):
тоесть если число отрицательное, то:
Да. Но короче
Tom91 писал(а):
я старшие 4 бита даже считывать не собираюсь, а первые 3 пропускаю, S хранится отдельно
Уверены, что правильный результат получится? Я просто не работал с этими датчиками, не знаю в каком виде он данные дает.
Tom91 писал(а):
непонятно почему тогда (код ниже) прибавляют не 30 ??? (исходник выше)
Код: Выделить всё
subi digit1, -48 ; подготовка к пересылке
subi digit2, -48
subi digit3, -48
subi digit4, -48
Как раз 30 и прибавляют

Точнее, не 30, а 0x30, что в десятичном виде составляет 48, а поскольку в AVR нет инструкции сложения с константой, но есть вычитание, то сложение выполнено в виде вычитания "минус константы". В данном случае (когда гарантировано 0 <= digitx <= 9) можно то же самое сделать операцией ИЛИ с константой, т.е. "дописать" тройку в старший нибл:
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 22:09:51
stas00n
Tom91 писал(а):я старшие 4 бита даже считывать не собираюсь, а первые 3 пропускаю, S хранится отдельно
Тогда диапазон корректного измерения температуры будет от минус 16 до плюс 15 градусов, устраивает?
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 22:33:06
Tom91
stas00n, а не могли бы вы пояснить свой код преобразований, тоесть описать алгоритм его работы...
Код: Выделить всё
_bin2bcd:
ldi r17,255
ldi r18,255
_calc_hundreds:
inc r18
subi r16,100
brbc sreg_c,_calc_hundreds
subi r16,156
_calc_tens:
inc r17
subi r16,10
brbc sreg_c,_calc_tens
subi r16,246
stas00n писал(а):Tom91 писал(а):я старшие 4 бита даже считывать не собираюсь, а первые 3 пропускаю, S хранится отдельно
Тогда диапазон корректного измерения температуры будет от минус 16 до плюс 15 градусов, устраивает?
Почему?
SSSS SXXX XXXX XXXX - это 2байтный код с датчика обеспечивает 12разрядное разрешение, где S - показатель знака
Для 9 разрядного разрешения биты 0,1,2 откидываются что я и сделал, старшие 4 бита просто повторяют значения S, посути они ненужны, или я что-то не так понял?
В результате у меня остаётся только 9бит: S XXXX XXXX (приращение 0,5"С)
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 23:32:49
stas00n
Tom91 писал(а):stas00n, а не могли бы вы пояснить свой код преобразований, тоесть описать алгоритм его работы...
Так наверное будет понятней:
Код: Выделить всё
_bin2bcd:
ldi r17, -1
ldi r18, -1
_calc_hundreds:
inc r18
subi r16,100
brbc sreg_c,_calc_hundreds
subi r16, -100
_calc_tens:
inc r17
subi r16,10
brbc sreg_c,_calc_tens
subi r16, -10
Просто асемблер у меня когда-то не дружил с отрицательными числами, поэтому я заменял их положительными "аналогами", процессору-то пофигу...
Алгоритм такой: сперва считаем сотни, для этого вычитаем из преобразуемого числа 100; если результат положительный (не было переноса) инкрементируем разряд сотен, если перенос случился, значит результат отрицательный и подсчет сотен закончен, переходим к подсчету десятков, предварительно вернув последнюю вычтенную сотню "назад"; аналогично с десятками, инкрементируем регистр десятков вычитая из числа по 10 и сравнивая результат с нулем (смотрим на бит переноса); потом возвращаем "назад" последний вычтенный десяток, после этого единицы получаются сами собой в r16. Регистры десятков и сотен инициализируются значением минус один, т.к. инкрементируются они до первой операции вычитания (так цикл короче получается).
Tom91 писал(а):Для 9 разрядного разрешения биты 0,1,2 откидываются что я и сделал, старшие 4 бита просто повторяют значения S, посути они ненужны, или я что-то не так понял?
Дык, "откидывать" надо младшие биты
младшего байта, а вы откинули старшие, которые имеют наибольший вес. Там 12-битное знаковое число, содержащее целую (8 бит) и дробную (4 бита) части выровнено вправо, что в принципе, верно, а запятая получается между 3 и 4 битом младшего байта. Если сдвинуть значение влево на 4 бита, запятая придется аккурат между старшим и младшим байтом. Надо смотреть, как удобней считать будет.
Re: Как перевести код (DS18B20)
Добавлено: Вт янв 18, 2011 23:58:39
stas00n
Re: Как перевести код (DS18B20)
Добавлено: Ср янв 19, 2011 00:05:15
Tom91
Дык, "откидывать" надо младшие биты младшего байта, а вы откинули старшие, которые имеют наибольший вес. Там 12-битное знаковое число, содержащее целую (8 бит) и дробную (4 бита) части выровнено вправо, что в принципе, верно, а запятая получается между 3 и 4 битом младшего байта. Если сдвинуть значение влево на 4 бита, запятая придется аккурат между старшим и младшим байтом. Надо смотреть, как удобней считать будет.
Вот именно что число 12 битное, а выгоняем из него 16 битное, тоесть:
SSSS SXXX XXXX XXXX - исходное число (16бит), откинул старшую тетраду:
SXXX XXXX X
XXX - сама температура (12бит), откинул 0,1,2 биты :
S XXXX XXXX - температура (9бит)
Или я что-то не так понял?
+125'C 0000 0111 1101 0000
+25.0625'C 0000 0001 1001 0001
-55'C 1111 1100 1001 0000
Re: Как перевести код (DS18B20)
Добавлено: Ср янв 19, 2011 00:22:54
stas00n
В принципе и так можно, тогда двигать лучше на 3 бита вправо, заполняя старшие биты знаками (S). Вообще, как угодно, зависит от того, где предпочтительней запятую ставить. В любом случае, в один байт не укладываетесь, значит вычисления будут уже 16-битные..
Re: Как перевести код (DS18B20)
Добавлено: Ср янв 19, 2011 00:41:48
Tom91
Так SXXXX XXXX это сдвигаю вправо и кладу в r16 (S-учёт знака, тоесть если отриц перевожу, инверсия + 1), на выходе получаю
r18,r17,r16 - целые грудусы, но как быть с дробными, к тому же приращение при 9 битах 0,5"С Тоесть если всё правильно понимаю после запятой 0 или 5
Как реализовать такой алгорит
Re: Как перевести код (DS18B20)
Добавлено: Ср янв 19, 2011 01:34:20
stas00n
Выровняйте, как я в начале рекомендовал сдвигом влево на 4 бита, младшие биты заполнить нулями, получится старший байт - целая часть, младший - дробная, запятая посередине; если старший бит целой части (15-й) равен единице, то бишь число отрицательно, берем модуль. Целую часть преобразуем вышеописанной процедурой, дробную еще проще - смотрим на старший бит дробной части (7-й), если он равен 0, то десятичная цифра после запятой 0, иначе - 5. Вообще, веса разрядов дробной части располагаются (слева направо) так: 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, - суть так же как и целой части, - следующий (влево) вдвое больше предыдущего, поэтому оперировать числами с фиксированной запятой можно так же как целыми.