Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: atmega16 взаимное влияние каналов ацп друг на друга
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Lost_Viking
Здравствуйте, не могу никак понять что у меня происходит.
Задача такая: замер сигнала на 4х ногах ацп, пропуск каждого сигнала через "экспоненциальное скользящее среднее" с маленьким коэффициентом, и последовательная передача этих четырех значений в манчестер-коде с разделителем. Реализовано все на if(){}, так что код заифан чуть более, чем почти полностью.
Для передачи бита используются два манбита. В свою очередь... Короче, передача работает отлично. Вопрос в АЦП.
Когда я снимаю сигнал с переменного резистора, и подаю его на PA0, а другие каналы АЦП висят в воздухе - на них каким-то чудесным образом передается сигнал, приложенный к PA0. Я прекрасно понимаю, что многое насасывается из воздуха, да и 50Гц вполне может быть там... Стоит мне коснуться осциллографом к одному из висячих в воздухе каналов, так там сразу наводка уходит, и остается значение около 7-12 в относительных величинах (от 0 до 255). Если посчитать, то... напряжение опоры у меня примерно 5 вольт. Допустим, что 4.5 вольта. Не важно. 5000/256 = 19.5мВ на инкремент. То есть постоянно присутствует примерно 200 мВ. Если я замыкаю на землю висячий канал, то там все равно эти ~200мВ. Переменным резистором, в принципе, я тоже замыкаю на землю канал, когда выкручиваю его до упора.
Но это еще не все! Теперь подключаю другой переменный резистор к PA1. PA2 и PA3 вообще убираю из программы. То есть переключение идет между двумя каналами PA0 и PA1. Выставляю на PA1 максимум, кручу PA0, и смотрю при этом что на выходе фильтра (m1 эксп.скользящее среднее) порта PA1. По идее значения должны не меняться, т.к. каналы влиять друг на друга не должны. Да и по осциллографу питание не просаживается. Однако, если я уменьшаю сигнал на PA0 до 0, то у меня уменьшаются выходные значения PA1 на 10 значений (от 0 до 255).

Чего я только не пробовал: делал паузы, пропуск первых двух преобразований после переключения, изменял внутреннюю частоту АЦП, частоту семплов, отключал от схемы все что можно отключить. Однако влияние это оставалось, а на осциллографе никаких изменений, кроме небольшого изменения шума. Если брать Aref , которое у меня равно VCC=~5вольт, и разведенно по правилам, то шум этот имеет амплитуду ~10-20мВ относительно этих 5 вольт, а может и меньше. 10-20 мВ - это не 200мВ. И не видно, что шум этот меняется по амплитуде. В него просто добавляется какая-то фигня, которая по амплитуде не меняет шум.

Я использую отладочную плату, купленную по ebay. На AREF и AVCC конденсатор с обозначением 104 (100нФ или 10нФ?), на AVCC питание через дроссель с неизвестным номиналом. Порты все отключены от схемы, и сопротивление между ними более 200кОм. Питание от 7805. Вроде бы все по уму сделано.

Прошу помощи.
CODE

#include <avr/io.h>
#include <avr/interrupt.h>
#define bits 8
#define buffsize 4
#define freq_timer 1000
#define syncsize 8
#define syncperiod 4
#define shift 23
unsigned char c=256-(125000/freq_timer);
unsigned char sync[syncsize]={1,0,0,0,0,0,0,1};
unsigned char buff[buffsize]={0,0,0,0};
unsigned char a[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned char m=0,st,st=0,count=0,prevbit=0,prevnbit=0,prevnbyte=0,nbyte=0,nbit=0;
long m0=0,m1=0,m2=0,m3=0,adcdata=0,g=0;
long k=625;


ISR(TIMER0_OVF_vect)
{
TCNT0=c;
ADCSRA|=0x40;
if ((ADCSRA & 0x10)==0){};
ADCSRA|=0x10;
adcdata=ADCH;
adcdata<<=shift;

//здесь считаем среднее и переключаем каналы
if (count<=17)
{

m0+=(adcdata-m0)/k;
if (count==17)
{
ADMUX=0x61;
ADCH=0;
buff[0]=m0>>shift;


}
}
if ((count>17)&&(count<=35))
{


m1=m1 + (adcdata-m1)/k;
if (count==35)
{
ADMUX=0x60;
ADCH=0;
buff[1]=m1>>shift;


}
}
/*if ((count>35)&&(count<=53))
{

m2=m2 + (adcdata-m2)/k;
if (count==53)
{
ADMUX=0x63;
ADCH=0;
buff[2]=m2>>shift;

}
}
if (count>=54)
{

m3=m3 + (adcdata-m3)/k;
if (count==71)
{
ADMUX=0x60;
ADCH=0;
buff[3]=m3>>shift;

}
}
//здесь реализована передача.
if (count<(syncperiod*16))
{
if (count&0x01)
{

if(buff[prevnbyte]&a[prevnbit])
{
PORTC=0;
}
else
{
PORTC=1;
}
}
else
{

if(buff[nbyte]&a[nbit])
{
PORTC=1;

}
else
{
PORTC=0;

}
prevnbit=nbit;
prevnbyte=nbyte;
nbit++;
if(nbit==8)
{

nbit=0;
nbyte++;
if (nbyte==buffsize){nbyte=0;}

}
}
}
if (count>=(syncperiod*16))
{
PORTC=sync[st];
st++;
if (st==(syncsize)){st=0;}
}



count++;
if (count==((syncperiod*16)+syncsize)){count=0;};


}






int main(void)
{
PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0xFF;

PORTD=0x00;
DDRD=0xFF;

PORTB=0x00;
DDRB=0xFF;

ASSR=0x00;
TCCR0=0x03;
TCNT0=c;
OCR0=0x00;

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


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

TIMSK=0x01;

ACSR=0x80;
SFIOR=0x00;

ADCSRA=0x86;
ADMUX=0x60;

SPCR=0x00;

TWCR=0x00;

sei();

while (1)
{





}}
neiver
Просто у АЦП на входе есть так называемый "sample and hold" кондкнсатор ёмкостью несколько пикофарад. При переключении каналов АЦП к этому конденсатору через мультиплексор подключаются разные входы. И если вход никуда не подключен, или сопротивление источника сигнала велико, то этот конденсатор не успевает перезарядится. Из-за этого естественно есть некоторое взаимное влияние каналов друг не друга, и чем больше частота переключение каналов и выше выходное сопротивление источников сигнала, тем оно выше.
Lost_Viking
блин! в прошлый раз вроде бы делал пропуск первых двух семплов после переключения. видать что-то не то делал, или не на том канале. сейчас внимательно в коде порылся, и сделал нормальный пропуск. опытным путем получил, что пропускать надо первые два семпла. как и написано в мануалах и на форумах. всем спасибо!

p.s. еще 4 ифа sm.gif))))

кстати, если не трудно - можно более подробней о ситуации, когда концы болтаются в воздухе?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.