STM32-单总线类传感器-红外遥控工作原理讲解

STM32-单总线类传感器-红外遥控工作原理讲解

红外遥控工作原理讲解

光的基础知识

光的本质:光的本质是电磁波,其传播本质上是一种粒子振动。广义上,光是指所有的电磁波谱。狭义上的光是人类眼睛可以看见的一种电磁波,也称可见光,。

光的波长:是指波在一个振动周期内传播的距离。光的波长由光的频率以及传播的介质决定,光通过不同介质的时候,频率不变而波长发生改变

光的颜色:是由它的波长来决定的,各种颜色有各自的波长,人的眼睛能看到的可见光按波长从长到短排列,依次为红、橙、黄、绿、青、蓝、紫。

红外线

可见光:光整个电磁波谱包括了无线电波、红外线、紫外线以及X射线等。它们的波长不同,其中波长在380~760纳米之间就是一般的可见光。依次为红、橙、黄、绿、青、蓝、紫。比紫光波长还短的光叫紫外线,比红光波长还长的光叫红外线。

红外线:是波长介于微波与可见光之间的电磁波,波长在1mm到760纳米(nm)之间,比红光长的非可见光。

高于绝对零度(-273.15℃)的物质都可以产生红外线。现代物理学称之为热射线。我们把红光之外的辐射叫做红外线(紫光之外是紫外线),人的肉眼不可见。

红外通信

无线远程遥控技术:

又称为遥控技术,是指实现对被控目标的遥远控制,在工业控制、航空航天、家电领域应用广泛。

红外遥控:

是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机和手机系统中。

红外通讯:

就是通过红外线传输数据。发射器发出红外信号,接收器接收到信号进行解析。

红外通信

红外遥控器:

红外遥控器是利用一个红外发光二极管,以红外光为载体来将按键信息传递给接收端的设备。红外光对于人眼是不可见的,因此使用红外遥控器不会影响人的视觉(可以打开手机摄像头,遥控器对着摄像头按,可以看到遥控器发出的红外光)。

信号调制:

日常生活环境中有很多红外光源,太阳、蜡烛火光、白炽灯、甚至是我们的身体。这些红外光源都可能会对我们的接收设备产生干扰,为了屏蔽干扰,只接收有效信息,我们就需要用到调制。

通过调制我们可以把指定的数字信号转换为特定频率的红外光进行发送,调制载波频率一般在30khz到60khz之间,大多数使用的是38kHz

红外接受器:

红外线接收器是一种可以接收红外信号并能独立完成从红外线接收到输出与TTL电平信号兼容的器件,体积和普通的塑封三极管差不多,适合于各种红外线遥控和红外线数据传输。

信号解调:

解调就是将模拟信号转换成数字信号。红外接收器接收到外部发射器传过来的红外信号后,会按照固定的协议去解析信号,并转换成数字信号输出。

NEC协议详解

NEC协议特点

  • 8位地址码,8位命令码
  • 完整发射两次地址码和命令码,以提高可靠性
  • 脉冲时间长短调制方式
  • 38KHz载波频率
  • 位时间 1.12ms或2.25ms

红外遥控实例讲解

实现红外遥控2个按键分别控制开关一盏灯

cubemx配置

只需要将连接传感器的那根信号线配置为上升和下降沿中断即可

驱动代码

RemoteInfrared.c

#include "RemoteInfrared.h"

#define REPEAT_KEY  0xEE

extern __IO uint32_t GlobalTimingDelay100us;
extern __IO uint32_t GlobalTimingDelay100usTx;


__IO uint32_t FlagGotKey = 0;

__IO Remote_Infrared_data_union RemoteInfrareddata;


/************************************************************************
//处理红外接收  
-------------------------协议--------------------------
开始拉低9ms,接着是一个4.5ms的高脉冲,通知器件开始传送数据了
接着是发送4个8位二进制码,第一二个是遥控识别码(REMOTE_ID),第一个为
正码(0),第二个为反码(255),接着两个数据是键值,第一个为正码
第二个为反码.发送完后40ms,遥控再发送一个9ms低,2ms高的脉冲,
表示按键的次数,出现一次则证明只按下了一次,如果出现多次,则可
以认为是持续按下该键.

*名称: Remote_Infrared_KEY_ISR(INT11_vect )													 
*功能: INT0中断服务程序		       									
*参数: 无					          									
*返回: 无		                           								
*************************************************************************/	
// 检测脉冲宽度最长脉宽为5ms
const uint32_t TIME_DELAY_6MS = 60;
const uint32_t TIME_DELAY_10MS = 100;

