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********************************/ #includesbit 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******************************/ #includesbit 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.
Previous article:Infrared remote control communication principle
Next article:Temperature sensor DS18B20
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- W806-KIT Complete Information Package
- Filter Problems
- Switching Power Supply Theory and Design
- TI Single-Cell Fuel Gauge Basic Introduction and FAQs
- 【CH579M-R1】+Use of timestamp function
- 【AT-START-F425 Review】+u8g2 transplant test
- RS-485 transceiver: a summer mojito
- Do you know Allegro? Learn about Allegro's latest solutions for 48V systems required for vehicle electrification and emission control
- Disassembling a small thermometer and hygrometer
- The Definitive Guide to Arduino Robotics