Reputation: 11
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:
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
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