void Remote_Infrared_KEY_ISR(void)
{
	static __IO uint8_t  bBitCounter = 0; //键盘帧位计数
  static __IO uint32_t bKeyCode = 0;
	bBitCounter++;


	if(bBitCounter == 1)        // 开始拉低9ms
	{
        if(Remote_Infrared_DAT_INPUT) // 高电平无效
        {
            bBitCounter = 0;
        }
        else
        {
            GlobalTimingDelay100us = TIME_DELAY_10MS;
					  
        }
	}
	else if(bBitCounter == 2)   // 4.5ms的高脉冲
	{
        if(Remote_Infrared_DAT_INPUT)
        {
            if((GlobalTimingDelay100us > 2) && (GlobalTimingDelay100us < 18))
            {
                GlobalTimingDelay100us = TIME_DELAY_6MS;
            }
            else
            { 
                bBitCounter = 0; 
                //printf(".");
            }
        }

        else
        {
            bBitCounter = 0;            
        }
	}
	else if(bBitCounter == 3)   // 4.5ms的高脉冲
	{
        if(Remote_Infrared_DAT_INPUT)
        {
            bBitCounter = 0; 
        }
        else
        {
            if((GlobalTimingDelay100us > 5) && (GlobalTimingDelay100us < 20))    //起始码 4.5ms
            {
                GlobalTimingDelay100us = TIME_DELAY_6MS;
                //printf("引导码");
            }
            else if((GlobalTimingDelay100us > 32) && (GlobalTimingDelay100us < 46))   //重复码 2.25ms
            {
							  //重复码
                bBitCounter = 0;
                RemoteInfrareddata.uiRemoteInfraredData = bKeyCode;
                //RemoteInfrareddata.uiRemoteInfraredData = REPEAT_KEY;
                bBitCounter = 0;
                FlagGotKey = 1;
            }            
            else
            {
                bBitCounter = 0; 
                //printf("%d&", GlobalTimingDelay100us);
            }          
        }
	}    
	else if(bBitCounter > 3 && bBitCounter < 68) //接收8位数据
	{  

        if(Remote_Infrared_DAT_INPUT)          //检测数据脉冲低电平的时间
        {
            if((GlobalTimingDelay100us > 50) && (GlobalTimingDelay100us < 58))
            {
                GlobalTimingDelay100us = TIME_DELAY_6MS;
            }
            else
            {
                bBitCounter = 0; 
                //printf("#");
            }           
        }
        else
        {
            if((GlobalTimingDelay100us > 50) && (GlobalTimingDelay100us < 58))       // '0'  0.56ms左右
            {
                GlobalTimingDelay100us = TIME_DELAY_6MS;
								bKeyCode <<= 1;  // MSB First 
                bKeyCode += 0x00;
            }
            else if((GlobalTimingDelay100us > 40) && (GlobalTimingDelay100us < 48))  //'1'   1.685ms左右
            {
                GlobalTimingDelay100us = TIME_DELAY_6MS;            
								bKeyCode <<= 1;  // MSB First 
                bKeyCode += 0x01;
            }              
            else
            {
                bBitCounter = 0; 
            }  
        }

       if(bBitCounter == 67)
        {
            RemoteInfrareddata.uiRemoteInfraredData = bKeyCode;
            bBitCounter = 0;
            FlagGotKey = 1;
            //printf("KeyCode = 0x%X", bKeyCode);
        }
	}
	else
	{
		bBitCounter = 0;
        //printf("KeyCode = 0x%X", bKeyCode);
	}
}

