Infrared remote control communication

Keywords: IoT stm32

Infrared remote control protocol

Wireless contactless control technology
At present, PWM (pulse width modulation) of NEC Protocol and PPM (pulse position modulation) of Philips RC-5 Protocol are widely used in the coding of infrared remote control

characteristic

Anti interference ability, reliable signal transmission, low power consumption, low cost and easy to realize

appearance


Receiver head: OUT GDN 3.3V

NEC protocol features

① 8-bit address and 8-bit instruction length
② Address and command secondary transmission
③ PWM pulse width modulation represents 0.1 with the duty cycle of transmitting infrared carrier
④ Carrier frequency 38Khz
⑤ Bit time is 1.125ms or 2.25ms (distinguished by high-level duration)

NEC code point definition

One pulse corresponds to 560us continuous carrier. One logic 1 transmission takes 2.25ms and one logic 0 transmission takes 1.125ms
The remote control receiver is at low level when receiving pulse and high level when there is no pulse
Then 1:560us low + 1680us high
2: 560us low + 560us high

NEC remote control command format

The data format is:
Synchronous terminal address code address inverse code control code control inverse code
Synchronization code: 9ms low level + 4.5ms high level
Others are in 8-bit data format
Sequence: low order in front, high order in back
Inverse code can increase transmission reliability

Serial code

9ms low level + 2.5 high level + 0.56 low level + 97.94ms high level
If the key is not released after a frame of data is sent, a duplicate code will be transmitted
Serial code

Hardware connection


Programming ideas

one ️⃣ Start timer input capture default rising edge capture counting frequency 1MHz automatic loading value 10000 overflow time 10ms
two ️⃣ Timer input capture update interrupt capture interrupt capture rising edge generate capture interrupt timer count overflow update interrupt
three ️⃣ When the rising edge is captured, set the falling edge immediately, set the timer count value to 0, and set the bit 4 value of the variable RmtSta to 1 to mark the capture to the rising edge
four ️⃣ The value of the capture falling edge read timer is assigned to the variable Dval, then the capture polarity is set to rising edge capture, and the bit 4 of RmtSta is judged
1: If the rising edge is captured, judge that the Dval 300-800 (560) is 0; 1400-1800 is 1, 2200-2600 indicates continuous transmission, and 4200-4700 indicates synchronization code
five ️⃣ Overflow interrupt occurs in the timer. If the synchronization code is received before and it is the first overflow, the key information collection is completed

Experimental procedure

//initialization
void Remote_Init(void)    			  
{		
  GPIO_InitTypeDef  GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef  TIM1_ICInitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//Enable GPIOA clock
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//TIM1 clock enable

  //GPIOA8 multiplex pull-up
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//Performance reuse
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push pull output
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//Pull up
  GPIO_Init(GPIOA, &GPIO_InitStructure);//initialization
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //GPIOA8 multiplex TIM1
	
	TIM_TimeBaseStructure.TIM_Prescaler=167;  Prescaler 1 M Counting frequency	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //Count up
	TIM_TimeBaseStructure.TIM_Period=10000;   //Set counter auto reload value
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure); 
  	  
 	//Initialize TIM2 input capture parameters
	TIM1_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01  	 Select input IC1 to map on TI1
  TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//Rising edge capture TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // mapping
  TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	 //Configure input frequency division without frequency division 
  TIM1_ICInitStructure.TIM_ICFilter = 0x03;//IC1F=0003 8 timer clock cycle filtering
  TIM_ICInit(TIM1, &TIM1_ICInitStructure);//Initialize timer 2 input capture channel
	 

	TIM_ITConfig(TIM1,TIM_IT_Update|TIM_IT_CC1,ENABLE);//Allow update interrupt allow CC1IE capture interrupt
  TIM_Cmd(TIM1,ENABLE ); 	 	//Enable timer 1
 
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//Preemption priority 1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//Sub priority 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRO channel enable
	NVIC_Init(&NVIC_InitStructure);	//Initialize NVIC register

  NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//Preemption sub priority 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		//Sub priority 2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ channel enable
	NVIC_Init(&NVIC_InitStructure);	//Initialize NVIC register
}

//Timer 1 input capture interrupt service routine

