Atmega 328p: Problem med ADC:er

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Castello
Inlägg: 127
Blev medlem: 9 februari 2014, 13:40:08
Ort: Göteborg

Atmega 328p: Problem med ADC:er

Inlägg av Castello »

Hej!

Jag håller på att bygga en elektronisk konstlast (http://elektronikforumet.com/forum/view ... =3&t=81981) och har tänkt visa inställd och faktisk utström på en LCD. Jag har fått displayen att fungera men när jag vill läsa värden från olika kanaler verkar det som att den alltid väljer samma input/kanal. Jag vill ju läsa ifrån kanal 4 respektive 5, till exempel, men oavsett vilken pin jag lägger en spänning på så skrivs denna på båda raderna.

Finns det något känt problem/trick med mikrokontrollern eller är har jag gjort något fel i koden? :S

Jag tackar ödmjukast för all hjälp!

Bild finns här:
(Lite rolig bild, man ser hur en av siffrorna håller på att skrivas om i bildögonblicket)

*******************Koden börjar här***************************

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.c"

#define F_CPU 8000000 //Clock frequency
#define Isetpin 4
#define Ioutpin 5

/******Prototypes******/

unsigned int ReadADC(char ch);
void initADC(void);

/******Main code*******/

int main(void)
{
double Iset;
double Iout;
int Isetint;
int Ioutint;

initLcd();
initADC();

lstring(1, "Iset = ");
lstring(2, "Iout = ");

setAddress(0x0C);
writeLcd(1, 'A');
setAddress(0x4C);
writeLcd(1, 'A');

for(;;){

//Check set current

Iset = 5000*(double)ReadADC(Isetpin)/1024;
Isetint = (unsigned int)Iset;


setAddress(0x07);
writeNumber(Isetint/1000);
writeLcd(1, '.');
writeNumber((Isetint%1000)/100);
writeNumber((Isetint%100)/10);

_delay_ms(10);


//Check output current

Iout = 5000*(double)ReadADC(Ioutpin)/1024;
Ioutint = (unsigned int)Iout;


setAddress(0x47);
writeNumber(Ioutint/1000);
writeLcd(1, '.');
writeNumber((Ioutint%1000)/100);
writeNumber((Ioutint%100)/10);

_delay_ms(10);
}
return 0; /* never reached */
}

void initADC()
{
ADMUX=(1<<REFS0)|(1<<REFS1); // Voltage reference: Aref=AVcc;
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Prescaler div factor =128
}

unsigned int ReadADC(char ch) //extremeelectronics.co.in
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;

//Start Single conversion
ADCSRA|=(1<<ADSC);

//Wait for conversion to complete
while(!(ADCSRA & (1<<ADIF)));

//Clear ADIF by writing one to it
ADCSRA|=(1<<ADIF);

_delay_ms(5);

return(ADC);

}

*******************Koden slutar här***************************
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Atmega 328p: Problem med ADC:er

Inlägg av sodjan »

> *******************Koden börjar här***************************
> *******************Koden slutar här***************************

Om du använder "code" taggarna så behövs inte de där två raderna
och dessutom blir koden (mer) läsbar och bara det är är ju bra... :-)
snigelen
Inlägg: 815
Blev medlem: 8 maj 2009, 11:02:14
Ort: Lund

Re: Atmega 328p: Problem med ADC:er

Inlägg av snigelen »

Kod: Markera allt

    ADMUX|=ch;
Du kan inte bara använda bitvis eller, du måste nollställa först. Eller använd bara tilldelning. Typ

Kod: Markera allt

    ADMUX = (1<<REFS0)|(1<<REFS1) | ch;
Användarvisningsbild
Castello
Inlägg: 127
Blev medlem: 9 februari 2014, 13:40:08
Ort: Göteborg

Re: Atmega 328p: Problem med ADC:er

Inlägg av Castello »

Tack för tipset Sodjan! Jag bifogar senaste kodversionen nedan, för läsbarhet om inte annat. Och tack till Snigelen för tipset.

Jag har nu ett problem med att ADC:erna "spiller över" på varann. Om jag lägger 5V på en ingång hamnar ca 0.23V på den andra, vilket gäller åt båda hållen! Mycket konstigt.

- Jag har testat att sätta inputregistren för ADC:n till GND respektive Vref, och det funkar kanon (visar exakt vad tänker mig).
- När mikron är spänningslös har jag öppen krets mellan ADC-ingångarna men när den är igång har jag ca 44 Ohm mellan ADC-ingångarna.

Det låter som att det finns någon intern krets jag missat att styra upp, eller?

