一篇文章教会你红外发送模块发送红外信号,附STM32代码示例

目录

一、NEC协议介绍:​

二 、NEC协议特点:

(1)8位地址和8位命令长度:

(2)扩展模式可用,加倍地址大小:

(3)地址和命令都传输两次以提高可靠性:

(4)脉冲距离调制(Pulse Distance Modulation):

(5)载波频率为38kHz:

(6)位时间是1.125ms或2.25ms:

(7) 完整的数据传输格式: 

三、NEC协议:

四、扩展NEC协议:

五、所使用的红外发射和接收模块: 

 六、示例代码(STM32):

(1)初始化红外发射模块的GPIO端口和定时器生成38khz载波:

(2)发送引导码:

(3)发送NEC数据位0/1:

(4)NEC数据发送一个字节: 

(5)发送完整数据: 

七、效果演示及代码:


一、NEC协议介绍:​

  NEC协议是一种广泛使用的红外通信协议,它由NEC公司(现在称为Renesas)开发。这种协议也被称为日本格式,尽管它在全球范围内都有应用。NEC协议被用于多种设备,包括VCR、电视、投影仪等,其中NEC公司制造了遥控器的IC芯片。

二 、NEC协议特点:

(1)8位地址和8位命令长度:

  • NEC协议使用8位地址码和8位命令码。地址码用于标识特定的设备,命令码用于指定要执行的操作。
  • (2)扩展模式可用,加倍地址大小:

  • NEC协议有一个扩展模式,可以将地址长度从8位扩展到16位,从而提供更多的地址空间,允许更多的设备被唯一标识。
  • (3)地址和命令都传输两次以提高可靠性:

  • 为了确保数据的可靠性,NEC协议会将地址和命令各发送两次。第一次发送原始值,第二次发送其反码(inverted code)。
  • (4)脉冲距离调制(Pulse Distance Modulation):

  • NEC协议使用脉冲距离调制,这是一种通过改变脉冲之间的距离来编码信息的方法。
  • (5)载波频率为38kHz:

  • 红外信号的载波频率为38kHz,这是红外通信中常用的频率,可以确保信号的传输效率和抗干扰能力。
  • (6)位时间是1.125ms或2.25ms:

  • 在NEC协议中,每个位的持续时间可以是1.125ms或2.25ms,这取决于位的值。逻辑"0"通常用一个较短的脉冲表示,而逻辑"1"用一个较长的脉冲表示。这种编码方式有助于接收器区分逻辑"0"和逻辑"1"。
  •  

  • NEC协议使用脉冲距离编码来编码位。每个脉冲是一个560微秒长的38kHz载波脉冲(大约21个周期)。逻辑"1"需要2.25毫秒来传输,而逻辑"0"的时间只有它的一半,即1.125毫秒。推荐的载波占空比是1/4或1/3。 
  • (7) 完整的数据传输格式: 

  •  引导码+8位地址码+8位地址反码+8位命令码+8位命令反码。 
  • 三、NEC协议:

            上图展示了NEC协议的一个典型脉冲序列。根据这个协议,最低位(LSB)首先被传输。在这个例子中,地址 0x59 和命令0x16 被传输。消息的开始是一个9ms的AGC脉冲,这个脉冲被用来设置早期红外接收器的增益。这个AGC脉冲之后是一个4.5ms的间隙,紧接着是地址和命令的传输。地址和命令各传输两次,第二次所有位都取反,可以用于验证接收到的消息。由于每个位都以其取反的长度重复,因此总的传输时间是固定的。如果你不关心这种可靠性,可以忽略取反的值,或者你可以将地址和命令各扩展到16位! 请注意,在消息的末尾必须跟随一个额外的560µs脉冲,以便能够确定最后一个位的值。

            即使遥控器上的按键被按住,命令也只传输一次。只要按键保持按下状态,每110毫秒就会传输一次重复码。这个重复码仅仅是一个9毫秒的AGC脉冲,后面跟着一个2.25毫秒的间隙和一个560微秒的脉冲。 

     

    四、扩展NEC协议:

            NEC协议由于其广泛的应用,很快所有的地址可能值都被用完了。为了解决这个问题,通过牺牲地址的冗余性,地址范围从256个可能的值扩展到了大约65000个不同的值。这样,地址范围就从8位扩展到了16位,而没有改变协议的其他属性。通过这种方式扩展地址范围,消息的总传输时间就不再是固定的了,它现在取决于消息中1和0的总数。如果你想保持总消息时间的恒定,你需要确保地址字段中的1的数量是8个(这也自动意味着0的数量也是8个)。这将减少不同地址的最大数量到大约13000个。

            请注意,扩展协议中有256个地址值是无效的,因为它们实际上是标准的NEC协议地址。当低字节正好是高字节的相反数时,它就不是有效的扩展地址。

    五、所使用的红外发射和接收模块: 

     红外接收模块使用教程:

    一篇文章教会你红外接收模块接收红外遥控信号,附STM32代码示例

     六、示例代码(STM32):

    (1)初始化红外发射模块的GPIO端口和定时器生成38khz载波:

    // 初始化红外发射管所在的GPIO端口
    void IR_Init(void) {
        // 使能GPIOB端口的时钟,因为红外发射管通常连接到GPIO端口
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   
        // 使能定时器3(TIM3)的时钟,因为需要使用定时器来生成精确的PWM信号
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
        // 定义GPIO初始化结构体
        GPIO_InitTypeDef GPIO_InitStructure;    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;     					// 选择GPIOB的第0脚作为红外发射管的控制引脚
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      			// 设置GPIO模式为复用推挽输出,适合PWM输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;               // 设置GPIO速度为50MHz,确保信号变化足够快
        GPIO_Init(GPIOB, &GPIO_InitStructure);						    // 应用配置到GPIOB的第0脚
    
        // 选择TIM3为内部时钟源,若不调用此函数,TIM默认也为内部时钟
        TIM_InternalClockConfig(TIM3);
        
        // 定义定时器基本初始化结构体
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;   
        TIM_TimeBaseStructure.TIM_Prescaler = 72-1;						// 设置预分频器为71,用于降低定时器的计数速度
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     // 设置计数模式为向上计数
        // 设置自动重载寄存器的值,这会影响PWM的频率
        // 这里设置为26-1,即26,定时器计数到26后重置为0
        TIM_TimeBaseStructure.TIM_Period = 26-1;     
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;			// 设置时钟分频,这里不分频
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);				    // 应用这些配置到TIM3
    
        // 定义PWM输出初始化结构体
        TIM_OCInitTypeDef TIM_OCInitStructure; 
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				// 设置输出比较模式为PWM模式1
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	// 设置输出状态为使能
        TIM_OCInitStructure.TIM_Pulse = 0;								// 设置PWM脉冲宽度初始值为0,这将被用来调整PWM占空比
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		// 设置输出极性为高,这意味着PWM信号在活动时为高电平
        TIM_OC3Init(TIM3, &TIM_OCInitStructure);  						// 应用这些配置到TIM3的通道3
        TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  				// 使能预装载,允许在更新事件时更新比较值
       
        TIM_Cmd(TIM3, ENABLE);											// 使能TIM3

            首先配置定时器TIM3,在配置里面TIM默认的内部时钟为72MHz,设置预分频器为71,那么TIM的时钟频率为1MHz,也就是计数频率1us,计数周期修改成了25,也就是26个周期(0也算一个),经过换算可以得出1MHz / 26 ≈ 38.4615KHz,这个跟红外接收模块的频率38KHz差不多能匹配,我所使用的红外接收模块接收时需要38KHz的载波,所以配置成38KHz,市面上也有不是38KHz的红外接收模块,可以自行修改载波频率。

    (2)发送引导码:

    // 发送NEC引导码
    void IR_SendLeader(void) {
    	
        TIM_SetCompare3(TIM3, 9);         // 产生9ms的高电平
        Delay_us(9000);
        TIM_SetCompare3(TIM3, 0);         // 产生4.5ms的低电平
        Delay_us(4500);
    
    }

            引导码由9ms的低电平+4.5ms的高电平组成。红外接收模块在接收到红外信号时通常输出的是低电平。这是因为红外接收模块通常包含一个红外光电二极管,它在接收到红外光时会产生电流,从而触发一个开关(通常是三极管或MOSFET)导通。当这个开关导通时,它会将接收模块的输出引脚从高电平拉低到低电平。这里的引导码是相对于红外接收模块来说是9ms的低电平+4.5ms的高电平。推荐的载波占空比是1/4或1/3,26的1/3大约是9左右。

    (3)发送NEC数据位0/1:

    // 发送NEC数据位0/1
    void IR_SendBit(uint8_t bit) {
    
        if (bit) {                       //数据位1
            TIM_SetCompare3(TIM3, 9);    // 产生560us的高电平
            Delay_us(560);
            TIM_SetCompare3(TIM3, 0);    // 产生1680us的低电平
            Delay_us(1680);
        } else {                         //数据位0
            TIM_SetCompare3(TIM3, 9);    // 产生560us的高电平
            Delay_us(560);
            TIM_SetCompare3(TIM3, 0);    // 产生560us的低电平
            Delay_us(560);
        }
    
    }
  • 发送数据位0:   0.56ms低电平+ 0.56ms的高电平。
  • 发送数据位1:   0.56ms低电平+1.68ms的高电平 。
  • (4)NEC数据发送一个字节: 

    // NEC数据发送一个字节,从高位开始
    void IR_WriteByte(uint8_t byte) {
    
        for (uint8_t i = 0; i < 8; i++) {
            // 提取当前位的值
            uint8_t bit = (byte >> (7 - i)) & 0x01;
            // 写入这一位
            IR_SendBit(bit);		
        }
    
    }

            在NEC红外通信协议中,数据是按照先发送高位(MSB)再发送低位(LSB)的顺序进行传输的。这意味着在发送每个字节时,最高位(MSB)会首先被发送,然后依次是次高、次低…直到最低位(LSB)。 

    (5)发送完整数据: 

    // 发送NEC数据包
    void IR_SendNEC(uint8_t data, uint8_t address) {
    	
        IR_SendLeader(); 				// 发送引导码
    	
    	IR_SendByte(address);			// 发送地址码
    	IR_SendByte(~address);			// 发送地址反码
    	IR_SendByte(data);				// 发送命令码
    	IR_SendByte(~data);				// 发送命令反码
    	
        TIM_SetCompare3(TIM3, 9); 		// 发送结束码
        Delay_us(560);
        TIM_SetCompare3(TIM3, 0);
    }

    在消息的末尾必须跟随一个额外的560µs脉冲,以便能够确定最后一个位的值。

    七、效果演示及代码:

     

    通过网盘分享的文件:19- 红外接收模块接收红外发送模块信号
    链接: https://pan.baidu.com/s/1IaBiTvzRT6ym3xIFY6TPLA?pwd=xfks 提取码: xfks 

     

    作者:The_xzs

    物联沃分享整理
    物联沃-IOTWORD物联网 » 一篇文章教会你红外发送模块发送红外信号,附STM32代码示例

    发表回复