Перейти к содержанию
    

Дробная арифметика

Делаю цифровой вольтметр на 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 видимо... Подскажите пожалуйста как решить проблему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По моему Вы перемудрили. Я обычно делаю такие операции в целочисленной арифметике - чуть сложнее писать, зато гарантировано, да и выполняется не в пример быстрее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если нужно более-менее точно, то источник опорного напряжения для АЦП нужно взять стабильный, желательно готовый на напряжение, например, 4.096В. Будет удобно. А так можно для простоты результат умножить на 5, затем последовательно делить: на 1000 - получим первую цифру (вольты), остаток - на 100 (десятые доли вольт), остаток - на 10 (десятки милливольт), и остаток - милливольты.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Потом надо отобразить на индикаторе. У меня есть функция, которая принимает на вход номер знакоместа на LCD и цифру от 0 до 9.

 

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

 

DrawLCD((int)data, 1);

 

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

 

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

 

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

 

ЗЫ. Ну и, на всякий случай - на входе АЦП больше вольта? :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если я правильно догадался у вас опорное напряжение 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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Топикстартеру. Как уже выше заметили для вашего случая плавающая арифметика не нужна совсем. Разрешение вашего АЦП хуже 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), считая количество этих вычитаний.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Флоатами получается очень медленно и громоздко. Для своего вольтметра все делал делением и вычислением остатка на интегерах. Вывод на три 7-сегментных светодиодных индикатора. Могу сурсы дать.

Существует какой-либо быстрый алгоритм разложения 16-битного целого на десятичные составляющие, с шифтами например? На аттини26 делением и остатками при 1МГц у меня эта операция занимает 200мкс. Интересно, подсчетом вычитаний 1000, 100, 10 быстрей будет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в 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

Что будет быстрее - зависит от конвертируемых чисел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в BCD можно конверировать или разложением на степени 10 (отнимать 10000, 1000, 100, 10, 1 и считать количество) или сдвигами+BCD коррекцией :

 

Или приведением числа 0000...9999 к формату 0...1 с фиксированной точкой (в 16 бит укладывается дробная часть, а целая равна 0) и домножением на 10 для получения очередной цифры. При наличии аппаратного умножителя так вообще пожалуй наибыстрейший способ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...