Kod: Markera allt

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.c"

#define F_CPU			8000000 //Clock frequency
#define Isetpin			4
#define Ioutpin			5

/******Prototypes******/

unsigned int ReadADC(char ch);
void initADC(void);

/******Main code*******/

int main(void)
{
	double Iset;
	double Iout;
	int Isetint;
	int Ioutint;
	
	initLcd();
	initADC();
		
	lstring(1, "Iset = ");
	lstring(2, "Iout = ");
	
	setAddress(0x0C);
	writeLcd(1, 'A');
	setAddress(0x4C);
	writeLcd(1, 'A');
	
    for(;;){
    
	//Check set current
		
		Iset = 5000*(double)ReadADC(0b00001111)/1024;		
		Isetint = (unsigned int)Iset;
		

		setAddress(0x07);
		writeNumber(Isetint/1000);
		writeLcd(1, '.');
		writeNumber((Isetint%1000)/100);
		writeNumber((Isetint%100)/10);

		_delay_ms(10);

	//Check output current
		
		Iout = 5000*(double)ReadADC(0b00001110)/1024;		
		Ioutint = (unsigned int)Iout;
		
		
		setAddress(0x47);
		writeNumber(Ioutint/1000);
		writeLcd(1, '.');
		writeNumber((Ioutint%1000)/100);
		writeNumber((Ioutint%100)/10);
		
		_delay_ms(10);
    }
    return 0;   /* never reached */
}

void initADC()
{
	ADMUX=(1<<REFS0)|(1<<REFS1);                       // Voltage reference: Internal reference 1.1V;
	ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Enable ADC and set prescaler div factor =128
}

unsigned int ReadADC(char ch) //extremeelectronics.co.in
{
	//Select ADC Channel
	
	ch = ch&0b00001111;
	ADMUX = (1<<REFS0)|(1<<REFS1) | ch;

	//Start Single conversion
	ADCSRA|=(1<<ADSC);
	
	//Wait for conversion to complete
	while(!(ADCSRA & (1<<ADIF)));

	//Clear ADIF by writing one to it
	ADCSRA|=(1<<ADIF);
		
	return(ADC);

}
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Atmega 328p: Problem med ADC:er

Inlägg av sodjan »

Notera att du efter bytet av "kanal" behöver en tid för att ingångssteget
ska hinna stabilisera sig innan man startar omvandlingen. Det ska
framgå av databladet och jag vet inte vad det kallas på en AVR...
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Re: Atmega 328p: Problem med ADC:er

Inlägg av Wedge »

@Sodjan: Nej. Hårdvaran tar hand om sample-and-hold-timingen, 1.5 ADC-cykler. Det ingår i omvandlingstiden på 13 cykler. Inget man behöver tänka på.
Kapitel 24.3, figur 24.5 i databladet.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Atmega 328p: Problem med ADC:er

Inlägg av sodjan »

Tja, tänka och tänka... :-) Beroende på hur den externa kopplingen
ser ut (speciellt impedansen på det man ska mäta) så kanske man
behöver tänka på det i alla fall. Hur som helst...

> Om jag lägger 5V på en ingång hamnar ca 0.23V på den andra, vilket gäller åt båda hållen! Mycket konstigt.

Kan du beskriva närmare hur du får det? Blir det 0.23V direkt efter byte av kanal?
Ligger dessa 0.23V kvar även vid flera omvandlingar utan kanalbyte? Vad är det
anslutet till kanalen som ger 0.23V? Ingenting? (Det kan i sig vara ett problem...)

Databladet säger inget specifikt om någon "discharge" av S/M kondingen, så det
är lite oklart vad man bör förvänta sig vid omvandling från en oansluten pinne...

> När mikron är spänningslös har jag öppen krets mellan ADC-ingångarna men när den är igång har
> jag ca 44 Ohm mellan ADC-ingångarna.

Jag vet inte om det är relevant att ohm mäta på det där sättet. Ohm mätningen i sig
påför spänning på pinnarna och det kan ge alla möjliga underliga fenomen.
larsson
Inlägg: 188
Blev medlem: 9 juni 2007, 16:49:21
Ort: Göteborg

Re: Atmega 328p: Problem med ADC:er

Inlägg av larsson »

Det låter inte normalt att spänningar läcker över mellan kanalerna. Får anta att du dubbel- och trippelkollat din koppling.

Gör du enstaka läsning efter kanalväxling eller flera läsningar på pinnen innan du ger upp? Kanske är det bara den första avläsningen som är off? Har hänt mig, men minns inte om det var på denna kontrollern.

