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

Помогите разобратся с АЦП.

 

Пишу программу для считывания уровня напряжения с переменного резистора (от 0 до 5 В).

Микроконтроллер: ATmega16 работает на частоте 16МГц. Вход A0. Разрядность АЦП: 10бит. Считывание одинарное (но вызывается регулярно)

 

Программа работает, но при считывании уровня 0В выдает в ADCW не 0, а 15. При этом с верхним уровнем никаких проблем нет (1023).

 

Код программы ниже. Написано в WinAVR последней версии (на нижних версиях результат тот же).

Бьюсь неделю, не могу понять. Пробовал прошивать другой контроллер (8535) - результат тот же :07:

 

#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
    #define  F_CPU 16000000UL
#include <util/delay.h>

volatile unsigned int ADC_w = 0;

int
segment_decoder(int num, int point)
{
int result = 0x3F;
    switch(num)
    {
        case 0: result = 0x3F;
        break;
        case 1: result = 0x06;
        break;
        case 2: result = 0x5B;
        break;
        case 3: result = 0x4F;
        break;
        case 4: result = 0x66;
        break;
        case 5: result = 0x6D;
        break;
        case 6: result = 0x7D;
        break;
        case 7: result = 0x07;
        break;
        case 8: result = 0x7F;
        break;
        case 9: result = 0x6F;
        break;
        default: result = 0x3F;
        break;
    }

if(point!=0)
    {
    result = (result | 0x80);
    }

  return result;
}

ISR(ADC_vect)
{
    ADC_w = ADCW;//ADCL;
}


int main(void)
{
_delay_ms(2);

DDRA = 0x00;
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;

PORTA= 0xFF;
PORTB= 0x00;
PORTC= 0x00;
PORTD= 0x00;


SREG    |= _BV(7);

   ADCSRA |= (1<<ADPS0); 
   ADCSRA |= (1<<ADPS1); 
   ADCSRA |= (1<<ADPS2); 
    
ADMUX  = 0x40;
    
   ADCSRA |= (1 << ADATE);
   ADCSRA |= (1<<ADIE);
   ADCSRA |= (1<<ADEN);

sei();
   while(1)
    {
    ADCSRA |= (1<<ADSC);
    while(ADCSRA & 0x40)
    {
            PORTB = segment_decoder( (ADC_w/1000)%10, 0);
        PORTD = 2;
    _delay_us(10);
        PORTD = 0;
            PORTB = segment_decoder( (ADC_w/100)%10, 0);
        PORTD = 4;
    _delay_us(10);
        PORTD = 0;
            PORTB = segment_decoder( (ADC_w/10)%10, 1);
        PORTD = 8;
    _delay_us(10);
        PORTD = 0;
            PORTB = segment_decoder( ADC_w%10, 0);
        PORTD = 16;
    _delay_us(10);
    }
    };

return 0;
}

Изменено пользователем azure

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


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

там 0 может и не быть, потому как шумы, эффекты квантования и т.п., а вы уверены, что это не ошибка в отображении значения? для проверки можно поставить светодиод на какой нибудь вывод порта и зажигать его если значение АЦП будет равно константе (15 в вашем случае).

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


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

Я результат преобразования вывожу на семисегментные индикаторы, ручку переменоого резистора кручю - вижу колеблится или нет (внешних помех никаких нет, результат стоит стабильно).

 

Общался я с человеком, который подобное писал на Асемблере для МК 8535 - говорит, что у него начинает с 0 до 1023. Свою программу я прогнал и в 8535 - у меня с 15 до 1023.

 

Что интересно, при моделировании в VMLab - показывает от 0 до 1023. Вот и думаю что не так: или код, или программатор, или ??

 

Не могу никак добится результата :(

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


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

Я результат преобразования вывожу на семисегментные индикаторы, ручку переменоого резистора кручю - вижу колеблится или нет (внешних помех никаких нет, результат стоит стабильно).

 

Общался я с человеком, который подобное писал на Асемблере для МК 8535 - говорит, что у него начинает с 0 до 1023. Свою программу я прогнал и в 8535 - у меня с 15 до 1023.

 

Что интересно, при моделировании в VMLab - показывает от 0 до 1023. Вот и думаю что не так: или код, или программатор, или ??

 

Не могу никак добится результата :(

А если закоротить вход на землю?

Скорее всего просто нету нуля у этого резистора

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


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

Я при работе с АЦП использую только 8 старших бита, так как если посмотреть в даташит, то оговаривается, что ошибка может быть в младших 2 битах.

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


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

А если так попробовать - ADC_w=0;

и пустить разок

 

Если покажет 0, то надо померить напряжение между входом и аналоговой землёй, только нормальным цифровым вольтметром

 

Блин, это ж AVR...

Вообще по правилам на время преобразования рекомендуется гасить ядро, а по прерыванию от АЦП просыпаться и обрабатывать результат.

Хотя 15 это не 1-2 разряда, а все 4. Вряд ли в этом дело.

Изменено пользователем MrYuran

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


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

А если закоротить вход на землю?

Скорее всего просто нету нуля у этого резистора

+1

Только нуля нет именно в момент измерения. Я с таким сталкивался, правда не на АВР. АЦП в момент измерения ток вытекающий начинает генерировать. А когда не мереет ничо из него не течёт. А переменный резистор с большим сопротивлением?

 

Нет не в этом дело. У вас в программе ошибка. Ну остаток от деления на 1000 вы на индикатор вывели. А при выводе след. разряда надо из значения АЦП предыдущий * 1000 ( 100, 10) вычетесть, а уж потом остаток считать. Как же у вас вообще всё это работало? Там ведь начиная со следующего после 1го ненулевого разряда ошибка получалась! Попробуйте под отладчиком таким способом 222 (десятичное) вывести - 200 на индикаторе получите.

Или я что-то там с вашей программой не понял?

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


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

Если результат стабильно 15, то скорее всего что то с программой, попробуйте сделать как я говорил со светодиодом или как выше предложили, попробуйте просто в вашу переменную ADC_w записывать "0" - что будет на экране?

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


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

8 бит мне мало, нудно мерять с точностью 0.1%

 

при штучном ADC_w=0, ноль показывается, ща буду мерять напряжения

 

Или я что-то там с вашей программой не понял?

 

Что-то не понялм :)

Там такие опреации:

 

(ADC_w/100)%10

ADC_w = 222 следует: ADC_w/100 = 22.2 делее %10 получаем то что после точки 2

ADC_w = 321 следует: ADC_w/100 = 32.1 делее %10 получаем то что после точки 1

 

Ранее использовал floor()

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


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

Нужно "засыпать" на время преобразования.

Можно попробовать измерить внутренний 0-(MUX=1111).

Что-то с землями.

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


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

Внутренней землей я задавался - был 0 (меряло верно) - что странно :).

 

Нашол я AVR120: Characterization and Calibration of the ADC on AVR, где рассказывается о возможных искажениях (ошибках) измерений.

 

То-есть: АЦП меряет от 15 до 1023. Делаю смещени (математикой): получаю от 0 до 1008. Умножаю на коэффициент 1024/1009: получаю прямую от 0 до 1023.

 

При практике: идеальное измерение значений подаваемых на вход. Подавалось на вход напряжение 5В, 2.5В. 0.25В и 0В - проверка мультиметром показало АЦП с этой корекцией меряет верно.

Эксперементировал на 2 ATmega16 и одной 8535.

 

Может это и не верное, но пока решение.

 

Очень и искрене благодарен всем за отклик на помощь. СПС!

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


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

Кстати. А что за контроллер?

 

В новых контроллерах вы можете прочитать 0 и Vcc питание. Это позволяет найти смещение и смасштабировать.

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


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

На Меге16 у меня работают сразу три АЦП без выключения ядра 10 бит и все нормально от 0 до 1023.Единственное что подается сигнал с ОУ.

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


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

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

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

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

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

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

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

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

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

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