AVR atmega 644P ADC problem

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
mrOh
EF Sponsor
Inlägg: 541
Blev medlem: 6 mars 2005, 13:54:31
Ort: Bromma

AVR atmega 644P ADC problem

Inlägg av mrOh »

Hej.

Jag har försökt slänga ihop en liten höjd och accelerations logger som ska kastas med lite olika former ur en helikopter på fredag. Det mesta har fungerat bra men AD konverteringarna strular. Det har fungerat jättebra med bara en kanal, men såfort jag kollar en i taget av de 7 jag använder så blir alla värden ungefär samma och fel. Det första värdet är ofta rätt (ca 800) men sen minskar det o stannar runt 60-70. se nedan.

Kod: Markera allt

ch: 1. Value: 816 :: ch: 2. Value: 632 :: ch: 3. Value: 496 :: ch: 4. Value: 487 :: ch: 5. Value: 352 :: ch: 6. Value: 334 :: ch: 7. Value: 327 :: 
ch: 1. Value: 319 :: ch: 2. Value: 304 :: ch: 3. Value: 287 :: ch: 4. Value: 287 :: ch: 5. Value: 286 :: ch: 6. Value: 255 :: ch: 7. Value: 255 :: 
ch: 1. Value: 255 :: ch: 2. Value: 252 :: ch: 3. Value: 231 :: ch: 4. Value: 224 :: ch: 5. Value: 224 :: ch: 6. Value: 224 :: ch: 7. Value: 199 :: 
ch: 1. Value: 192 :: ch: 2. Value: 192 :: ch: 3. Value: 192 :: ch: 4. Value: 176 :: ch: 5. Value: 167 :: ch: 6. Value: 167 :: ch: 7. Value: 167 :: 
ch: 1. Value: 152 :: ch: 2. Value: 143 :: ch: 3. Value: 152 :: ch: 4. Value: 152 :: ch: 5. Value: 127 :: ch: 6. Value: 127 :: ch: 7. Value: 127 :: 
ch: 1. Value: 127 :: ch: 2. Value: 113 :: ch: 3. Value: 112 :: ch: 4. Value: 120 :: ch: 5. Value: 113 :: ch: 6. Value: 99 :: ch: 7. Value: 103 :: 
ch: 1. Value: 112 :: ch: 2. Value: 103 :: ch: 3. Value: 96 :: ch: 4. Value: 97 :: ch: 5. Value: 103 :: ch: 6. Value: 88 :: ch: 7. Value: 88 :: 
ch: 1. Value: 96 :: ch: 2. Value: 96 :: ch: 3. Value: 79 :: ch: 4. Value: 88 :: ch: 5. Value: 96 :: ch: 6. Value: 79 :: ch: 7. Value: 79 :: 
ch: 1. Value: 92 :: ch: 2. Value: 92 :: ch: 3. Value: 71 :: ch: 4. Value: 79 :: ch: 5. Value: 88 :: ch: 6. Value: 71 :: ch: 7. Value: 71 :: 
ch: 1. Value: 88 :: ch: 2. Value: 81 :: ch: 3. Value: 71 :: ch: 4. Value: 79 :: ch: 5. Value: 88 :: ch: 6. Value: 71 :: ch: 7. Value: 71 :: 
ch: 1. Value: 79 :: ch: 2. Value: 79 :: ch: 3. Value: 63 :: ch: 4. Value: 71 :: ch: 5. Value: 79 :: ch: 6. Value: 63 :: ch: 7. Value: 67 :: 
ch: 1. Value: 79 :: ch: 2. Value: 71 :: ch: 3. Value: 63 :: ch: 4. Value: 71 :: ch: 5. Value: 79 :: ch: 6. Value: 63 :: ch: 7. Value: 67 :: 
[/size]

Specs. ATMega644P, drivs på 3.3V. AREF avkopplad mot GND med 0u1F. AVCC är LC kopplad mot VCC 10uH och 0u1F . Allt enligt min tolkning av databladet.

Så vad är inkopplat:
ADC ch: 1. Trycksensor, drivs på 5V. Spänningsdelad utgång, 20k och 39k mot GND.
ADC ch: 2,3,4. Accelerometer X, Y, Z. Analoga utsignaler upp till 3.3V.
ADC ch: 5,6,7. Hänger lösa i detta läge.
UART
ISP
En switch mot PortB pin 1 som om på jordar och startar sen loggern i log läge. Är den ej på så är PortB pin1 uppdragen och den startar i utläsning/debug läge.

Ordnar schema om någon önskar.

Är det någon som har en aning om vad det kan bero på så blir jag evigt tacksam.
Se koden nedan, den är ganska hastigt ihopslängd och i många fall stulen från olika källor så jag ber om ursäkt för hur den ser ut.

Kod: Markera allt

/*	Absolute Pressure/Altimeter and Acceleration logger
	Johan Juhlén 2010.								*/

