07 Experiment
Creating different colors using RGB LEDs
Source and description
http://sincgrid.in/avr-tutorials/avr-tutorial-experiment-7/
http://sincgrid.in/avr-tutorials/avr-tutorial-experiment-7/
#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++;}
}