Clueless and Curious
Clueless and Curious

Reputation: 11

Attiny85 "analogRead()" with ADC problems

So I'm messing around with the Attiny85, my project requires what in Arduino would have been analogRead, I have learned a bit about ADC in this great instructable. I'm having problem though with what seems like to be the reading aspect. As I can't use serial monitor I've tried setting up a simple circuit in which bellow a certain threshold read from a spring vibration sensor (something similar to this) a red led will lit and above the threshold a blue led will lit.

I've considered this being a circuit problem and while still very much possible I do think it is software related, due to the fact that when I eliminate the sensor from the equation and connect what would have been the two ends of the sensor together (essentially connecting straight 5v to ADC2). I've also flipped the leds operation (red above threshold and blue below) and it worked as expected considering the sensor value doesn't seem to register (i.e only the led of zero activity is lit no matter how aggressively I shock the sensor or connecting straight to the 5v).
There were some odd behaviors though:

  1. whenever I bump the sensor trying to replace the led that is being lit, the led that is already lit sort of fade away ever so slightly and back the other led though is off.
  2. The weirdest encounter I've met which unfortunately I can't recreate was that the leds switched when I bumped the sensor but never flipped back when the vibration should have settled down back again. Then disconnecting the microcontroller and connecting it again would retrieve the original led and again would work for flipping to the high. This made me think maybe im not clearing some register that is needed to read again, but if so it shouldn't have flipped in the first place either as it must do some reading of low values before I bump it.

The circuit is similar to this (the 5v and GND are delivered via an Arduino Uno and the sensor is not the same)

My code:

#include <Arduino.h>
#include <avr/io.h>

#define redLed PB0
#define blueLed PB1
int analogData;

void adc_setup(){
  ADMUX |= (1 << REFS1);  // setup ADC reference voltage to internal 1.1v
  
                          // To use ADC2 ADMUX[0:3] needs to be 0010
  ADMUX |= (1 << MUX1);   // Sets ADC2 as analog input channel


  ADMUX |= (1 << ADLAR);  // Left Adjust the ADCH and ADCL registers. Left adjusting means that the two least significant bits will be stored in ADCL that way reading only ADCH will give a rather accurate 8 bit representation
  ADCSRA |= (1 << ADEN);  // enables the ADC
  
                          // It's recommended for some reason I haven't tried to understand to set the adc clock to 125kHz, as our general clock speed is 1mHz, we need to set ADC clock prescaler to divide by 8
  ADCSRA |= (1 << ADPS1); // To achieve 8 time division ADPS(ADC Prescaler Select) bits in the ADCSRA are set to 011
  ADCSRA |= (1 << ADPS0); // ^^
}

int main()
{ 
    DDRB |=(1 << blueLed);          // Set the blueLed as Output
    DDRB |=(1 << redLed);           // Set the redLed as Output

  adc_setup();
  while (1)
  {
    ADCSRA |= (1 << ADSC);          // Start conversion
    analogData = ADCH;              // Store data in analogData variable
    if(analogData<160){             // Value was choosen randomly
        PORTB |=(1 << redLed);      // turn on red led
        PORTB &= ~(1 << blueLed);   // turn off blue led
    }
    else{
      PORTB |=(1 << blueLed);  
      PORTB &= ~(1 << redLed);
    }
    delay(300);
  }
  
}

Edit: I've deleted the delay command and the code sort of works now, it definitely registers the analog input it does switch between the led and then back again real quick but I guess that's a matter of the threshold being abstract, my application of the sensor doesn't really need that sorted out (at least quite now so I'll consider this a win).

Thanks for those that tried to help and raised interesting points, this is my first ever question on Stackoverflow and it was much more pleasant than anticipated.

Upvotes: 1

Views: 1356

Answers (1)

KIIV
KIIV

Reputation: 3739

You'll have to wait until ADSC flag gets cleared after the conversion is finished (or you can check Interrupt flag + clear it by writting log 1, or use ISR handler which clears it automatically)

Another issue might be reading ADCH only. There is a temp register for ADCH which gets updated when ADCL is readed (for atomicity), and now it might never get updated. However if you just read 16b ADC register instead, the compiler makes sure it'll work properly. 16b register access APPNOTE

Upvotes: 1

Related Questions