ADC with Atmega328

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I'm stuck with a problem and I can not figure out why it can not work.

I setup a interrupt that will start with a Timer1 Compare A Handler.
Every time the interrupt is started it is the meaning that it reads the value on 1 of the ADC pins. But noting is happening.

What should happen is the next:
I tied a 10K potentiometer to ADC0 and a LED to PD6 and PD7. When the Voltage on ADC0 is under 2V5 or above 1 of the LEDs is turned on.
But this is not working.

I tied AVcc to Vcc and put Aref with 100nF to GND.
I included the Main file PT544.asm and the interrupt.
By the way I set the prescaler to 128 because in the futher I want to use a 16Mhz crystal.

Maybe one of you can help me to find out what I'm doing wrong.

Thanks,
Patrick

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't seen a multi-channel ADC approach on an AVR like you are doing. But it mostly seems OK.

adcon6:		cpi 	temp0,$07
			brne	adc1
			lds 	temp0,ADCH
			mov 	V3,temp0
			ldi 	temp0,$60
			sts 	ADMUX,temp0
			ldi		temp0,$C7
			sts 	ADCSRA,temp0
adc1:		rjmp	adcon1
			ret

When channel 7 is done, you will never leave the ISR.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see what you are meaning :oops: :
code code...
adc1: rjmp adcon1
ret

And it must be like this:
code code...
ret
adc1: rjmp adcon1

But is there a other way of multi-channel ADC?

I changed it but it is still not working, it's probably something small that I don't see.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is code from one of my apps in C, for multi-channel with a look-up table for the correspondence between conversion index and the ADMUX channel setting. It saves the 10-bit ADC result into an array of result values. The look-up table is created and stored in EEPROM but I use an SRAM copy in operation because I don't want to do EEPROM operations in an ISR.

//
//	ANALOG INPUTS
//	=============
//
// (index into adc_raw[])
#define	ADC_ACID			0
#define	ADC_TACID			1
#define	ADC_CAUSTIC			2
#define	ADC_TCAUS			3
#define	ADC_RINSE			4
#define	ADC_TRINS			5

// 3 concentration + 3 temp. comp.
#define	ADC_CHANNELS		6

// (index int [ee_]ad_table)
#define	CHANNEL_ACID			0
#define	CHANNEL_TACID			1
#define	CHANNEL_CAUSTIC			2
#define	CHANNEL_TCAUS			3
#define	CHANNEL_RINSE			6
#define	CHANNEL_TRINS			7
...
// A/D
register unsigned char	ad_index;				// which channel in ee_ad_channel[] is being
												// converted/stored

unsigned char			ad_channel[ADC_CHANNELS];
unsigned char			ad_count;				// A/D conversion on this many entries
												//	of ee_ad_channel, starting at index 0

//
//	"Raw" ADC samples parked here by the ISR
//
unsigned int			adc_raw[ADC_CHANNELS];
...
// ================================
// Table of A/D channels to convert
// ================================
eeprom	unsigned char	ee_ad_channel[ADC_CHANNELS] =
{
CHANNEL_ACID,
CHANNEL_TACID,
CHANNEL_CAUSTIC,
CHANNEL_TCAUS,
CHANNEL_RINSE,
CHANNEL_TRINS
};

eeprom	unsigned char	ee_ad_count		= ADC_CHANNELS;	// A/D conversion on this many entries
												//	of ee_ad_channel, starting at index 0
...
// Set up the ADC cycling.
ad_count = ee_ad_count;					// number of channels of conversion
for (looper = 0; looper < ad_count; looper++)
	{
	ad_channel[looper] = ee_ad_channel[looper];
	}

...

//
// **************************************************************************
// *
// *		A D C _ I S R
// *
// **************************************************************************
//
// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
// Read the AD conversion result
	adc_raw[ad_index] = ADCW;

// Select next ADC input
	if (++ad_index >= ad_count)
		{
		ad_index=0;
		}

	ADMUX = ADC_VREF_TYPE + ad_channel[ad_index];

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

}

And some compiler-generated ASM code...

 
_ad_channel:
	.BYTE 0x6
_ad_count:
	.BYTE 0x1

_adc_raw:
	.BYTE 0xC
...
;
;
;//
;// **************************************************************************
;// *
;// *		A D C _ I S R
;// *
;// **************************************************************************
;//
;// ADC interrupt service routine
;// with auto input scanning
;interrupt [ADC_INT] void adc_isr(void)
;  059B {
_adc_isr:
	ST   -Y,R26
	ST   -Y,R27
	ST   -Y,R30
	ST   -Y,R31
	IN   R30,SREG
	ST   -Y,R30
;  059C // Read the AD conversion result
;  059D 	adc_raw[ad_index] = ADCW;
	MOV  R30,R4
	LDI  R26,LOW(_adc_raw)
	LDI  R27,HIGH(_adc_raw)
	LDI  R31,0
	LSL  R30
	ROL  R31
	ADD  R26,R30
	ADC  R27,R31
	LDS  R30,120
	LDS  R31,120+1
	ST   X+,R30
	ST   X,R31
;  059E 
;  059F // Select next ADC input
;  05A0 	if (++ad_index >= ad_count)
	INC  R4
	LDS  R30,_ad_count
	CP   R4,R30
	BRLO _0x5B
;  05A1 		{
;  05A2 		ad_index=0;
	CLR  R4
;  05A3 		}
;  05A4 
;  05A5 	ADMUX = ADC_VREF_TYPE + ad_channel[ad_index];
_0x5B:
	MOV  R30,R4
	LDI  R31,0
	SUBI R30,LOW(-_ad_channel)
	SBCI R31,HIGH(-_ad_channel)
	LD   R30,Z
	SUBI R30,-LOW(64)
	STS  124,R30
;  05A6 
;  05A7 // Start the AD conversion
;  05A8 	ADCSRA |= (1 << ADSC);
	LDS  R30,122
	ORI  R30,0x40
	STS  122,R30
;  05A9 
;  05AA }
	LD   R30,Y+
	OUT  SREG,R30
	LD   R31,Y+
	LD   R30,Y+
	LD   R27,Y+
	LD   R26,Y+
	RETI

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.