const int rs = 12;
const int en = 11;
const int d4 = 10;
const int d5 = 9;
const int d6 = 8;
const int d7 = 7;
char text[5];
boolean nec_ok = 0;
byte i, nec_state = 0, command, inv_command;
unsigned int address;
unsigned long nec_code;
void pulseEnable() {
digitalWrite(en, HIGH);
delayMicroseconds(1);
digitalWrite(en, LOW);
delayMicroseconds(50);
}
void sendCommand(byte command) {
digitalWrite(rs, LOW);
digitalWrite(d4, (command >> 4) & 1);
digitalWrite(d5, (command >> 5) & 1);
digitalWrite(d6, (command >> 6) & 1);
digitalWrite(d7, (command >> 7) & 1);
pulseEnable();
digitalWrite(d4, command & 1);
digitalWrite(d5, (command >> 1) & 1);
digitalWrite(d6, (command >> 2) & 1);
digitalWrite(d7, (command >> 3) & 1);
pulseEnable();
}
void sendData(byte data) {
digitalWrite(rs, HIGH);
digitalWrite(d4, (data >> 4) & 1);
digitalWrite(d5, (data >> 5) & 1);
digitalWrite(d6, (data >> 6) & 1);
digitalWrite(d7, (data >> 7) & 1);
pulseEnable();
digitalWrite(d4, data & 1);
digitalWrite(d5, (data >> 1) & 1);
digitalWrite(d6, (data >> 2) & 1);
digitalWrite(d7, (data >> 3) & 1);
pulseEnable();
}
void printText(const char* text, int row, int col) {
int position = col + (row == 1 ? 0x40 : 0x00);
sendCommand(0x80 | position); // Set DDRAM address
for (int i = 0; text[i] != '\0'; ++i) {
sendData(text[i]);
}
}
void setup() {
pinMode(rs, OUTPUT);
pinMode(en, OUTPUT);
pinMode(d4, OUTPUT);
pinMode(d5, OUTPUT);
pinMode(d6, OUTPUT);
pinMode(d7, OUTPUT);
sendCommand(0x33);
sendCommand(0x32);
sendCommand(0x28);
sendCommand(0x0C);
sendCommand(0x06);
sendCommand(0x01);
printText("Address:0x0000",0,0);
printText("Com:0x00 In:0x00",1,0);
// 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 < 8000)){
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)
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
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){ // mcu receives NEC message successfully
nec_ok = 0; // Reset decoding process
nec_state = 0;
TCCR1B = 0; // Disable Timer1 module
address = nec_code >> 16;
command = nec_code >> 8;
inv_command = nec_code;
sprintf(text, "%04X", address);
printText(text,0, 10);
sprintf(text, "%02X", command);
printText(text,1, 6);
sprintf(text, "%02X", inv_command);
printText(text,1, 14); // Display inverted command
attachInterrupt(0, remote_read, CHANGE);
}
}