#define F_CPU 8000000// Clock Speed
#define UART_BAUD  19200

#include <avr/io.h>
#include <stdio.h> 
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <string.h>

#include "uart.h"

#define ADC_CHANNELS_USED 7
#define PIN_B1 (PINB&1)

//unsigned int EEMEM loggedData[2000];
unsigned int eemem_address = 0;

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

void inits(void);
void dataLog(void);
unsigned int readADC(uint8_t ch);

//set some timer to count seconds.
volatile char buffer[16];

ISR(TIMER1_COMPA_vect)
{
	dataLog();
}


int main(void)
{
	
	int i;
	int j = 2000;
	unsigned int input;
	inits();
	volatile char buffer[16];
	stdout = &mystdout;
	
	for(;;)
	{
		if (!PIN_B1)
		{
			TCCR1B |= (1<<WGM12);		//CTC 
			TCCR1B |= (1<<CS12);		//Prescaler 1024
			TCCR1B |= (1<<CS10);		// -'-
			TIMSK1 |= (1<<OCIE1A);		//interrupt at compare match 

			OCR1A = 0x0F42;				//period = ~1s at 8MHz
			sei();
			while(1)
				{;}
		}
		printf("Welcome.\n\rPress 'r' to read out memory. (w to do a testwrite to memory WILL ERASE ALL CURRENT DATA!)\n\r> ");
		input = uart_get_schar();
		printf(input);
		if (tolower(input) == 'w')
		{
			printf("Write\n\r");
			unsigned int temp =830;
			while (1)
			{
				printf("temp = %u\n\r", temp);
				eeprom_write_word ((uint16_t *)eemem_address, temp);
//				sprintf(buffer, "%u", readADC(0));
				printf("%u written to EEPROM address %u.\n\r", eeprom_read_word((uint16_t *)eemem_address),eemem_address);
				_delay_ms(200);
				temp++;
				eemem_address = eemem_address +2;
				if (eemem_address > 1999)
					{
					printf("EEPROM FULL\n\r");
					while(1);
					}
			}
		}
		if (tolower(input) == 'r')
		{
			printf("Read\n\r");
			while (1)
			{
				printf("Value in EEPROM: %u\n\r", eeprom_read_word((uint16_t *)eemem_address));
				_delay_ms(200);
				eemem_address = eemem_address +2;
				if (eemem_address > 1999)
					{
					printf("Read out finished.\n\r");
					while(1);
					}
			}
		}
		if (tolower(input) == 'a')
		{
			printf("Read out ADC\n\r");
			while (1)
			{
				for (i = 0; i<ADC_CHANNELS_USED; i++)
				{ 
					printf("ch: %u. Value: %u :: ",i+1,readADC(i));
					_delay_ms(200);
				}
				printf("\n\r");
			}
		}
	}
}

void dataLog(void)
{
	unsigned int i, temp;
	for (i = 0; i<ADC_CHANNELS_USED; i++)
	{
		temp = readADC(i);
		eeprom_write_word ((uint16_t *)eemem_address, temp);
		eemem_address = eemem_address +2;
		if (eemem_address > 1999)
			{
			printf("EEPROM FULL\n\r");
			TIMSK1 &= ~(1<<OCIE1A); // Turn off timer1
			while(1);
			}
	} 
}


void inits(void)
{
	// Init PORT A
	DDRA =0x00;	// Inputs
	PORTA = 0x00;	// Not pulled up
	DDRB = 0;
	PORTB = 0xFF;
	
	// Init UART
	uart_init();
	
	// ADC init
	ADMUX |= (1 << REFS0);
	ADCSRA |= (1 << ADEN);

	return;
}

unsigned int readADC(uint8_t ch)
{
	int i;
	ADMUX |= ch;
	ADCSRA |= (1 << ADSC);
	while(ADCSRA & (1<<ADSC));
	return ADC;
}
eqlazer
Inlägg: 923
Blev medlem: 22 september 2007, 13:53:45
Ort: Göteborg

Re: AVR atmega 644P ADC problem

Inlägg av eqlazer »

Ska det vara "ADMUX |= ch;", blir det inte så att du bara ettställer bitarna hela tiden och aldrig nollar?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: AVR atmega 644P ADC problem

Inlägg av sodjan »

Behöver du inte vänta (lite) efter byte av ADC kanal ?
Användarvisningsbild
mrOh
EF Sponsor
Inlägg: 541
Blev medlem: 6 mars 2005, 13:54:31
Ort: Bromma

Re: AVR atmega 644P ADC problem

Inlägg av mrOh »

eqlazer. Jag älskar dig. ^_^)b

Stort tack, imponerande att du såg det så snabbt.

min snabbfulfix blev att börja varje ADC läsning med att nolla.

Kod: Markera allt

ADMUX &=~(0x07);
sen för säkerhetsskull köra två avläsningar varje gång, enligt databladet kan den vara lite konstig på första avläsningen efter att man ändrat mux.

