Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Дробная арифметика
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Skaf
Делаю цифровой вольтметр на 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
По моему Вы перемудрили. Я обычно делаю такие операции в целочисленной арифметике - чуть сложнее писать, зато гарантировано, да и выполняется не в пример быстрее.
Skaf
Напишите пожалуйста, как вы делаете.
Herz
Если нужно более-менее точно, то источник опорного напряжения для АЦП нужно взять стабильный, желательно готовый на напряжение, например, 4.096В. Будет удобно. А так можно для простоты результат умножить на 5, затем последовательно делить: на 1000 - получим первую цифру (вольты), остаток - на 100 (десятые доли вольт), остаток - на 10 (десятки милливольт), и остаток - милливольты.
AHTOXA
Цитата(Skaf @ Aug 7 2009, 23:59) *
Потом надо отобразить на индикаторе. У меня есть функция, которая принимает на вход номер знакоместа на LCD и цифру от 0 до 9.

Пытаюсь отобразить целую часть

DrawLCD((int)data, 1);

А на экране получаю 0. Какой-то косяк с умножением на 0.0049 видимо... Подскажите пожалуйста как решить проблему?


Наверное цифра - это '0', '1', '2'...'9'? Тогда надо

DrawLCD((int)data + '0', 1);

ЗЫ. Ну и, на всякий случай - на входе АЦП больше вольта? smile.gif
Vishv
Если я правильно догадался у вас опорное напряжение 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
Топикстартеру. Как уже выше заметили для вашего случая плавающая арифметика не нужна совсем. Разрешение вашего АЦП хуже 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
Осталось только объяснить, откуда вдруг взялось BCD smile.gif
xgcyo
Флоатами получается очень медленно и громоздко. Для своего вольтметра все делал делением и вычислением остатка на интегерах. Вывод на три 7-сегментных светодиодных индикатора. Могу сурсы дать.
Существует какой-либо быстрый алгоритм разложения 16-битного целого на десятичные составляющие, с шифтами например? На аттини26 делением и остатками при 1МГц у меня эта операция занимает 200мкс. Интересно, подсчетом вычитаний 1000, 100, 10 быстрей будет?
ukpyr
в 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
Цитата
в BCD можно конверировать или разложением на степени 10 (отнимать 10000, 1000, 100, 10, 1 и считать количество) или сдвигами+BCD коррекцией :


Или приведением числа 0000...9999 к формату 0...1 с фиксированной точкой (в 16 бит укладывается дробная часть, а целая равна 0) и домножением на 10 для получения очередной цифры. При наличии аппаратного умножителя так вообще пожалуй наибыстрейший способ.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.