// Arduino remote controlled DC motor (speed and direction control) // NEC IR remote control is used (Car MP3) #define pwm1 5 #define pwm2 6 boolean nec_ok = 0, motor_dir = 0, repeated = 0; byte i, nec_state = 0, duty_cycle = 0; unsigned long nec_code; void setup() { pinMode(pwm1, OUTPUT); pinMode(pwm2, OUTPUT); // Timer1 module configuration TCCR1A = 0; TCCR1B = 0; // Disable Timer1 module TCNT1 = 0; // Set Timer1 preload value to 0 (reset) TIMSK1 = 1; // enable Timer1 overflow interrupt attachInterrupt(0, remote_read, CHANGE); // Enable external interrupt (INT0) } void remote_read() { unsigned int timer_value; if(nec_state != 0){ timer_value = TCNT1; // Store Timer1 value TCNT1 = 0; // Reset Timer1 } switch(nec_state){ case 0 : // Start receiving IR data (we're at the beginning of 9ms pulse) TCNT1 = 0; // Reset Timer1 TCCR1B = 2; // Enable Timer1 module with 1/8 prescaler ( 2 ticks every 1 us) nec_state = 1; // Next state: end of 9ms pulse (start of 4.5ms space) i = 0; return; case 1 : // End of 9ms pulse if((timer_value > 19000) || (timer_value < 17000)){ // Invalid interval ==> stop decoding and reset nec_state = 0; // Reset decoding process TCCR1B = 0; // Disable Timer1 module } else nec_state = 2; // Next state: end of 4.5ms space (start of 562µs pulse) return; case 2 : // End of 4.5ms space if((timer_value > 10000) || (timer_value < 3000)){ nec_state = 0; // Reset decoding process TCCR1B = 0; // Disable Timer1 module } else{ nec_state = 3; // Next state: end of 562µs pulse (start of 562µs or 1687µs space) if(timer_value < 6000) // Check if previous code is repeated repeated = 1; } return; case 3 : // End of 562µs pulse if((timer_value > 1400) || (timer_value < 800)){ // Invalid interval ==> stop decoding and reset TCCR1B = 0; // Disable Timer1 module nec_state = 0; // Reset decoding process } else { // Check if the repeated code is for button 2 or 3 if(repeated && (nec_code == 0x40BFB04F || nec_code == 0x40BF708F)){ repeated = 0; nec_ok = 1; // Decoding process is finished with success detachInterrupt(0); // Disable external interrupt (INT0) } else nec_state = 4; // Next state: end of 562µs or 1687µs space } return; case 4 : // End of 562µs or 1687µs space if((timer_value > 3600) || (timer_value < 800)){ // Time interval invalid ==> stop decoding TCCR1B = 0; // Disable Timer1 module nec_state = 0; // Reset decoding process return; } if( timer_value > 2000) // If space width > 1ms (short space) bitSet(nec_code, (31 - i)); // Write 1 to bit (31 - i) else // If space width < 1ms (long space) bitClear(nec_code, (31 - i)); // Write 0 to bit (31 - i) i++; if(i > 31){ // If all bits are received nec_ok = 1; // Decoding process OK detachInterrupt(0); // Disable external interrupt (INT0) return; } nec_state = 3; // Next state: end of 562µs pulse (start of 562µs or 1687µs space) } } ISR(TIMER1_OVF_vect) { // Timer1 interrupt service routine (ISR) nec_state = 0; // Reset decoding process TCCR1B = 0; // Disable Timer1 module } void loop() { if(nec_ok) { nec_ok = 0; // Reset decoding process nec_state = 0; TCCR1B = 0; // Disable Timer1 module if(nec_code == 0x40BF30CF){ // If button 1 is pressed (change motor direction of rotation) motor_dir = !motor_dir; // Toggle direction variable if(motor_dir) digitalWrite(pwm2, 0); else digitalWrite(pwm1, 0); } if(nec_code == 0x40BF708F && duty_cycle < 255) // If button 3 is pressed (increase motor speed) duty_cycle++; if(nec_code == 0x40BFB04F && duty_cycle > 0) // If button 2 is pressed (decrease motor speed) duty_cycle--; if(motor_dir) analogWrite(pwm1, duty_cycle); else analogWrite(pwm2, duty_cycle); attachInterrupt(0, remote_read, CHANGE); // Enable external interrupt (INT0) } }