Skaf 0 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Делаю цифровой вольтметр на AVR ATmega16. Пишу на Си (WinAVR). После аналого-цифрового преобразования у меня есть переменная int ADCD с 10-и битным результатом. Мне надо показать число на экране. Сначала хочу перевести в вольты. float data = ADCD * 0.0049; где 0.0049 получилось от 5 / 1024 Потом надо отобразить на индикаторе. У меня есть функция, которая принимает на вход номер знакоместа на LCD и цифру от 0 до 9. Пытаюсь отобразить целую часть DrawLCD((int)data, 1); А на экране получаю 0. Какой-то косяк с умножением на 0.0049 видимо... Подскажите пожалуйста как решить проблему? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vishv 0 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба По моему Вы перемудрили. Я обычно делаю такие операции в целочисленной арифметике - чуть сложнее писать, зато гарантировано, да и выполняется не в пример быстрее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Skaf 0 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Напишите пожалуйста, как вы делаете. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Herz 6 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Если нужно более-менее точно, то источник опорного напряжения для АЦП нужно взять стабильный, желательно готовый на напряжение, например, 4.096В. Будет удобно. А так можно для простоты результат умножить на 5, затем последовательно делить: на 1000 - получим первую цифру (вольты), остаток - на 100 (десятые доли вольт), остаток - на 10 (десятки милливольт), и остаток - милливольты. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Потом надо отобразить на индикаторе. У меня есть функция, которая принимает на вход номер знакоместа на LCD и цифру от 0 до 9. Пытаюсь отобразить целую часть DrawLCD((int)data, 1); А на экране получаю 0. Какой-то косяк с умножением на 0.0049 видимо... Подскажите пожалуйста как решить проблему? Наверное цифра - это '0', '1', '2'...'9'? Тогда надо DrawLCD((int)data + '0', 1); ЗЫ. Ну и, на всякий случай - на входе АЦП больше вольта? :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vishv 0 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Если я правильно догадался у вас опорное напряжение 5 В. В этом случае: int16_t raschet(void) { int16_t b_uff;//выходное значение в милливольтах b_uff=((int32_t)ADCD*5000)/1024; return b_uff; } Ну и далее: uint8_t mas_ADC [4];//содержит цифры для вывода void out (int16_t in) { uint16_t d; d=in&0x7fff; mas_ADC[0]=d/1000+0x30; d=d%1000; mas_ADC[1]=d/100+0x30; d=d%100; mas_ADC[2]=d/10+0x30; mas_ADC[3]=d%10; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Топикстартеру. Как уже выше заметили для вашего случая плавающая арифметика не нужна совсем. Разрешение вашего АЦП хуже 1мВ, поэтому результат измерения можно представлять именно в миллиВольтах с помощью двухбайтового целого числа. Причем деление на 1024 заменяется сдвигом вправо на 10 бит. unsigned int data = (unsigned int)((unsigned long)ADCD*5000UL)>>10UL); //содержимое data - напряжение в мВ: число от 0мВ до 4995мВ По второй части вопроса. Потом надо отобразить на индикаторе. У меня есть функция, которая принимает на вход номер знакоместа на LCD и цифру от 0 до 9.Цифра от 0 до 9 в бинарном виде принимается или в виде ASCII-кода? Если в виде ASCII-кода, то нужно к каждому числу результата BCD-преобразования добавлять ASCII-код нуля '0' = 0x30. Для преобразования в BCD-формат делением (или боже вас упаси! функцией sprintf) пользоваться вовсе не обязательно. Можно последовательно вычитать степени числа десять (т.е. 10000, 1000, 100, 10), считая количество этих вычитаний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 7 августа, 2009 Опубликовано 7 августа, 2009 · Жалоба Осталось только объяснить, откуда вдруг взялось BCD :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xgcyo 0 12 августа, 2009 Опубликовано 12 августа, 2009 · Жалоба Флоатами получается очень медленно и громоздко. Для своего вольтметра все делал делением и вычислением остатка на интегерах. Вывод на три 7-сегментных светодиодных индикатора. Могу сурсы дать. Существует какой-либо быстрый алгоритм разложения 16-битного целого на десятичные составляющие, с шифтами например? На аттини26 делением и остатками при 1МГц у меня эта операция занимает 200мкс. Интересно, подсчетом вычитаний 1000, 100, 10 быстрей будет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ukpyr 0 12 августа, 2009 Опубликовано 12 августа, 2009 · Жалоба в BCD можно конверировать или разложением на степени 10 (отнимать 10000, 1000, 100, 10, 1 и считать количество) или сдвигами+BCD коррекцией : http://www.avr-asm-tutorial.net/avr_en/calc/CONVERSION.html http://www.avr-asm-tutorial.net/avr_en/cal...RT.html#bin2bcd http://www.msclub.ce.cctpu.edu.ru/MCU_MPU/AVR/BINBCD.htm http://www.msclub.ce.cctpu.edu.ru/MCU_MPU/AVR/BINBCDapp1.htm http://www.msclub.ce.cctpu.edu.ru/MCU_MPU/AVR/BINBCDapp3.htm Что будет быстрее - зависит от конвертируемых чисел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 12 августа, 2009 Опубликовано 12 августа, 2009 · Жалоба в BCD можно конверировать или разложением на степени 10 (отнимать 10000, 1000, 100, 10, 1 и считать количество) или сдвигами+BCD коррекцией : Или приведением числа 0000...9999 к формату 0...1 с фиксированной точкой (в 16 бит укладывается дробная часть, а целая равна 0) и домножением на 10 для получения очередной цифры. При наличии аппаратного умножителя так вообще пожалуй наибыстрейший способ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться