Страница 1 из 1

АЦП разрешение и шумы

Добавлено: Сб окт 19, 2013 13:27:28
Aselicon
Добрый день!
Атмега8
Мучаю аналоговый датчик температуры типа LM35, характиристика 1град/10мВ.
Внутреннее опорное напряжение. АЦП 10 бит.
2560мВ/1024=2,5мВ (шаг измеряемого напряжения) получается измерить 1мВ невозможно?
В итоге работы очень хочется видеть десятые доли градуса, сейчас они скачут через 2-3 значения.
Осциллографом смотрю шумы на выходе с датчика, они составляют порядка 20мВ.
Вычитал про спец спящий режим ADC noise reduction, однако примеров использования не нашел.
Используя генератор начального кода в cvavr подсмотрел как усыплять контроллер, при этом шум уменьшается в два раза. Однако как разбудить его, непойму.
Привожу часть кода
Спойлер

Код: Выделить всё


#include <mega8.h>
#include <delay.h>

unsigned int indication,vol;
unsigned char ADC_TIMER, tic;
unsigned char  takt;
unsigned char SET;
unsigned int temp;

unsigned char i;
unsigned int j;
                                                                    
 unsigned int read_adc(void)
{
ADMUX=0xE5;;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
#asm
    in   r30,mcucr
    cbr  r30,__sm_mask
    sbr  r30,__se_bit | __sm_adc_noise_red
    out  mcucr,r30
    sleep
    cbr  r30,__se_bit
    out  mcucr,r30
#endasm
return vol;
}

interrupt [ADC_INT] void adc_isr(void)             //Прерывание по окончанию АЦП
{
read_adc();
//vol=ADCW/25; 
}

// Read the AD conversion result
// with noise canceling



interrupt [TIM0_OVF] void timer0_ovf_isr(void)
 {    
    ADC_TIMER++;
      if (ADC_TIMER==50)              // временными промежутками задаем некоторые существенные отрезки времени
         {
          ADCSRA|=0x40;             // Запускаем преобразование
          ADC_TIMER=0; 
         } 
  
 }  

// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{

 } 

void main(void)
{
PORTB=0x81;
DDRB=0x3E;

PORTC=0x00;
DDRC=0x1F;

PORTD=0x58;
DDRD=0xB9;


TCCR0=0x03;
TCNT0=0x00;

TCCR1A=0x00;
TCCR1B=0x03;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x20;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;


ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;


TIMSK=0x11;

ADMUX=0xE5;                  // Выбираем АЦП канал (PortC.5-ADC5)
ADCSRA=0x8F;                 // Настройка АЦП 

eeptoflash();
 #asm("sei")
while (1)
      {

      }
}
Считаю что первым шагом нужно заставить контроллер нормально работать с засыпанием, чтобы побороть шумы, а вторым уже думать как программно повысить разрешение, брать среднее из выборок или еще чтото.

Re: АЦП разрешение и шумы

Добавлено: Сб окт 19, 2013 14:58:12
Flasher
Усиль сигнал операционником.

Re: АЦП разрешение и шумы

Добавлено: Сб окт 19, 2013 15:11:30
Aselicon
затратно, хоть и максимальное значение с датчика будет 1,5В. Интересует шумодав в первую очередь, а во вторую возможно оверсемплинг

Re: АЦП разрешение и шумы

Добавлено: Сб окт 19, 2013 16:27:29
uk8amk

Код: Выделить всё

unsigned int read_adc(void)
{
ADMUX=0xE5;;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
#asm
    in   r30,mcucr
    cbr  r30,__sm_mask
    sbr  r30,__se_bit | __sm_adc_noise_red
    out  mcucr,r30
    sleep
    cbr  r30,__se_bit
    out  mcucr,r30
#endasm
return adc_data;
}

interrupt [ADC_INT] void adc_isr(void)//Прерывание по окончанию АЦП
{
adc_data=ADCW; 
}
 

void main(void)
{
...
...
#asm("sei")
while (1)
      {
	disable_tims_and_irqs();//запретить все таймеры и внешн прерывания 
	//чтобы проц не проснулся когда идёт преобразование
	result = read_adc();
	do_something_with_result( result );//делать что-то с результатом
      }
}

Re: АЦП разрешение и шумы

Добавлено: Сб окт 19, 2013 17:24:58
Aselicon
[quote="uk8amk"]
Понял свою проблему, чтение пытался произвести в прерывании в итоге все засыпало беспробудно.
Переделал правильно, однако тк вывод идет на 7сег индикатор, видны подергивания во время засыпания. Осциллограф показывает периодическое уменьшение шумов :))

В итоге решил проблему очень в лоб:

Код: Выделить всё

interrupt [ADC_INT] void adc_isr(void)             //Прерывание по окончанию АЦП
{
z++;
ADCvol[z]=ADCW/25;
zz=ADCvol[z]+zz;
if (z==255) {vol=zz/255; z=0; zz=0;}
}
Появилась недостающая дискретность, работает восхитительно. В мире стало больше на одну улыбку :))

Re: АЦП разрешение и шумы

Добавлено: Сб окт 19, 2013 19:43:50
uk8amk
однако тк вывод идет на 7сег индикатор, видны подергивания во время засыпания.
1) время АЦ преобразования невелико, поэтому не стоит чрезмерно задирать частоты регенерации дисплея. 100-200Гц обычно достаточно для большинства случаев.
2) попытайтесь синхронизировать прерывание регенерации с запуском АЦП. Например, в процедуре прерывания производится регенерация, затем выставляется флаг. В основной программе флаг опрашивается и если надо, то запускается преобразование.
3) если событие запуска должно быть асинхронно - попытайтесь сделать некое подобие барьера синхронизации. Вроде такого:

/

Код: Выделить всё

/"асинхронное" событие по отношению к основной программе
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
	is_async = TRUE;
}

void main(void)
{
	while(1)
	{
		is_async = FALSE;
		while(is_async == FALSE);
		read_adc();
		is_async = FALSE;
		
	}
}