Thursday, February 28, 2008

Simple Idle Mode ( Mega ) ADC Example

The first ADC control example uses the Idle sleep mode and a simple
delay loop between samples, and the use of a pointer to write to the
output array. The latter is hardly warranted in this case, but if the
output array was two-dimensional it would make sense. Note the use of sbi/cbi instructions setting bits on PORTA. This is a very good debug tool if you have access to an oscilloscope.



/******************************************************************************

Sample program to demonstrate using the Mega103 analog to digital
converter (ADC) in conjunction with the simple sleep instruction to
minimize power use.

For demonstration purposes, the high 8 bits of channel 3 (10-2) are written
to PORTB, the set of LEDs on an STK300.

Ron Kreymborg
May 2001

******************************************************************************/

#include <stdlib.h>
#include <interrupt.h>
#include <signal.h>

#define BYTE unsigned char
#define ADC_CONTROL (1<<ADEN | 1<<ADIE | 1<<ADPS2 | 1<<ADPS0)

int main(void);
void AtoDconverter(void);
void Delay(void);

static volatile int Sample[8]; // a/d converter samples
static volatile int *Pointer[8];
static volatile BYTE Index;

int main(void)
{
int i, value;

// PORTA
outp(0x00, PORTA); // all low
outp(0xff, DDRA); // all output
// PORTB
outp(0xff, PORTB); // all low
outp(0xff, DDRB); // all output
sbi(ACSR, ACD); // disable comparator
cbi(MCUCR, SM0);
cbi(MCUCR, SM1);
sbi(MCUCR, SE);

for (i=0; i<8; i++)
Pointer[i] = &Sample[i]; // initialise pointers

Delay(); // allow clocks to settle
sei(); // hello world

while (1)
{
AtoDconverter(); // take a sample
value = ~(Sample[2]>>2); // display channel 3 on the STK300
outp(value, PORTB); // set of leds
Delay();
}

return 0;
}

//---------------------------------------------------------------------
// Control the ADC for an eight channel sample using the inbuilt noise
// cancelling capability.
//
void AtoDconverter(void)
{
sbi(PORTA, 1); // for scoping

outp(ADC_CONTROL, ADCSR);
for (Index=0; Index<8; Index++)
{
sbi(PORTA, 3); // for scoping
cbi(ADCSR, ADEN); // turn off ADC
outp(Index, ADMUX); // select the channel
outp(ADC_CONTROL | 1<<ADSC, ADCSR); // turn ADC on and start conversion

// The read is done in the interrupt routine. Here we go to
// sleep in Idle mode until the conversion is done.
//
asm("sleep"::);
cbi(PORTA, 3); // for scoping
}

cbi(PORTA, 1); // for scoping
}

//---------------------------------------------------------------------
// Arbitrary inter-sample delay.
//
void Delay(void)
{
int i, j;

for (i=0; i<2000; i++)
j = i;
}

//---------------------------------------------------------------------
// ADC conversion complete interrupt
//
SIGNAL(SIG_ADC)
{
*Pointer[Index] = inp(ADCL) | inp(ADCH)<<8;
}

No comments: