I've set up my Diecimila to use some IR receiver code (RC5 protocol) and the code works perfectly: I'm able to interpret the signals from my Philips remote without a hitch. The problem is that I'm trying to use the code to set the volume on my speakers but I'm having trouble generating a PWM signal.
Basically, I want to have an integer variable named volume where I can store the current volume level. Pressing "Volume Up" adds 1 to the current level and "Volume Down" subtracts 1.
However, for some reason the value of volume is never stored and just resets to zero each time it reads new data from the remote. Therefore, I can't use the variable to set a PWM value. For example, when I press "Volume Up" continuously I get this:
1
1
1
1
instead of this:
1
2
3
4
How can I make this work?
I've pasted the code I'm working with below for reference:
// RC5 remote control receiver decoder.
// Tested with Philips or Philips compatible TV remotes.
// Developed by Alessandro Lambardi, 25/12/2007
// Released under Creative Commons license 2.5.
// Non-commercial use, attribution, share alike.
//
// Completely interrupt driven, no 'wait until' loops.
// When a valid code is received it is made available at
// variable data_word (main loop).
// External Arduino clock 16Mhz, hardware prescaler = 1
// Designed for AVR ATtiny24, adapted for Arduino.
//
// Program memory resources used (ATtiny24):
// 670 Program bytes circa out of 2048 (1/3 circa)
// 4 data bytes out of 128
//
// Internal hardware resources used:
// 8Bit Timer 0: reset by software as required
// PORTA B, bit 0 can be relocated together with pin
// change interrupt assignments
#define F_CPU 16000000UL // CPU clock in Hertz.
#define TMR0_PRESCALER 256UL // Provides a 62.5KHz clock
#define IR_BIT 1778UL // bit duration (us) in use for IR remote (RC5 std)
#define IR_IN 8 //IR receiver is on digital pin 8 (PORT B, bit0)
#define S_LEFT 9 // Left speaker volume
#define S_RIGHT 11 // Right speaker volume
#define TMR0_T (F_CPU/TMR0_PRESCALER*IR_BIT/1000000UL)
#define TMR0_Tmin (TMR0_T - TMR0_T/4UL)
#define TMR0_Tmax (TMR0_T + TMR0_T/4UL)
#if TMR0_Tmax > 255
#error "TMR0_Tmax too big, change TMR0 prescaler value ", (TMR0_Tmax)
#endif
// Variables that are set inside interrupt routines and watched outside
// must be volatile
volatile uint8_t tmr0_OC1A_int; // flag, signals TMR0 timeout (bad !)
volatile uint8_t no_bits; // RC5 bits counter (0..14)
volatile uint16_t ir_data_word; // if <> holds a valid RC5 bits string (good !)
void start_timer0(uint8_t cnt) {
OCR0A = cnt;
TCNT0 = 0;
tmr0_OC1A_int = 0;
TIMSK0 |= _BV(OCIE0A); // enable interrupt on OC0A match
TCCR0B |= _BV(CS02); // start timer0 with prescaler = 256
}
// Interrupt service routines
ISR(PCINT0_vect) { // signal handler for pin change interrupt
if(no_bits == 0) { // hunt for first start bit (must be == 1)
if(!digitalRead(IR_IN)){
start_timer0(TMR0_Tmax);
no_bits++;
ir_data_word = 1;
}
} else {
if(!tmr0_OC1A_int) { // not too much time,
if(TCNT0 > TMR0_Tmin) { // not too little.
// if so wait next (mid bit) interrupt edge
start_timer0(TMR0_Tmax);
no_bits++;
ir_data_word <<= 1;
if(!digitalRead(IR_IN)){
ir_data_word |= 1;
} else {
ir_data_word &= ~1;
}
}
}
}
}
ISR(TIM0_COMPA_vect) { // timer0 OC1A match interrupt handler
TCCR0B &= ~(_BV(CS02) | _BV(CS01) | _BV(CS00)); // stop timer
tmr0_OC1A_int = 1; // signal timeout
no_bits = 0; // start over with hunt for valid stream
ir_data_word = 0;
}
int volume = 0; // Initialize volume at zero
int oldvolume = 0; // Variable for restoring volume after mute
boolean mute = false; // Flag to indicate mute status
uint8_t data_word; // 0..63 holds a valid RC5 key code.
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
// IR remote control receiver is on IR_IN digital port
pinMode(IR_IN, INPUT);
// pin change interrupt enable on IR_IN port
PCMSK0 |= _BV(PCINT0);
PCICR |= _BV(PCIE0);
// Timer 0 : Fast PWM mode. Stopped, for now.
TCCR0A = _BV(WGM00) | _BV(WGM01);
TCCR0B = _BV(WGM02);
no_bits = 0;
sei(); // enable interrupts
}
void loop() {
if((no_bits == 14) && ((ir_data_word & 0x37C0) == 0x3400)){ // Changed from 0x3000 to 0x3400 to account for different device (aux)
no_bits = 0; // prepare for next capture
data_word = ir_data_word & 0x3F; // extract data word
//Serial.print(data_word, HEX); // output code to console
//Serial.print("\n"); // output code to console
switch(data_word) {
case 0x10: // Volume UP
// If mute isn't set and we haven't reached max, add to volume
if (mute == false) {
if (volume < 255) {
volume = volume + 1;
Serial.print(volume);
Serial.print("\n\r");
}
}
break;
case 0x11: // Volume DOWN
// If mute isn't set and we haven't reached min, subtract from volume
if (mute == false) {
if (volume > 0) {
volume = volume - 1;
Serial.print(volume);
Serial.print("\n\r");
}
}
break;
case 0x0D: // MUTE
// If mute isn't set, save current volume and set mute
if (mute == false) {
mute = true;
oldvolume = volume;
volume = 0;
Serial.print("MUTE");
Serial.print("\n\r");
} else {
// Else, restore previous volume and unset mute
mute = false;
volume = oldvolume;
oldvolume = 0;
Serial.print("UNMUTE");
Serial.print("\n\r");
}
break;
}
}
analogWrite(S_LEFT, volume);
analogWrite(S_RIGHT, volume);
}