C/C++

Как вывести дробный результат в Proteus из скрипта на C (ATMega16)?

Есть схема фильтра нижних частот с микроконтроллером ATMega16. Есть код, который должен реализовывать оконную функцию (хоть и кривую). Я не могу вывести дробное число на осциллограф, там почему-то 0 всегда. То есть, в коде есть строка Dout = lowADC * 1.3. Как раз выводимое значение. Если я умножаю lowADC на целое число, то выводится нормально, но при умножении на дробь выводится либо 0 (если дробь меньше 1), либо вообще что-то странное. Я пробовал поменять тип данных на float у Dout и lowADC, но результата это не дало (точнее, я не знаю, как вывести результат). Что я делаю не так? И как мне вывести дробный результат Dout?

#include <avr/io.h>
#include <stdint.h>

void ADC_INIT() // конфигурирование АЦП
{
ADCSRA |= (1<<7); // Бит ADEN=1 включение АЦП
ADCSRA |= (1<<2) | (1<<1) | (1<<0); // ADPS0..2=111, предделитель - 128
ADCSRA |= (1<<5); // ADATE=1, запуск ФЦП по прерыванию
SFIOR &= -(1<<7) & (1<<6) & -(1<<0); // ADTS2..0=010 — запуск от внеш. прерывания INT0
ADMUX &= (1<<7) | (1<<6); // выбор ИОН, 11 - внутренний ИОН 1.1В
ADMUX &= (1<<0); // выбор 0-го входа мультиплексора
ADMUX &= (1<<5); // выравние рез-та по левому краю
}

int main(void)
{
ADC_INIT();
ADCSRA |= (1<<6); // запуск преобразования
DDRD = 0xFF; // режим регистра D - выход
DDRC = 0xFF; // режим регистра C - выход
uint16_t Dout = 0; // выходное значение фильтра
static const float b0 = 0.1716787f;
static const float b1 = 0.1967263f;
static const float b2 = 0.1967263f;
static const float b3 = 0.1716787f;
// линия задержки
float x3 = 0.0;
float x2 = 0.0;
float x1 = 0.0;
float x0 = 0.0;
while (1)
{
if (ADCSRA & (1<<4)) // флаг прерывания от АЦП
{
// ADCL и ADCH - верх-й и нижн.р-ры с рез-том преобразования АЦП
uint8_t lowADC = ADCL;
uint16_t Din = ADCH << 8 | lowADC;
// двигаем регистр
x3=x2;
x2=x1;
x1=x0;
x0=lowADC;
// Считаем "отфильтрованное" значение
Dout = lowADC * 1.3;//x0*b0 + x1*b1 + x2*b2 + x3*b3;
PORTD = (uint8_t)Dout; //результат записываем в р-р порта D (мл.байт)
PORTC = (uint8_t)(Dout >> 8); // в р-р порта С записываем ст. байт
ADCSRA |= (1<<4); // Бит ADIF - флаг прерывания от АЦП
}
}
}
Для вывода дробных чисел на осциллограф в Proteus из скрипта на C (ATMega16) необходимо использовать функцию printf() с форматированием числа. Для этого нужно подключить библиотеку stdio.h и настроить вывод на нужный порт.

В вашем коде можно использовать следующий код для вывода значения Dout на порт PORTD в формате с плавающей точкой с двумя знаками после запятой:

#include <stdio.h>

// ...

while (1)
{
// ...
Dout = lowADC * 1.3;
char buf[10];
sprintf(buf, "%.2f", Dout);
printf("%sn", buf);
PORTD = (uint8_t)Dout;
// ...
}


Здесь функция sprintf() форматирует значение Dout в строку buf с двумя знаками после запятой, а функция printf() выводит эту строку на стандартный вывод, который в вашем случае должен быть настроен на порт PORTD.

Обратите внимание, что для использования функции printf() необходимо настроить вывод на нужный порт. Для этого можно использовать функцию uart_init(), которая настраивает USART на нужную скорость и форматирование.
ИЕ
Иван Егоров
14 368
Лучший ответ
Приводить к uint8_t тут не нужно.
PORTD = Dout;
PORTC = Dout >> 8;

Зачем нужна переменная Din которая нигде не использована?
uint16_t Din = ADCH << 8 | lowADC;

Какой смысл в переменной float (x0-x3) хранить однобайтный lowADC?

А в каком формате принимает данные осцилограф? Т.е. как интрепретирует биты на портах D и С?

Где то читал что трогать два первых бита на PORTD не рекомендуют, ибо забиндены на последовательный порт.
..
... ...
51 416