Experiment 7
Creating different colors using RGB LEDs
Objective – Use the switch to select the LED (from RGB led) and then the potentiometer to set the intensity of that LED and thus create your own color from amongst 16million colors
Pre-Requisites – AVR Motherboard, Mini USB cable, 12V DC Adapter, Software Setup (as described in introduction)
Theory – Intensity variation for a single LED was discussed in experiment 6. In the given experiment combination of red, green and blue color is produced, selection of the color is based on switch input. Each color has 256 steps, the combination of these 3 LED leads to 256 x 256 x 256 colors or 16 millions colors.
The ATmega328 has 6 PWM outputs, 2 are located on each timer/counter. The AVR’s PWM timer is capable of running in 3 different modes: Fast PWM, Phase Corrected PWM and Phase and Frequency Phase Corrected PWM.
Use navigation switch to navigate between led. Use right Navi switch to move from R -> G ->B->R and use left Navi switch to move from R ->B->G->R. Thereafter use pot to change the duty cycle of respective led. When navigating to next led, last led will maintain its state.
Connections/Schematic
Connections :-
Nano <–> MV1
D9(PB1)<–>red led
D10(PB2)<–>green led
D11(PB3)<–>blue led
A0 <–> POT
A1 <–> NAV
Code
#include <avr/io.h>
#include <avr/io.h>
#include <stdlib.h> //for itoa
#include <stdlib.h> //for abs()
#define F_CPU 16000000UL
#include <util/delay.h>
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
#define Down_button 0
#define Left_button 770
#define Right_button 510
#define Center_button 680
#define Up_button 820
#define button_margin 20
#define rled_pwm_threshold OCR1A
#define gled_pwm_threshold OCR1B
#define bled_pwm_threshold OCR2A
char buffer[16]; //Output of the itoa function
uint16_t led_selected=0;
/************************************************************************/
/*
0 -> no led is selected
1 -> r selected
2 -> g selected
3 -> b selected
*/
/************************************************************************/
void adc_init(void); //Function to initialize/configure the ADC
uint16_t read_adc(uint8_t channel); //Function to read an arbitrary analog channel/pin
void USART_init(void); //Function to initialize and configure the USART/serial
void USART_send( unsigned char data); //Function that sends a char over the serial port
void USART_putstring(char* StringPtr); //Function that sends a string over the serial port
void send_data_to_pc(uint32_t dump);
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
uint16_t naviButton (uint16_t raw ){
if(raw < 1020){ //one of navigation button is pressed
if(abs(raw-Up_button)<button_margin){ // up button is pressed
return 1;
}else if(abs(raw-Left_button)<button_margin){
return 2;
}else if(abs(raw-Down_button)<button_margin){
return 3;
}else if(abs(raw-Right_button)<button_margin){
return 4;
}else if(abs(raw-Center_button)<button_margin){
return 5;
}
}
return 0;
}
void selectNextLed(uint8_t buttonSelected){
if(buttonSelected==2){ //left circular shift 0 1 2 3
if(led_selected==0){
led_selected=3;
}else if(led_selected==1){
led_selected=3;
}else if(led_selected==2){
led_selected=1;
}else if(led_selected==3){
led_selected=2;
}
}else if(buttonSelected==4){//right circular shift 0 1 2 3
if(led_selected==0){
led_selected=1;
}else if(led_selected==1){
led_selected=2;
}else if(led_selected==2){
led_selected=3;
}else if(led_selected==3){
led_selected=1;
}
}
}
int main(void){
adc_init(); //Setup the ADC
USART_init(); //Setup the USART
//PWM1&2 initialisation
TCCR1A = 0b10100001;// set PWM mode for PB1 and PB2
TCCR1B = 0b00000010; //set clock:8 prescaler
//PWM3 initialisation
TCCR2A = 0b10000001; // set PWM mode for PB3
TCCR2B = 0b00000010; //set clock:8 prescaler
DDRB = 0xFF; //set portB as output
while(1){
volatile uint16_t navi_adc= read_adc(1);
/*
*
Idle -> 0
up button -> 1
Down button -> 3
Left button -> 2
Right button -> 4
center button -> 5
*/
uint8_t button_pressed =naviButton(navi_adc);
_delay_ms(200);
if(button_pressed!=0){//either left or right button is pressed
if((button_pressed == 2) | (button_pressed == 4) ){
selectNextLed(button_pressed);
}
if(button_pressed == 5){ //center button is pressed
led_selected=0; //reset selected led
}
}
if(led_selected!=0){ //atleast a led is selected
uint16_t pot_value = map(read_adc(0),100,1023,0,255); // adc give 10bit converting it to 8 bit
//100 is selected because of pot offset
send_data_to_pc(pot_value);
if(led_selected ==1){
rled_pwm_threshold = pot_value;
}else if(led_selected ==2){
gled_pwm_threshold = pot_value;
}else if(led_selected ==3){
bled_pwm_threshold = pot_value;
}
_delay_ms(50);
}
}
return 0;
}
void send_data_to_pc(uint32_t dump){
itoa(dump, buffer, 10); //Convert the read value to an ascii string
/*char * itoa ( int value, char * str, int base );*/
USART_putstring(buffer); //Send the converted value to the terminal
USART_putstring(" "); //Some more formatting
USART_send('\r');
USART_send('\n');
}
void adc_init(void){
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //16Mhz/128 = 125Khz the ADC reference clock
ADMUX |= (1<<REFS0); //Voltage reference from Avcc (5v)
ADCSRA |= (1<<ADEN); //Turn on ADC
ADCSRA |= (1<<ADSC); //Do an initial conversion because this one is the slowest
//and to ensure that everything is up and running
}
uint16_t read_adc(uint8_t channel){
ADMUX &= 0xF0; //Clear the older channel that was read
ADMUX |= channel; //Defines the new ADC channel to be read
ADCSRA |= (1<<ADSC); //Starts a new conversion
while(ADCSRA & (1<<ADSC)); //Wait until the conversion is done
return ADCW; //Returns the ADC value of the chosen channel
}
void USART_init(void){
UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}
void USART_send( unsigned char data){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
}
void USART_putstring(char* StringPtr){
while(*StringPtr != 0x00){
USART_send(*StringPtr);
StringPtr++;}
}