Simple ADC loop returning max values [ATMega328P] [Registers] [C] [ArduinoUno]

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

Hi! First time posting here, but it seems like a great resource when troubleshooting, so I'm sure I'll be back!

 

Unfortunately I haven't been able to get a simple ADC loop to run on my Arduino Uno. I am trying to complete part of a university assignment in which we are learning to use C code to manage the registers of the ATMega328P as part of an Arduino Uno. The goal is quite simple - get the built-in LED to light up when the ADC registers a high value (above the 511 threshold), and otherwise turn off it off. I'm using a voltage divider of a 100 Ohm and 330 Ohm resistor, from the 5V to GND pin of my Arduino. The midpoint voltage is measured through wire to the A0 Arduino pin.

 

I've been staring at the datasheet for ages, and I just don't get what's not working with the code below. I have tried running the Arduino ADC example, which works on that pin, proving that the hardware works (I suppose?). I also started writing to the Serial port in order to see what values the ADC was picking up. An LED is connected to Arduino pin 12 in order to see when the conversion is running (depending on the ADCSRA ADSC bit value), and it seems like the ADC is indeed working... 

 

EDIT: Forget to mention that it is continuously returning the maximum value of 1023, although I measure around 3.75V from my voltmeter. 

 

Thankful for any guidance! :)

 

// Write a program that continuously converts an analogue singal on ADC0. If the value exceeds 50% turn on built-in LED, else turn off LED. 

unsigned int ADCres = 0; // 16 bits of data storage for both ADCH and ADCL
unsigned int threshold = 511; //0x01FF; // Half of nominal 10-bit max value: 1024/2-1=511

void setup() {
  // For testing...
  Serial.begin(9600);
  Serial.print("\nThreshold is set to: ");
  Serial.print(threshold, BIN);
  
  // Regarding LED
  DDRB|=0x20; //Define PB5 as output
  DDRB|=0x10; //Define second LED to see if ADCSRA.ADSC is switching values. 
  
  // Regarding ADC
  PRR &= 0xFE; // Power Reduction ADC in PRR.PRADC (bit 0) must be 0 (enable ADC-functionality). Keep other values.
  
  //ADMUX = (ADMUX & 0xF0)+0b00000000; // Select input channel ADC0 (Arduino A0) with bits 0-3 as 0000. First clear bits 0-3, then add correct combo. Keep bits 4-7. See datasheet pg 317 for other pin selections.
  //ADMUX &= 0b00111111; // Set voltage reference to VCC by clearing bits 6 and 7, as 00 will set AREF (5V). Keeps other vals. 
  //ADMUX &= 0b11011111; // By default, the value is presented RIGHT ADJUSTED (here set to 0 manually as well). Left adjusted is toggled by setting ADMUX.ADLAR (bit 5) to 1. Keep other vals.
  
  ADMUX = 0b00100000;  //Final result of above operations. Difference: LEFT ADJ! 
}

void loop() {

  ADCSRA = 0b11000111; // Start a conversion (ADSC, bit 6) and enable ADC (ADEN, bit 7). Pre-scaler of 128 (bits 0-2: 111) to get more accurate results (pg. 308). Pg 319 in datasheet.

  while(ADCSRA & 0x40){
    //Wait for ADCSRA.ADSC to return to 0, signifying that the conversion is complete.
    PORTB |=0x10; // Second LED on to show conversion is still working.
  }

  delay(500);
  PORTB &=0xEF; //Second LED off to show conversion finished. Should be on for roughly half a sec. 
  
  // Conversion complete! Time to read result. 
    // ADC-value stored in ADCH (high bits, 2 MSBs) and ADCL (low bits, 8 LSBs). Make sure to read ADCL first and then ADCH, 
    // since reading ADCL will block ADC access to data registers (ie no new data can be recorded). Once ADCH is read, ADC access is re-enabled. 
  
  //ADCres = ADCL; // Start by reading low first. FOR RIGHT ADJ
  //ADCres += ((ADCH&0b00000011)<<8); // Add the high bits in their right spots by shifting left 8 bits. Mask the first 6 bits of ADCH. 
  
  ADCres = ADCL>>6; // WHEN USING LEFT ADJ
  ADCres += (ADCH<<2);
  Serial.print("\nADCres is currently: "); 
  Serial.print(ADCres, BIN);
  
  if (ADCres > threshold){
    PORTB |= 0x20; // Turn on LED
  }
  else{
    PORTB &= 0xDF; // Turn off LED
  }
  
  delay(500); //Delay to allow second LED time to be off (in order to see blinking effect). 
  
}

Mechatronics student

Last Edited: Sun. Sep 17, 2017 - 04:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You've set the external reference AREF, which likely has nothing connected to it.  You'll probably want the AVCC reference instead with REFS[1:0]=0b01.

 

Please don't use magic numbers.  Your code is hard to read, hard to debug, hard to maintain.

 

And why are you reading ADCH/L separately, and in such a convoluted manner?

ADCres = ADC;

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Ah, what a quick and helpful reply - thanks a lot! 

You were completely right about the AVCC reference voltage. Apparently the professor who walked us through the basics missed that part, and I must have misunderstood the datasheet (since I did consider changing that, and actually thought I'd tried it at some point). 

 

Reading ADC is muuuch easier than what I did - also something the professor did, and I didn't find any alternatives while reading the datasheet. Good to know for the future! 

Yeah, I suppose the "magic numbers" are really bad code - but this really isn't going to be ported to any other platforms. I did initially try to use shifting of bits, but removed it as part of my troubleshooting. 

 

Once again, thanks so much for the help - glad I wasn't too far off!

Mechatronics student

Last Edited: Sun. Sep 17, 2017 - 05:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, I suppose the "magic numbers" are really bad code - but this really isn't going to be ported to any other platforms. I did initially try to use shifting of bits, but removed it as part of my troubleshooting. 

Portability is not the only reason to use bit names.  As I said, magic numbers make your code unreadable.  To those from whom you are seeking help, and to you a month down the road.

 

Don't start bad habits now.  They will be harder to unlearn later.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]