#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
// photoresistor's "gamma" and "rl10" attributes
const float GAMMA = 0.7;
const float RL10 = 50;
// Servo Motor Pins Setup
#define SERVO_DDR DDRB
#define SERVO_PORT PORTB
#define SERVO_PIN PB1
// Servo Motor Channels
#define ADC_CH1 0
#define ADC_CH2 1
// Arrays to Store Raw ADC data and processed ADC data
volatile uint16_t adc_RAW[2] = {0, 0};
volatile float lux_value[2] = {0, 0};
// Function to Initialize PWM
void init_ADC(void) {
ADMUX |= (1 << REFS0); // AVcc with external capacitor at AREF pin
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128
ADCSRA |= (1 << ADATE); // Enable ADC auto trigger
ADCSRA |= (1 << ADIE); // Enable ADC interrupt
ADCSRA |= (1 << ADEN); // Enable ADC
ADCSRA |= (1 << ADSC); // Start first conversion
}
ISR(ADC_vect) {
static uint8_t channel = ADC_CH1;
adc_RAW[channel] = ADC;
lux_value[channel] = ProcessPhotoResistor(adc_RAW[channel]);
channel = (channel == ADC_CH1) ? ADC_CH2 : ADC_CH1;
ADMUX = (ADMUX & 0xF8) | channel;
ADCSRA |= (1 << ADSC); // Start next conversion
}
ISR(INT1_vect) // ISR for Blue Button
{
// Turn Servo Towards right when Blue Button is pressed
// And turn ON Blue LED
PORTD |= (1<<PD6);
_delay_ms(100);
PORTD &= ~(1<<PD6);
_delay_ms(100);
OCR1A -= 30;
}
ISR(INT0_vect) // ISR for Green button
{
// Turn Servo Towards right when Green Button is pressed
// And turn ON Green LED
PORTD |= (1<<PD5);
_delay_ms(100);
PORTD &= ~(1<<PD5);
_delay_ms(100);
OCR1A += 30;
}
void init_PWM(void) {
TCCR1A |= (1 << COM1A1) | (1 << WGM11); // Non-inverting mode, Fast PWM mode
TCCR1B |= (1 << WGM13) | (1 << WGM12) | (1 << CS11); // Fast PWM mode, Prescaler 8
ICR1 = 39999; // Top value for 50Hz PWM frequency
OCR1A = 3000; // Initial servo position
SERVO_DDR |= (1 << SERVO_PIN); // Set servo pin as output
}
float ProcessPhotoResistor(uint16_t RAW_ADC)
{
// Convert the analog value into lux value:
int analogValue = RAW_ADC;
float voltage = analogValue / 1024. * 5;
float resistance = 2000 * voltage / (1 - voltage / 5);
float lux = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
return lux;
}
int main(void) {
// Port Setup and Initialization
//set PD2 (INT0) and PD3 (INT1) as inputs with pull-up resistors
DDRD &= ~((1 << PD2) & ~(1 << PD3) & ~(1 << PD4) );
PORTD |= (1 << PD2) | (1 << PD3);
DDRD |= (1 << PD5) | (1 << PD6) | (1 << PD7);
// set interrupt types: Low Level
EICRA = 0x00;//(1 << ISC00) | (1 << ISC11) | (1 << ISC01) | (1 << ISC10);
// enable external interrupts INT0 and INT1
EIMSK |= (1 << INT0) | (1 << INT1);
sei(); // Enable global interrupts
init_ADC(); // Initialize ADC
init_PWM(); // Initialize PWM
while (1) {
if(PIND & (1<<PD4)) // if ON run everything
{
PORTD |= (1<<PD7); // Turn ON red LED
}
else
{
PORTD &= ~(1<<PD7); // Turn OFF red LED
uint16_t diff = (lux_value[ADC_CH1] > lux_value[ADC_CH2]) ? (lux_value[ADC_CH1] - lux_value[ADC_CH2]) : (lux_value[ADC_CH2] - lux_value[ADC_CH1]);
if (diff > 50) { // Threshold to ignore small light differences
if (lux_value[ADC_CH1] > lux_value[ADC_CH2]) {
OCR1A -= 10;
} else {
OCR1A += 10;
}
if (OCR1A < 1000) {
OCR1A = 1000;
} else if (OCR1A > 5000) {
OCR1A = 5000;
}
_delay_ms(10); // Short delay to allow servo to move
}
}
}
return 0;
}