NEC protocol infrared remote control

Publisher:WiseSage123Latest update time:2017-11-16 Source: eefocusKeywords:NEC Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The communication distance of home appliance remote controls is often not high, and the cost of infrared is much lower than other wireless devices, so infrared always occupies a place in home appliance remote control applications. There are many baseband communication protocols for remote controls, about dozens of them, and the commonly used ones are ITT protocol, NEC protocol, Sharp protocol, Philips RC-5 protocol, Sony SIRC protocol, etc. The most commonly used is the NEC protocol, so the remote control that comes with our KST-51 development board directly uses the NEC protocol. In this class, we will also explain the NEC protocol standard.

The data format of the NEC protocol includes the boot code, user code, user code (or user code inverse), key code and key code inverse, and the last stop bit. The stop bit mainly plays an isolation role and is generally not judged. We will ignore it when programming. The data encoding is a total of 4 bytes and 32 bits, as shown in Figure 16-7. The first byte is the user code, the second byte may also be the user code, or the inverse of the user code, which is determined by the manufacturer. The third byte is the key data code of the current key, and the fourth byte is the inverse of the key data code, which can be used for data error correction.

Figure 16-7 NEC protocol data format

The NEC protocol does not represent data in a way that is as intuitive as the UART protocol we have learned before. Instead, each bit of data itself needs to be encoded and then modulated on the carrier.

  • Pilot code: 9 ms carrier + 4.5 ms idle.

  • Bit value “0”: 560 us carrier + 560 us idle.

  • Bit value "1": 560 us carrier + 1.68 ms idle.

Combined with Figure 16-7, we can see clearly that the dark section at the front is the 9 ms carrier of the pilot code, followed by the 4.5 ms idle of the pilot code, and the data code behind is a crossover of many carriers and idles, and their length is determined by the specific data to be transmitted. The HS0038B infrared integrated receiver will output a low level when receiving a signal with a carrier, and a high level when idle. We use a logic analyzer to capture an infrared button and decode it through the HS0038B to understand it, as shown in Figure 16-8.

Figure 16-8 Infrared remote control button coding

As can be seen from the figure, the first is the start code of 9 ms carrier plus 4.5 ms idle, the data code is low-order first and high-order last, the first byte of the data code is 8 groups of 560 us carrier plus 560 us idle, that is, 0x00, the second byte is 8 groups of 560 us carrier plus 1.68 ms idle, which can be seen as 0xFF, these two bytes are the user code and the inverse of the user code. The key code of the button is 0x0C in binary, and the inverse code is 0xF3, followed by a 560 us carrier stop bit. For our remote control, different buttons are distinguished by key codes and key code inverse codes, and the user codes are the same. In this way, we can parse the key code of the current button through the program of the microcontroller.

When we studied interrupts earlier, we learned that the 51 microcontroller has two external interrupts: external interrupt 0 and external interrupt 1. Our infrared receiving pin is connected to the P3.3 pin, and the second function of this pin is external interrupt 1. Bit 3 and bit 2 in the TCON register are related to external interrupt 1. Among them, IE1 is the external interrupt flag bit. When an external interrupt occurs, this bit is automatically set to 1. Similar to the timer interrupt flag bit TF, it will be automatically cleared after entering the interrupt, and it can also be cleared by software. Bit 2 is used to set the external interrupt type. If bit 2 is 0, then the interrupt can be triggered as long as P3.3 is low level. If bit 2 is 1, then the falling edge of P3.3 from high level to low level can trigger the interrupt. In addition, the external interrupt 1 enable bit is EX1. Now let's write the program and use the digital tube to display the user code and key code of the remote control.

The Infrared.c file is mainly used to detect infrared communication. When an external interrupt occurs, it enters the external interrupt and is timed by timer 1. First, the boot code is judged, and then the high and low level time of each bit of the data code is obtained bit by bit, so as to know whether each bit is 0 or 1, and finally the data code is decoded. Although the function finally realized is very simple, the complexity of the encoding itself makes the interrupt program of infrared reception more complicated in logic. So we first provide the program flow chart of the interrupt function. You can refer to the flow chart to understand the program code, as shown in Figure 16-9.

Figure 16-9 Infrared receiving program flow chart

/***************************Infrared.c file program source code********************************/
#include 
sbit IR_INPUT = P3^3; //Infrared receiving pin
bit irflag = 0; //Infrared receiving flag, set to 1 after receiving a frame of correct data
unsigned char ircode[4]; // infrared code receiving buffer