Här är ett långskott: Kolla avsnitt 24.9.5 i databladet, testa att koppla bort den "digitala moden" från pinnarna genom att fylla i DIDR-registret.
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Re: Atmega 328p: Problem med ADC:er

Inlägg av Wedge »

Lägger man en spänning över en kondensator (MUX=kanal 1) så ligger den kvar när man INTE kopplar in något (MUX=kanal 2). Det är det som händer i ADC:n.
Jag testade att läsa två ADC-kanaler. Samtliga ADC-pinnar oanslutna, och alla kanaler visar "samma" digitalbrus. Jordar EN ingång, och båda mätvärden blir noll.
Det är helt meningslöst att titta på mätvärden från öppna ingångar.
Användarvisningsbild
Castello
Inlägg: 127
Blev medlem: 9 februari 2014, 13:40:08
Ort: Göteborg

Re: Atmega 328p: Problem med ADC:er

Inlägg av Castello »

Hej,

Jag har testat att sätta DIDR0 = 0b00110000, dvs stänga av digital input disable för pin 4 och 5. Det funkade tyvärr inte. Jag får alltså stabila värden på displayen, de ligger kvar många mätningar/konverteringar i följd. Möjligtvis åker minst signifikanta siffran upp eller ner ibland pga brus. Jag har heller inga problem med värden som "driver", allt sker mycket distinkt.

När båda ingångarna hänger löst visar båda 0V, alltid.

Vad som händer mer specifikt är alltså följande:

När jag mäter spänningsmatningen på 5V med en kanal (och den andra är flytande) hamnar ca 0.22V på den flytande kanalen, detta händer oavsett vilken spänning som mäter spänningsmatningen. (Det är kanske osmart att låta ingångar ligga flytande, men jag ser inte omedelbart varför ingången på en kanal ska påverka den andra, trodde de var isolerade från varann?)

När jag lägger 5V på en ingång och jordar den andra ser det bra ut, dvs jag får 5V resp 0V. Jag får också 5V på båda om jag lägger båda på spänningsmatningen, och samma sak med jord.

Men håll i er för nu blir det spännande: :!:

Jag har kopplat två st 10k motstånd i serie över spänningsbussen för att kunna mäta en spänning på ca 2.5V (det stämmer, har dubbelkollat med multimeter).

Jag borde alltså få 2.5V, men det får jag inte! Jag får istället 0.22V PÅ KANALEN JAG MÄTER MED. Och vad som är märkligare: Om jag lägger 5V på en kanal och samtidigt försöker mäta 2.5V med den andra så får jag 5V respektive 0.44V! Det vill säga, spänningarna adderas på ingången, 0.22+0.22V.

Jag är förbryllad, vad kan vara fel?
larsson
Inlägg: 188
Blev medlem: 9 juni 2007, 16:49:21
Ort: Göteborg

Re: Atmega 328p: Problem med ADC:er

Inlägg av larsson »

När jag mäter spänningsmatningen på 5V med en kanal (och den andra är flytande) hamnar ca 0.22V på den flytande kanalen, detta händer oavsett vilken spänning som mäter spänningsmatningen. (Det är kanske osmart att låta ingångar ligga flytande, men jag ser inte omedelbart varför ingången på en kanal ska påverka den andra, trodde de var isolerade från varann?)
Jo, men som Wedge skrev, du kan inte *mäta* på en ingång som hänger i luften. Pinnarna är nog isolerade från varandra men de delar alla på samma kondensator. Muxen är bara en "vridomkopplare" som kopplar önskad pinne till ena änden av den ensamma kondingen. Är inget anslutet till den pinnen så lämnar kondingen den spänning som den "råkar ha", kanske rester från grannpinnens spänning. Det "läcker" nog alltså inte per se, utan du laddar upp kondensatorn, byter till en flytande ingångspinne och den laddning som återstår visas som ett konstigt mätvärde.

Med flytande ingång vet kondingen inte riktigt vad den ska ta sig till. Anslut alltså pinnen nånstans innan du mäter.


Edit: Ditt sista stycke lät som ett kul mysterium, kan du inte posta en skiss på hur du kopplat det? Kan vara kul att återskapa det om det regnar i helgen :)
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43178
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Atmega 328p: Problem med ADC:er

Inlägg av sodjan »

Posta också en enkel "reproducer", alltså en enkel kod som
visar det fenomen som beskrivs. Det gör att det dels går att
kolla koden direkt och den som vill försöka återskapa "felet"
har också något att utgå ifrån.
Användarvisningsbild
Castello
Inlägg: 127
Blev medlem: 9 februari 2014, 13:40:08
Ort: Göteborg

