# LDR in AVR

This project was an exploration into how to use the ADC and the fast PWM signaling on the AVR architecture. Although there is nothing revolutionary going on in this project, I wanted to start building a library of Embedded C AVR functions. Firstly, to get better at embedded systems work because I find it really fun and satisfying to create pieces of technology that people use in everyday life and I want to build up to more ambitious projects using the modern tools of the trade (32-bit ARM Microcontrollers, USB and other complex serial protocols, etc.) For now, 8-bit AVR with a simple sensor input (in the form of a photoresistor) and feedback LED which has a brightness controlled by a pulse width modulated signal from the microcontroller.

The microcontroller of choice was an ATtiny261 for the simple reason that I found a lot of these while dumpster diving near the robotics lab. It still worked perfectly fine and programmed with out issue with help from my Atmel ICE and ISP Breadboard Adapter (check that out here!).

Moving onto the firmware, I break all my AVR programs into 6 sections for each file.

• Macros
• Includes
• Globals
• Functions
• Interrupt Service Routines
• Main

##### Macros
/******************** Macros *****************************/
#ifndef F_CPU
#define F_CPU 1000000UL //Set clock speed to 1MHz
#endif
#define BIT_SET(byte, bit) (byte & (1<<bit))


Starting with macros, I only specified the CPU clock speed which is mandatory to ensure any delay statements work properly (Need to have some reference to count the ticks). With no external clock for simplicity and no concern about temperature change for this demo, I set the AVR Fuse bits to use the internal 8MHz RC Oscillator with 65ms delay and divide the clock by 8. This is generally inadvisable since the internal oscillator is susceptible to significant clock skew and jitter as there are environmental/temperature changes around your microcontroller. However, you can improve the performance by increasing the start-up delay to 65ms and dividing the clock.

##### Includes
/******************** Includes ***************************/
#include <avr/io.h>


In the includes section, I include the avr/io.h library to get all the macros relating to the input/output pins of this microcontroller.

##### Globals

No globals were needed for this project, so the section is left empty.

##### Functions
/******************** Functions **************************/
//Initialize the PWM Output for OCR1B, set the max value in OCR1B
void PWM_init(){
//Enable PWM Output B
TCCR1A = (1<<PWM1B) | (0<<COM1B1) | (1<<COM1B0);
//Enable Clock Divider/64
TCCR1B = (0<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10);
//Enable Fast PWM Mode
TCCR1D = (0<<WGM11)|(0<<WGM10);
//Use PLL Clock for PWM Generator
PLLCSR |= (1<<PCKE)|(1<<PLLE);
//Max PWM value possible set though OCR1C
OCR1C = 0xFF;
}

//Use VCC for the analog reference voltage, left justify result, only use ADC0 for input
//Enable ADC, use for single conversion mode, clk/8 prescaler
}

//Pass bit in to get request measurement
//Wait for conversion
//Return the left justified result
}


In the function section I have functions for the initialization for the fast PWM signaling, 10-bit ADC, and obtaining an ADC value. I will cover these functions in more detail as they are encountered in main.

##### Interrupt Service Routines

No interrupt service routines as they are not used in this program.

##### Main
/******************** Main *******************************/
int main(void)
{
/* Initialize the I/O Registers */
/*				-I/O Map-
*	Reactive LED: PB3 (OC1B Timer Counter) (1: Output)
*  Light Dependent Voltage: PA0 (0: Input)
*/
DDRB |= (1<<PB3);
//Set the default values for outputs to zero and inputs to have pull-up resistors
PORTB |= (0<<PB3);

/* Initialize the timer/counter0 (Fast PWM Mode) */
PWM_init();

/* Storage for the LDR value from the ADC */
uint16_t LDRvalue = 0;

/* State machine loop */
while(1)
{
//Get the LDR value
//Based on the LDR value set the brightness of the LED though OCR1B
if(LDRvalue < 100){
OCR1B = 255;
}
else if(LDRvalue >= 100 && LDRvalue < 290){
OCR1B = 180;
}
else if(LDRvalue >= 290 && LDRvalue < 400){
OCR1B = 120;
}
else if(LDRvalue >= 400 && LDRvalue < 800){
OCR1B = 80;
}
else if(LDRvalue >= 800 && LDRvalue < 1000){
OCR1B = 20;
}
else{
OCR1B = 10;
}
}
}


In the main section there is the main entry point of the program. I start by initializing the outputs I have selected for the LED. PB3 was chosen because that this the timer output for Timer/Counter 1B which is the PWM timer that I will be configuring in the following function call PWM_init().
In PWM_init() I modify the timer/counter 1 control registers to enable output B, enable this timer/counter for its fast PWM option, set the PWM frequency to F_PLL/64. Below that is a more interesting register that enables a Phase Locked Loop that can be used to drive Timer/Counter 1 on the ATtiny261! Even though I am running the chip at 1MHz already I utilize the PLL to send a 1MHz signal to the timer. The PLL generates a 64MHz signal that I clock down to divide by 64 as previously mentioned. After the PWM registers are configured the OCR1C register controls max value for timer/counter 1, so I initialize it with the max value of 0xFF (8-bit max value).