/* Initialize infrared receiving function */
void InitInfrared(){
    IR_INPUT = 1; // Make sure the infrared receiving pin is released
    TMOD &= 0x0F; // Clear the control bit of T1
    TMOD |= 0x10; //Configure T1 to mode 1
    TR1 = 0; //Stop T1 counting
    ET1 = 0; //Disable T1 interrupt
    IT1 = 1; //Set INT1 to negative edge trigger
    EX1 = 1; // Enable INT1 interrupt
}
/* Get the duration of the current high level */
unsigned int GetHighTime(){
    TH1 = 0; // Clear T1 count initial value
    TL1 = 0;
    TR1 = 1; //Start T1 counting
    while (IR_INPUT){ //When the infrared input pin is 1, loop detection and waiting, and end this loop when it becomes 0
        //When the T1 count value is greater than 0x4000, that is, the high level duration exceeds about 18ms,
        //Forced exit loop is to avoid program hang here when signal is abnormal.
        if (TH1 >= 0x40){
            break;
        }
    }
    TR1 = 0; //Stop T1 counting
    return (TH1*256 + TL1); //T1 count value is synthesized into a 16-bit integer and returned
}
/* Get the duration of the current low level */
unsigned int GetLowTime(){
    TH1 = 0; // Clear T1 count initial value
    TL1 = 0;
    TR1 = 1; //Start T1 counting
    while (!IR_INPUT){ //When the infrared input pin is 0, loop detection and waiting, and end this loop when it becomes 1
        //When the T1 count value is greater than 0x4000, that is, the low level duration exceeds about 18ms,
        //Forced exit loop is to avoid program hang here when signal is abnormal.
        if (TH1 >= 0x40){
            break;
        }
    }
    TR1 = 0; //Stop T1 counting
    return (TH1*256 + TL1); //T1 count value is synthesized into a 16-bit integer and returned
}
/* INT1 interrupt service function, execute infrared reception and decoding */
void EXINT1_ISR() interrupt 2{
    unsigned char i, j;
    unsigned char byt;
    unsigned int time;

    //Receive and determine the 9ms low level of the boot code
    time = GetLowTime();
    //The time determination range is 8.5~9.5ms,
    //If it exceeds this range, it means it is a code error and exit directly
    if ((time<7833) || (time>8755)){
        IE1 = 0; // Clear INT1 interrupt flag before exiting
        return;
    }
    //Receive and determine the 4.5ms high level of the boot code
    time = GetHighTime();
    //The time determination range is 4.0~5.0ms,
    //If it exceeds this range, it means it is a code error and exit directly
    if ((time<3686) || (time>4608)){
        IE1 = 0;
        return;
    }
    //Receive and determine the subsequent 4 bytes of data
    for (i=0; i<4; i++){ //Loop to receive 4 bytes
        for (j=0; j<8; j++){ //Loop to receive and determine the 8 bits of each byte
            //Receive and determine the 560us low level of each bit
            time = GetLowTime();
            //The time determination range is 340~780us,
            //If it exceeds this range, it means it is a code error and exit directly
            if ((time<313) || (time>718)){
                IE1 = 0;
                return;
            }
            //Receive the high level time of each bit and determine the value of the bit
            time = GetHighTime();
            //The time determination range is 340~780us,
            //In this range, the bit value is 0
            if ((time>313) && (time<718)){
                byt >>= 1; //Since the low bit comes first, the data is shifted right and the high bit is 0
                //The time determination range is 1460~1900us,
                //In this range, the bit value is 1
            }else if ((time>1345) && (time<1751)){
                byt >>= 1; //Because the low bit comes first, the data is shifted right.
                byt |= 0x80; //high position 1
            }else{ //If it is not within the above range, it means it is an error code and exit directly
                IE1 = 0;
                return;
            }
        }
        ircode[i] = byt; //After receiving a byte, save it to the buffer
    }
    irflag = 1; //Set the flag after receiving
    IE1 = 0; // Clear INT1 interrupt flag before exiting
}

When reading this program, you will find that we made a timeout judgment if (TH1 >= 0x40) when obtaining the high and low level time. This timeout judgment is mainly to deal with abnormal input signals (such as unexpected interference, etc.). If the timeout judgment is not made, when the input signal is abnormal, the program may keep waiting for a jump edge that never arrives, causing the program to freeze.

In addition, the signals sent by pressing a button on the remote control once and by continuously pressing the button are different. Let's first compare the measured signal waveforms of the two key pressing methods, as shown in Figures 16-10 and 16-11.

Figure 16-10 Infrared single key timing diagram

Figure 16-11 Infrared continuous key timing diagram

The result of a single key press (Figure 16-9) is the same as Figure 16-8, so there is no need to explain it. For a continuous key press, a waveform similar to a single key press will be sent out first. After about 40 ms, a waveform of 9 ms carrier plus 2.25 ms idle, followed by a stop bit, will be generated. This is called a repeat code. As long as you keep pressing the key, a repeat code will be generated every 108 ms. Our program does not parse this repeat code separately, but ignores it directly. This does not affect the reception of normal key data. If you need to use this repeat code in your program in the future, you only need to add the analysis of the repeat code.

