In this blog I made NEC remote control decoder using Microchip PIC16F887 8-bit microcontroller and CCS C compiler, and this topic shows how to build the same project but using MikroElektronika mikroC PRO for PIC compiler.
Previous project and some information about the NEC protocol:
NEC Protocol decoder with PIC16F887 microcontroller – CCS C
Components Required:
- PIC16F887 microcontroller —> datasheet
- IR Receiver
- 1602 LCD screen
- 10k ohm variable resistor
- 5V Power source
- Protoboard
- Jumper wires
- PIC MCU Programmer (PICkit 3, PICkit 4…)
NEC remote control decoder with PIC16F887 MCU and mikroC compiler circuit:
NEC decoder circuit diagram is shown below.
In this example the PIC16F887 runs with its internal oscillator and MCLR pin function is disabled (configured in software).
The IR receiver has three pins (from left to right): GND, VCC and OUT where:
GND pin is connected to circuit ground.
VCC pin is positive power supply pin and it is connected to +5V.
OUT pin is the data pin and it is connected to PIC16F887 microcontroller RB0 pin (#33).
The 1602 LCD screen (2 rows and 16 columns) is used to display remote control decoded data, it is connected to the PIC16F887 MCU as follows:
RS —> pin RD0
E —> pin RD1
D4 —> pin RD2
D5 —> pin RD3
D6 —> pin RD4
D7 —> pin RD5
VSS, RW, D0, D1, D2, D3, and K are connected to circuit ground
VEE to the variable resistor (or potentiometer) output
VDD to +5V and A to +5V through 330 ohm resistor.
VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.
NEC remote control decoder with PIC16F887 microcontroller mikroC code:
The C code below was tested with mikroC pro for PIC version 7.1.0.
The PIC16F887 is configured to work with its internal oscillator @ 8MHz.
The message of the NEC protocol is 32-bit long: address (16 bits), command (8 bits), and inverted command (8 bits). Before the 32 bits there is 9ms burst and 4.5ms space.
A logic 1 is represented by 562.5µs burst and 562.5µs space (total of 1125µs) and a logic 0 is represented by 562.5µs burst and 1687.5µs space (total of 2250µs).
Keep in mind that the IR receiver output is always inverted.
The interval [ 9500µs, 8500µs ] is used for the 9ms pulse and for the 4.5ms space the interval [ 5000µs, 4000µs ] is used.
The 562.5µs pulse is checked with the interval [ 700µs, 400µs ] .
For the 562.5µs or 1687.5µs space I used the interval [ 1800µs, 400µs ], and to know if its a short or long space I used a length of 1000µs.
The output of the IR receiver is connected to the external interrupt pin RB0 (PORTB change interrupt), every change in the pin status generates an interrupt and Timer1 starts calculating, Timer1 value will be used in the next interrupt, this means Timer1 calculates the time between two interrupts which is pulse time or space time. Also, Timer1 interrupt is used to reset the decoding process in case of very long pulse or very long space.
Timer1 time step is 1µs (Timer1 increments every 1µs). If you use mcu frequency other than 8MHz, make sure to keep Timer1 time step to 1µs, otherwise time intervals have to be changed.
The decoding results are displayed on 1602 LCD screen connected to PORTD.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | // NEC Remote control decoder mikroC PRO for PIC compiler code // Used MCU: PIC16F887 runs with internal oscillator @ 8MHz // http://simple-circuit.com/ // LCD module connections sbit LCD_RS at RD0_bit; sbit LCD_EN at RD1_bit; sbit LCD_D4 at RD2_bit; sbit LCD_D5 at RD3_bit; sbit LCD_D6 at RD4_bit; sbit LCD_D7 at RD5_bit; sbit LCD_RS_Direction at TRISD0_bit; sbit LCD_EN_Direction at TRISD1_bit; sbit LCD_D4_Direction at TRISD2_bit; sbit LCD_D5_Direction at TRISD3_bit; sbit LCD_D6_Direction at TRISD4_bit; sbit LCD_D7_Direction at TRISD5_bit; // End LCD module connections bit nec_ok; char text[5]; unsigned short nec_state, command, inv_command, i; unsigned int address, timer_value; unsigned long nec_code; void Interrupt() { if (RBIF_bit && (PORTB.F0 || !PORTB.F0)){ // PORTB change ISR RBIF_bit = 0; if(nec_state != 0){ timer_value = (TMR1H << 8) + TMR1L; // Store Timer1 value TMR1H = 0; // Reset Timer1 TMR1L = 0; } switch(nec_state){ case 0 : // Start receiving IR data (we're at the beginning of 9ms pulse) TMR1H = 0; // Reset Timer1 TMR1L = 0; TMR1ON_bit = 1; // Enable Timer1 nec_state = 1; // Next state: end of 9ms pulse (start of 4.5ms space) i = 0; break; case 1 : // End of 9ms pulse if((timer_value > 9500) || (timer_value < 8500)){ // Invalid interval ==> stop decoding and reset nec_state = 0; // Reset decoding process TMR1ON_bit = 0; // Disable Timer1 } else nec_state = 2; // Next state: end of 4.5ms space (start of 562µs pulse) break; case 2 : // End of 4.5ms space if((timer_value > 5000) || (timer_value < 4000)){ nec_state = 0; // Reset decoding process TMR1ON_bit = 0; // Disable Timer1 } else nec_state = 3; // Next state: end of 562µs pulse (start of 562µs or 1687µs space) break; case 3 : // End of 562µs pulse if((timer_value > 700) || (timer_value < 400)){ // Invalid interval ==> stop decoding and reset TMR1ON_bit = 0; // Disable Timer1 nec_state = 0; // Reset decoding process } else nec_state = 4; // Next state: end of 562µs or 1687µs space break; case 4 : // End of 562µs or 1687µs space if((timer_value > 1800) || (timer_value < 400)){ // Time interval invalid ==> stop decoding TMR1ON_bit = 0; // Disable Timer1 nec_state = 0; // Reset decoding process break; } if( timer_value > 1000) // If space width > 1ms (short space) nec_code |= (unsigned long)1 << (31 - i); // Write 1 to bit (31 - i) else // If space width < 1ms (long space) nec_code &= ~((unsigned long)1 << (31 - i)); // Write 0 to bit (31 - i) i++; if(i > 31){ // If all bits are received nec_ok = 1; // Decoding process OK RBIE_bit = 0; // Disable PORTB change interrupt break; } nec_state = 3; // Next state: end of 562µs pulse (start of 562µs or 1687µs space) } } if (TMR1IF_bit){ // Timer1 ISR TMR1IF_bit = 0; // Clear Timer1 overflow flag bit nec_state = 0; // Reset decoding process TMR1ON_bit = 0; // Disable Timer1 } } void main() { OSCCON = 0X70; // Set internal oscillator to 8MHz nec_ok = 0; nec_state = 0; ANSELH = 0; // Configure all PORTB pins as digital Lcd_Init(); // Initialize LCD module Lcd_Cmd(_LCD_CURSOR_OFF); // cursor off Lcd_Cmd(_LCD_CLEAR); // clear LCD TMR1IF_bit = 0; // Clear Timer1 overflow interrupt flag bit RBIF_bit = 0; // Clear PORTB change interrupt flag bit TMR1IE_bit = 1; // Enable Timer1 overflow interrupt T1CON = 0x10; // Set Timer1 clock source to internal with 1:2 prescaler (Timer1 clock = 1MHz) INTCON = 0xC8; // Enable global, peripheral and PORTB change interrupts IOCB0_bit = 1; // Enable RB0 pin change interrupt Lcd_Out(1, 1, "Address:0x0000"); Lcd_Out(2, 1, "Com:0x00 In:0x00"); while(1) { while(!nec_ok); // Wait until NEC code receiver nec_ok = 0; // Reset decoding process nec_state = 0; TMR1ON_bit = 0; // Disable Timer1 address = nec_code >> 16; command = nec_code >> 8; inv_command = nec_code; IntToHex(address, text); // Save address in string text with hex format Lcd_Out(1, 11, text); // Display address ByteToHex(command, text); // Save command in string text with hex format Lcd_Out(2, 7, text); // Display command ByteToHex(inv_command, text); // Save inverted command in string text with hex format Lcd_Out(2, 15, text); // Display inverted command RBIE_bit = 1; // Enable PORTB change interrupt } } |
This project should gives the result shown in the following video:
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.
Many people request you to decode NEC and RC5 protocols in mikroC for AVR ATmega32 microcontroller.
Many people request you to decode NEC and RC5 protocols in mikroC for AVR ATmega32 microcontroller.
I hope you will consider my request.
Thanks
shema at proteus
Hi
The start 9ms pulse and 526.5us pulse composed of many small number of carrier pulses, so wouldn’t it trigger interrupt service routine.?
The diagram of the nec signal can be found in the link: http://simple-circuit.com/wp-content/uploads/2017/11/nec-protocol-modulation.png
It seems that the code considers the received signal as a continuous pulses instead of modulated carrier wave. Please help me understand why wouldn’t the timer1 be reset when a second high(or low-according to the type of edge detection) of the same pulse comes(according to your code)?
The IR receiver converts the ‘carrier pulses’ into one continues pulse.
on line 82 of your code is missing a BREAK statement
There is no need for a ‘break’ because it’s the end of case 4. But you can add it!
hy
please can you tell me that if i wouldn’t use Internal oscillator then i what to do?? mean i wan to use this program in PIC16F72. please can you help me??