Tack. Även ni som tog er tid att läsa tråden och fundera.

mvh / Johan

EDIT: Sojan, ja jag tror det, men somsagt så fullöser jag det genom att göra två läsningar. Jag har gott om tid så det stör inte funktionen.
SvenW
Inlägg: 1156
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Re: AVR atmega 644P ADC problem

Inlägg av SvenW »

Dessutom bör det vara en liten fördröjning från det att man ställer ADMUX tills dess att man startar omvandlingen, har jag för mig.

Alltså så här i readADC(uint8_t ch)

Kod: Markera allt

ADMUX = 0;
ADMUX |= ch;
_delay_us (2);
ADCSRA |= (1 << ADSC);
PS. Alltså som Sodjan redan sagt. Det går fort i tråden ibland!
Användarvisningsbild
mrOh
EF Sponsor
Inlägg: 541
Blev medlem: 6 mars 2005, 13:54:31
Ort: Bromma

Re: AVR atmega 644P ADC problem

Inlägg av mrOh »

hmm en delay är ju helt klart snyggare.

Aktuell readADC() som funkar:

Kod: Markera allt

unsigned int readADC(uint8_t ch)
{
	ADMUX &=~(0x07);
	ADMUX |= ch;
	_delay_us (2);
	ADCSRA |= (1 << ADSC);
	while(ADCSRA & (1<<ADSC))
		{;}
	return ADC;
}
sneaky
Inlägg: 1621
Blev medlem: 22 juni 2009, 18:38:42

Re: AVR atmega 644P ADC problem

Inlägg av sneaky »

Då problemet är löst så lånar jag tråden lite. Sånt här: ADMUX &=~(0x07); ger mig huvudvärk. Kan någon bena ut vad som sker där åt mig?
SvenW
Inlägg: 1156
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Re: AVR atmega 644P ADC problem

Inlägg av SvenW »

ADMUX &=~(0x07);

Det är 'AVR språk' Och - lika med - icke - sju.
Man drar ner de sista tre bitarna till noll.
Användarvisningsbild
mrOh
EF Sponsor
Inlägg: 541
Blev medlem: 6 mars 2005, 13:54:31
Ort: Bromma

Re: AVR atmega 644P ADC problem

Inlägg av mrOh »

Det är ett kortare sätt att skriva ADMUX = (ADMUX &~(0x07)); Kolla upp AND och OR mask.
Lite info finns här. http://sv.wikipedia.org/wiki/Mask_(dator)
sneaky
Inlägg: 1621
Blev medlem: 22 juni 2009, 18:38:42

Re: AVR atmega 644P ADC problem

Inlägg av sneaky »

Ah, det var negeringen av 0x07 som fick mig att se i kors. För mig känns det som ett extra onödigt steg. Själv hade jag nog skrivit masken direkt istället (och binärt). Jag föredrar fortfarande den, för mig, lite tydligare varianten &=0b111111000. Men det är väl för att jag inte har bankat in "tänket" hårt nog ännu hehe.
Användarvisningsbild
AndLi
Inlägg: 18305
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: AVR atmega 644P ADC problem

Inlägg av AndLi »

SvenW skrev:ADMUX &=~(0x07);

Det är 'AVR språk' Och - lika med - icke - sju.
Man drar ner de sista tre bitarna till noll.
Det enda som är AVR språk i den raden skulle vara ADMUX, resten är standard C

Det lär inte vara sista gången du ser en sån rad, ofta ser det ut ungefär som följer:

Kod: Markera allt

#define RED_LED 0x40    

PORTD &= ~RED_LED;  //nollar RED_LED biten
PORTD |= RED_LED; //sätter RED_LED biten
Utan ~ varianten skulle man behöva två olika defines, en för ettställa och en för nollställning. Bli mer omständigt och ökar felrisken
eqlazer
Inlägg: 923
Blev medlem: 22 september 2007, 13:53:45
Ort: Göteborg

Re: AVR atmega 644P ADC problem

Inlägg av eqlazer »

Gott att det löste sig! Om ändå mina egna ADC-problem vore såhär enkla att lösa :) (på nån Texas DSP-variant)
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Re: AVR atmega 644P ADC problem

Inlägg av vfr »

sneaky skrev:Jag föredrar fortfarande den, för mig, lite tydligare varianten &=0b111111000. Men det är väl för att jag inte har bankat in "tänket" hårt nog ännu hehe.
Det tycker jag du gör rätt i. Den visade varianten är mest bra om man redan råkar ha en konstant som motsvarar det värdet man behöver, t.ex från en inkluderingsfil eller liknande. I sådana fall kan det vara dumt att definiera samma sak på ett nytt ställe då det blir fler ställen att ändra på om man skulle göra en konstruktionsändring. D.v.s större risk för fel. Om man kan undvika, så ska man låta bli att ha samma sak definierad på flera ställen.

Så båda sätten är bra, på varsitt sätt.
Skriv svar