/********************************main.c file program source code******************************/
#include 
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[] = { // Digital tube display character conversion table
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = { //Digital tube display buffer
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char T0RH = 0; //T0 high byte of reload value
unsigned char T0RL = 0; //Low byte of T0 reload value
extern bit irflag;
extern unsigned char ircode[4];
extern void InitInfrared();
void ConfigTimer0(unsigned int ms);

void main(){
    EA = 1; // Enable general interrupt
    ENLED = 0; // Enable the digital tube selection
    ADDR3 = 1;
    InitInfrared(); //Initialize infrared function
    ConfigTimer0(1); //Configure T0 timing 1ms
    //PT0 = 1; //Configure T0 interrupt as high priority. Enabling this line can eliminate flickering during reception.

    while (1){
        if (irflag){ //Refresh the display when receiving infrared data
            irflag = 0;
            LedBuff[5] = LedChar[ircode[0] >> 4]; //User code display
            LedBuff[4] = LedChar[ircode[0]&0x0F];
            LedBuff[1] = LedChar[ircode[2] >> 4]; //Key code display
            LedBuff[0] = LedChar[ircode[2]&0x0F];
        }
    }
}
/* Configure and start T0, ms-T0 timing time */
void ConfigTimer0(unsigned int ms){
    unsigned long tmp; //temporary variable
    tmp = 11059200 / 12; //Timer counting frequency
    tmp = (tmp * ms) / 1000; //Calculate the required count value
    tmp = 65536 - tmp; //Calculate the timer reload value
    tmp = tmp + 13; //Compensate for the error caused by interrupt response delay
    T0RH = (unsigned char)(tmp>>8); //Timer reload value is split into high and low bytes
    T0RL = (unsigned char)tmp;

    TMOD &= 0xF0; // Clear the control bit of T0
    TMOD |= 0x01; //Configure T0 to mode 1
    TH0 = T0RH; //Load T0 reload value
    TL0 = T0RL;
    ET0 = 1; // Enable T0 interrupt
    TR0 = 1; //Start T0
}
/* LED dynamic scan refresh function, needs to be called in the timer interrupt */
void LedScan(){
    static unsigned char i = 0; //dynamic scan index
    P0 = 0xFF; // Turn off all segment selection bits and display blanking
    P1 = (P1 & 0xF8) | i; // Assign the bit selection index value to the lower 3 bits of port P1
    P0 = LedBuff[i]; //The data at the index position in the buffer is sent to port P0
    if (i < sizeof(LedBuff)-1){ //Index increment loop, traverse the entire buffer
        i++;
    }else{
        i = 0;
    }
}
/* T0 interrupt service function, execute digital tube scanning display */
void InterruptTimer0() interrupt 1{
    TH0 = T0RH; //Reload the reload value
    TL0 = T0RL;
    LedScan(); //Digital tube scanning display
}

The main function of the main.c file is to transmit the user code and key code information of the infrared remote control to the digital tube for display, and dynamically refresh the digital tube through the 1 ms interrupt of timer T0. I wonder if you have found through experiments that when we press the button of the remote control, the number displayed on the digital tube will flicker. What is the reason? The programs of the microcontroller are executed sequentially. Once we press the button of the remote control, the microcontroller will enter the interrupt program of the remote control decoding. The execution time of this program is relatively long, which takes dozens of milliseconds. If the dynamic refresh interval of the digital tube exceeds 10 ms, you will feel the flicker. Therefore, this flicker is caused by the delay of the dynamic refresh of the digital tube when the program executes infrared decoding.

How to solve it? We have talked about the interrupt priority problem before. If the interrupt preemption priority is set, interrupt nesting will occur. We have already talked about the principle of interrupt nesting when we talked about interrupts before. You can go back and review it. In this program, there are two interrupt programs, one is the external interrupt program responsible for receiving infrared data, and the other is the timer interrupt program responsible for digital tube scanning. In order to prevent infrared reception from delaying the execution of digital tube scanning, the timer interrupt must be nested with the external interrupt, that is, the timer interrupt is set to a high preemption priority. The timer interrupt program has an execution time of only tens of us. Even if it interrupts the execution of the infrared reception interrupt, it will only add an error of tens of us to the time measurement of each bit. This error is completely allowable in the shortest time judgment of 560 us, so interrupt nesting will not affect the normal reception of infrared data. In the main function, uncomment the line "//PT0 = 1;", which means that this line of code is effective. This sets the high preemption priority of the T0 interrupt. Compile it again, download it to the microcontroller, and try pressing the key. Is there no flicker? And you have realized the significance of interrupt nesting.


Keywords:NEC Reference address:NEC protocol infrared remote control

Previous article:Infrared remote control communication principle
Next article:Temperature sensor DS18B20

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号