void TIM1_CC_IRQHandler(void)
{ 		    	 
	if(TIM_GetITStatus(TIM1,TIM_IT_CC1)==SET) //Process Capture (CC1TE) interrupt
	{	  
		if(RDATA)//Rising edge capture
		{
			TIM_OC1PolarityConfig(TIM1,TIM_ICPolarity_Falling);		//CC1P=1 set falling edge capture
			TIM_SetCounter(TIM1,0);	   	//Clear timer value
			RmtSta|=0X10;					//The rising edge of the marker has been captured
		}else //Falling edge capture
		{
			Dval=TIM_GetCapture1(TIM1);
			TIM_OC1PolarityConfig(TIM1,TIM_ICPolarity_Rising); //CC1P=0 	 Set rising edge capture
			if(RmtSta&0X10)					//Complete a high level acquisition 
			{
 				if(RmtSta&0X80)//Received boot code
				{
					
					if(Dval>300&&Dval<800)			//560 standard value, 560us
					{
						RmtRec<<=1;	//Move left one bit
						RmtRec|=0;	//1 bit received   
					}else if(Dval>1400&&Dval<1800)	//1680 bit standard, 1680us
					{
						RmtRec<<=1;	
						RmtRec|=1;
					}else if(Dval>2200&&Dval<2600)	//Get the key value increase information 2500 as standard 2.5ms
					{
						RmtCnt++; 		//The number of keys is increased once
						RmtSta&=0XF0;	//Clear timer		
					}
 				}else if(Dval>4200&&Dval<4700)		//4500 is the standard value of 4.5ms
				{
					RmtSta|=1<<7;	//Mark successful boot reception
					RmtCnt=0;		//Clear key count register
				}						 
			}
			RmtSta&=~(1<<4);
		}				 		     	    					   
	}
	TIM_ClearITPendingBit(TIM1,TIM_IT_CC1);  //Clear interrupt flag bit
}

//Timer 1 overflow interrupt
void TIM1_UP_TIM10_IRQHandler(void)
{
 
  if(TIM_GetITStatus(TIM1,TIM_IT_Update)==SET) //Overflow interrupt
	{
		if(RmtSta&0x80)//Last received data
		{	
			RmtSta&=~0X10;						//Cancel rising capture flag
			if((RmtSta&0X0F)==0X00)RmtSta|=1<<6;//Mark that the key value information collection of one key has been completed
			if((RmtSta&0X0F)<14)RmtSta++;
			//14 is taken because it is about 90ms at the end of the continuous transmission code. If it overflows more than 13 times, it indicates that the received continuous transmission code has ended and the relevant parameters are cleared
			else
			{
				RmtSta&=~(1<<7);//Clear boot flag
				RmtSta&=0XF0;	//Clear counter	
			}						 	   	
		}							    
	}
	TIM_ClearITPendingBit(TIM1,TIM_IT_Update);  //Clear interrupt flag bit 
} 
//Processing infrared keyboard

u8 Remote_Scan(void)
{        
	u8 sta=0;       
    u8 t1,t2;  
	if(RmtSta&(1<<6))//Got all the information about a key
	{ 
	    t1=RmtRec>>24;			//Get the address code
	    t2=(RmtRec>>16)&0xff;	//Get address inverse code
 	    if((t1==(u8)~t2)&&t1==REMOTE_ID)//Verify the remote control identification code (ID) and address
	    { 
	        t1=RmtRec>>8;
	        t2=RmtRec; 	
	        if(t1==(u8)~t2)sta=t1;//The key value is correct	 
		}   
		if((sta==0)||((RmtSta&0X80)==0))//Key data error / remote control has not been pressed
		{
		 	RmtSta&=~(1<<6);//Clear received valid key ID
			RmtCnt=0;		//Clear key count
		}
	}  
    return sta;
}
//Main function
int main(void)
{ 
	u8 key;
	u8 t=0;	
	u8 *str=0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//Set system interrupt priority group 2
	delay_init(168);  //Initialization delay function
	uart_init(115200);		//Initialization serial port baud rate 115200
	
	LED_Init();					
 	LCD_Init();
 	Remote_Init();						 	
	
 	POINT_COLOR=RED;
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"REMOTE TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2021/10/10");
   	LCD_ShowString(30,130,200,16,16,"KEYVAL:");	
   	LCD_ShowString(30,150,200,16,16,"KEYCNT:");	
   	LCD_ShowString(30,170,200,16,16,"SYMBOL:");	 
	while(1)
	{
		key=Remote_Scan();	
		if(key)
		{	 
			LCD_ShowNum(86,130,key,3,16);		//Display key value
			LCD_ShowNum(86,150,RmtCnt,3,16);	//Displays the number of keystrokes		  
			switch(key)
			{
				case 0:str="ERROR";break;			   
				case 162:str="POWER";break;	    
				case 98:str="UP";break;	    
				case 2:str="PLAY";break;		 
				case 226:str="ALIENTEK";break;		  
				case 194:str="RIGHT";break;	   
				case 34:str="LEFT";break;		  
				case 224:str="VOL-";break;		  
				case 168:str="DOWN";break;		   
				case 144:str="VOL+";break;		    
				case 104:str="1";break;		  
				case 152:str="2";break;	   
				case 176:str="3";break;	    
				case 48:str="4";break;		    
				case 24:str="5";break;		    
				case 122:str="6";break;		  
				case 16:str="7";break;			   					
				case 56:str="8";break;	 
				case 90:str="9";break;
				case 66:str="0";break;
				case 82:str="DELETE";break;		 
			}
			LCD_Fill(86,170,116+8*8,170+16,WHITE);	//Clear previous display
			LCD_ShowString(86,170,200,16,16,str);	//Display SYMBOL
		}else delay_ms(10);	  
		t++;
		if(t==20)
		{
			t=0;
			LED0=!LED0;
		}
	}
}

Posted by centenial on Sun, 10 Oct 2021 01:08:12 -0700