Re: Atmega 328p: Problem med ADC:er

Inlägg av Castello »

Hej igen!

Jag har gjort en skiss över hur jag har kopplat upp det hela. Den finns på följande länk:

Jag började skriva en förklaring i ord men insåg att det skulle bli omöjligt att få överblick så jag sammanfattade beteendet i en sanningstabell istället. Notera att varje värde i varje ruta är kopplat till vad motsvarande ingång är inkopplad till, vilket visas med pedagogiska, dubbelriktade pilar.

Som ni säger så blir det lite kajko om man lämnar pinnen flytande, men jag har ändå tagit med det caset i tabellen. Om man tycker att det är dumt och/eller ointressant så kan man bara bortse från tabellens översta rad. Det som är intressant är rutorna längst ner till höger i tabellen. Där syns att om båda pinnanrna kopplas till 2.5V så får båda pinnarna 0.11V men om en kopplas till 2.5V och en till GND så får en pinne hela den spänningen. Det sker alltså någon form av spänningsdelning mellan ingångarna. :humm:

Koden är samma som innan, har lagt till den nedan.

Kod: Markera allt

#include <avr/io.h>
#include <util/delay.h>
#include "lcd.c"

#define F_CPU			8000000 //Clock frequency
#define Isetpin			4
#define Ioutpin			5

/******Prototypes******/

unsigned int ReadADC(char ch);
void initADC(void);

/******Main code*******/

int main(void)
{
	double Iset;
	double Iout;
	int Isetint;
	int Ioutint;
	
	initLcd();
	initADC();
		
	lstring(1, "Iset = ");
	lstring(2, "Iout = ");
	
	setAddress(0x0C);
	writeLcd(1, 'A');
	setAddress(0x4C);
	writeLcd(1, 'A');
	
	DIDR0 = 0b00110000;
	
    for(;;){
    
	//Check set current
		
		Iset = 5000*(double)ReadADC(0b00000100)/1024; //Ch 4
		Isetint = (unsigned int)Iset;
		

		setAddress(0x07);
		writeNumber(Isetint/1000);
		writeLcd(1, '.');
		writeNumber((Isetint%1000)/100);
		writeNumber((Isetint%100)/10);

		_delay_ms(10);

	//Check output current
		
		Iout = 5000*(double)ReadADC(0b00000101)/1024; //Ch 5
		Ioutint = (unsigned int)Iout;
		
		
		setAddress(0x47);
		writeNumber(Ioutint/1000);
		writeLcd(1, '.');
		writeNumber((Ioutint%1000)/100);
		writeNumber((Ioutint%100)/10);
		
		_delay_ms(10);
    }
    return 0;   /* never reached */
}

void initADC()
{
//	ADMUX=(1<<REFS0)|(1<<REFS1);                       // Voltage reference: Internal reference 1.1V;
//	_delay_ms(10);
	ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Enable ADC and set prescaler div factor =128
	_delay_ms(5);
}

unsigned int ReadADC(char ch) //extremeelectronics.co.in
{
	//Select ADC Channel
	
	ch = ch&0b00001111;
	ADMUX = (1<<REFS0)|(1<<REFS1) | ch;

	//Start Single conversion
	ADCSRA|=(1<<ADSC);
	
	//Wait for conversion to complete
	while(!(ADCSRA & (1<<ADIF)));

	//Clear ADIF by writing one to it
	ADCSRA|=(1<<ADIF);
		
	return(ADC);

Castor
Inlägg: 1989
Blev medlem: 24 mars 2012, 13:03:49

Re: Atmega 328p: Problem med ADC:er

Inlägg av Castor »

Har du möjlighet att testa med annan processor, den kan ju ha blivit skadad.
larsson
Inlägg: 188
Blev medlem: 9 juni 2007, 16:49:21
Ort: Göteborg

Re: Atmega 328p: Problem med ADC:er

Inlägg av larsson »

Prydlig kod och skiss. Ser inga konstigheter i schemat.

I koden verkar det som du sätter ref-spänning till 1,1 Volt? De signaler du mäter måste vara lägre än referensspänningen. Använd AVCC som referensspänning istället så kan du mäta upp till 5V. Du ändrar alltså inte kopplingen utan sätter bara biten REFS1 till 0.

Inte säkert att det är hela svaret på gåtan, får återkomma om jag hittar min labbplatta och kan koppla upp det. Att för säkerhets skull kolla med ett annat exemplar av ATMegan som Castor skrev är ingen dum idé.
Skriv svar