/************************************************************************
*名称: unsigned char Remote_Infrared_KeyDeCode(unsigned char bKeyCode)					 
*功能: PS2键盘解码程序		       									    
*参数: bKeyCode 键盘码 							
*返回: 按键的ASIIC码		                           								
************************************************************************/
uint8_t Remote_Infrared_KeyDeCode(void)
{
//	uint8_t Key = 0xFF;

	if (FlagGotKey == 1)//通码
	{
        FlagGotKey = 0;
		
        if((RemoteInfrareddata.RemoteInfraredDataStruct.bID == (uint8_t)~ RemoteInfrareddata.RemoteInfraredDataStruct.bIDNot)
            && (RemoteInfrareddata.RemoteInfraredDataStruct.bKeyCode == (uint8_t)~ RemoteInfrareddata.RemoteInfraredDataStruct.bKeyCodeNot))
        {
            printf("\n\r IR Receive KeyCode = 0x%02X, ", RemoteInfrareddata.RemoteInfraredDataStruct.bKeyCode);
						switch(RemoteInfrareddata.RemoteInfraredDataStruct.bKeyCode)
						{
							case 0:
								printf("ERROR  ");
								break;
							case 0xA2:
								printf("CH-    ");
								break;
							case 0X62:
								printf("CH     ");
								break;
							case 0XE2:
								printf("CH+    ");
								break;
							case 0X22:
								printf("|<<    ");
								break;
							case 0X02:
								printf(">>|    ");
								break;
							case 0XC2:
								printf("PLAY/PAUSE");
								break;
							case 0XE0:
								printf("VOL-   ");
								break;
							case 0XA8:
								printf("VOL+   ");
								break;
							case 0X90:
								printf("EQ     ");
								break;
							case 0X98:
								printf("100+   ");
								break;
							case 0XB0:
								printf("200+   ");
								break;
							case 0x68:
								printf("0      ");
								break;
							case 0x30:
								printf("1      ");
								break;
							case 0x18:
								printf("2      ");
								break;
							case 0x7A:
								printf("3      ");
								break;
							case 0x10:
								printf("4      ");
								break;
							case 0x38:
								printf("5      ");
								break;
							case 0x5A:
								printf("6      ");
								break;
							case 0x42:
								printf("7      ");
								break;
							case 0x4A:
								printf("8      ");
								break;
							case 0x52:
								printf("9      ");
								break;
											default:
													printf("Unknown key!");
						}
        }
        else
        {
          printf("\n\r ERR 0x%08X", RemoteInfrareddata.uiRemoteInfraredData);
        }
    }

		return RemoteInfrareddata.RemoteInfraredDataStruct.bKeyCode;
}

RemoteInfrared.h

#include "stm32f4xx_hal.h"

#define	Remote_Infrared_DAT_INPUT HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8)

typedef struct _Remote_Infrared_data_struct //定义红外线接收到的数据结构体类型
{
	uint8_t bKeyCodeNot; //按键的的ASIIC码值
	uint8_t bKeyCode; //shift键按下标志
	uint8_t bIDNot; //断码标志位
	uint8_t bID; //新键标志位
}Remote_Infrared_data_struct;

typedef union _Remote_Infrared_data_union //定义红外线接收到的数据结构体类型
{
	Remote_Infrared_data_struct RemoteInfraredDataStruct; 
	uint32_t uiRemoteInfraredData; 
}Remote_Infrared_data_union;

void Remote_Infrared_KEY_ISR(void);
uint8_t Remote_Infrared_KeyDeCode(void);

main函数

	/*设置SYSTICK为 100us中断一次 */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/10000);     
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

	printf("\n\r");
	printf("\n\r-------------------------------------------------");
	printf("\n\r FS-STM32开发板 IR红外线接收实验程序");
	printf("\n\r 请将红外线接收头连接到开发板的对应接口");
	printf("\n\r 然后用红外遥控器进行控制,注意串口输出");
	printf("\n\r-------------------------------------------------");  
	printf("\n\r----------------- 协议如下 ----------------------");
	printf("\n\r 首先是引导码: 开始拉低9ms,接着一个4.5ms的高脉冲.");    
	printf("\n\r       引导码的作用是通知接收方器准备接收数据;");
	printf("\n\r 引导码之后是4个字节的二进制码, 其中前两个字节是");
	printf("\n\r       遥控识别码(ID), 第一个为正码,第二个为反码,");
	printf("\n\r       后两字节是键值, 第一个为正码,第二个为反码.");
	printf("\n\r 最后可能有持续按下通知, 上述数据发送完后如果刚才");
	printf("\n\r       的按键持续被按下, 则发送9ms低,2ms高的脉冲。");
	printf("\n\r---------------- 载波为38kHz --------------------");  
	printf("\n\r 传输一个逻辑1需要2.25ms(560us低电平+1680us高电平)");
	printf("\n\r 传输一个逻辑0需要1.125ms(560us低电平+560us高电平)");
	printf("\n\r-------------------------------------------------");  
	printf("\n\r----- 本实验在中断中检测接收IR红外线的数据 ------\n\r");


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	uint8_t key_value = 0x00;
  while (1)
  {
		
		key_value = Remote_Infrared_KeyDeCode();
		if(key_value == 0x08){
			HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8, GPIO_PIN_RESET);
		}else{
			HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8, GPIO_PIN_SET);
		}
}

注意:一定要修改时钟配置为100us中断一次