单片机基于NEC协议的红外软编码和硬解码方案

在物联网产品的开发过程中经常需要基于无线的简单交互通讯,红外通讯比较适合近距离低速的

交换数据场景,红外协议比较多,比如NEC,RC5,NRC17等。

NEC红外协议,GPIO口的输出时序,
1.逻辑0为脉冲时间560us低电平+560us高电平,1.12ms周期 ,逻辑1为脉冲时间560us低电平+1690us高电平,  2.25ms周期。
2.命令格式 9ms低电平引导码+4.5ms高电平结果码+地址码+地址反码+命令码+命令反码 (经测试必须32BIT(4个字节))+560us低电平作为结束,经测试接收管自动反向,注意这四个字节为(A,~A,B,~B)。
3.占空比1/4到1/3载波为38KHZ的PWM。
4.命令格式的电平反向形式。

使用GD32F4XX串口3作为红外编解码通讯接口,

USART3_RX接收BC7120A的红外解码数据,波特率9600。

USART3_TX作为普通IO输出因引脚与外部38KHZ振荡电路通过与门输出调制脉冲到红外发射管。

delay.c软件延时

#ifndef __DELAY_H__
#define __DELAY_H__

#include "gd32f4xx.h"

#define   delay_us                  Delay_US
#define   delay_ms                  Delay_MS

#define   HAL_Delay                 Delay_MS    


void Delay_US(uint32_t time);

void Delay_MS(uint32_t time);


#endif


#include "delay.h"

#define CURRENT_CPU_FREQ           (SystemCoreClock / 1000000)

void Delay_US(uint32_t time)
{    
    while(time--)
	{
		 #if (CURRENT_CPU_FREQ == 120)
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		 #elif (CURRENT_CPU_FREQ == 168)
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
			#elif (CURRENT_CPU_FREQ == 200)
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
				 __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();						 
		  #else
		      __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		  #endif
	}
}


void Delay_MS(uint32_t time)
{   	
	
     Delay_US(time * 11000);
}


 

timer1.c定时器硬件延时

#ifndef __TIMER1_H__
#define __TIMER1_H__

#include "gd32f4xx.h"
#include "it_config.h"


void Timer_Init(void);

void Timer_Dly_Wait(uint32_t time);


#endif



#include "timer1.h"


#define  TIMx                                       TIMER0
#define  RCU_TIMx_CLK                               RCU_TIMER0

#define  TIMx_IRQn                                  TIMER0_UP_TIMER9_IRQn
#define  TIMx_IRQHandler                            TIMER0_UP_TIMER9_IRQHandler                        


/**100us时基*/
static __IO uint32_t timer1_100us_cnt             = 0;



void Timer_Init(void)
{
		
	timer_parameter_struct timer_initpara;

	rcu_periph_clock_enable(RCU_TIMx_CLK);

	timer_deinit(TIMx);
	/* initialize TIMER init parameter struct */
	timer_struct_para_init(&timer_initpara);
	

	/* TIMER1 configuration 配置出来中断为100us 168MHZ下*/
	timer_initpara.prescaler                  = 168 - 1;
	timer_initpara.alignedmode                = TIMER_COUNTER_EDGE;
	timer_initpara.counterdirection           = TIMER_COUNTER_UP;
	timer_initpara.period                     = 100;
	timer_initpara.clockdivision              = TIMER_CKDIV_DIV1;

	nvic_irq_enable(TIMx_IRQn, TIMER1_NVIC_PREEMPTIONPRIORITY, TIMER1_NVIC_SUBPRIORITY);
	

	timer_init(TIMx, &timer_initpara);

	timer_interrupt_enable(TIMx, TIMER_INT_UP);
	timer_enable(TIMx);
		
}




/**
  * @brief  This function handles TIMER1 interrupt request.
  * @param  None
  * @retval None
  */
void TIMx_IRQHandler(void)
{
	
    if(SET == timer_interrupt_flag_get(TIMx, TIMER_INT_FLAG_UP)){
        /* clear channel 0 interrupt bit */
        timer_interrupt_flag_clear(TIMx, TIMER_INT_FLAG_UP);
       		
       	timer1_100us_cnt++;
	
    }
}



//定时器防止uint32_t溢出延时函数
void Timer_Dly_Wait(uint32_t time)
{
     uint32_t cur_cnt = timer1_100us_cnt;

     if(cur_cnt + time <= 0xFFFFFFFF)
     {
        while(timer1_100us_cnt - cur_cnt < time);
     }
     else
     {
		  
        while(timer1_100us_cnt < 0xFFFFFFFF);	
		 
        time = time - (0xFFFFFFFF - cur_cnt);
        while(1 + timer1_100us_cnt < time);			 
     }
}



infrared.c红外软编码硬解码实现

#ifndef __INFRARED_H__
#define __INFRARED_H__

#include <string.h>
#include "cmsis_os.h"
#include "gd32f4xx.h"
#include "config.h"
#include "comtypes.h"
#include "delay.h"
#include "timer1.h"
#include "raygunled.h"
#include "mode.h"


#define IR_TX_FUNC
#define IR_RX_FUNC



void  IR_Init(void);

void  IR_Send(uint8_t*buf, uint8_t len);



#endif




#include "infrared.h"


#define USART2_DATA_ADDRESS                ((uint32_t)&USART_DATA(USART2))
#define USART3_DR_ADDR                     USART2_DATA_ADDRESS 

#define USARTx                             USART2
#define RCU_GPIO_CLK                       RCU_GPIOC
#define RCU_USARTx_CLK                     RCU_USART2
#define USART_GPIO_AF                      GPIO_AF_7

#define USARTx_TX_GPIO_PORT                GPIOC
#define USARTx_TX_PIN                      GPIO_PIN_10
#define USARTx_RX_GPIO_PORT                GPIOC
#define USARTx_RX_PIN                      GPIO_PIN_11

#define DMAx                               DMA0
#define RCU_DMAx_CLK                       RCU_DMA0
#define USARTx_TX_DMA_CHANNEL              DMA_CH3   
#define USARTx_RX_DMA_CHANNEL              DMA_CH1
#define USARTx_DMA_SUBPERI4                DMA_SUBPERI4

#define USARTx_IRQn                        USART2_IRQn
#define USARTx_IRQHandler                  USART2_IRQHandler

#define USART3_RECV_BUFF_LEN               (3)

#define TX_PIN_SET                         gpio_bit_set(USARTx_TX_GPIO_PORT,USARTx_TX_PIN)
#define TX_PIN_RESET                       gpio_bit_reset(USARTx_TX_GPIO_PORT,USARTx_TX_PIN)
#define IR_TX(x)	                          ((x) ? TX_PIN_SET : TX_PIN_RESET) 


static dma_single_data_parameter_struct dma_init_struct;

//DMA接收缓冲区
static __IO uint8_t usart3_recv_buf[USART3_RECV_BUFF_LEN];

__IO BOOLEAN  is_be_shooted              = FALSE;
__IO int      shooted_bullet             = 0;                      



#ifdef IR_TX_FUNC
static __INLINE void IR_DELAY(uint8_t tm)
{
      uint8_t tmp;
	
      tmp = tm / 10;
      if(tmp)
      {
	  osDelay(tmp);
      }
	
      tmp = tm % 10;
      if(tmp)
      {		 
          Timer_Dly_Wait(tmp);
      }
}
#endif




void  IR_Init(void)
{
					
	rcu_periph_clock_enable(RCU_GPIO_CLK);

	/* enable USART clock */
	rcu_periph_clock_enable(RCU_USARTx_CLK);

	/* connect port to USARTx_Tx */
	//gpio_af_set(USARTx_TX_GPIO_PORT, USART_GPIO_AF, USARTx_TX_PIN);

	/* connect port to USARTx_Rx */
	gpio_af_set(USARTx_RX_GPIO_PORT, USART_GPIO_AF, USARTx_RX_PIN);

	/* configure USART Tx  push-pull */
	gpio_mode_set(USARTx_TX_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP,USARTx_TX_PIN);
	gpio_output_options_set(USARTx_TX_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,USARTx_TX_PIN);

	gpio_bit_set(USARTx_TX_GPIO_PORT,USARTx_TX_PIN);

	/* configure USART Rx as alternate function push-pull */
	gpio_mode_set(USARTx_RX_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP,USARTx_RX_PIN);
	gpio_output_options_set(USARTx_RX_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,USARTx_RX_PIN);


	/* USART configure */
	usart_deinit(USARTx);

	//注意该波特率
	usart_baudrate_set(USARTx, 9600U);
	usart_word_length_set(USARTx, USART_WL_8BIT);
	usart_stop_bit_set(USARTx, USART_STB_1BIT);
	usart_parity_config(USARTx, USART_PM_NONE);

	usart_hardware_flow_rts_config(USARTx, USART_RTS_DISABLE);
	usart_hardware_flow_cts_config(USARTx, USART_CTS_DISABLE);

	usart_receive_config(USARTx, USART_RECEIVE_ENABLE);
	//usart_transmit_config(USARTx, USART_TRANSMIT_ENABLE);	

	///			
	/* enable DMA1 */
	rcu_periph_clock_enable(RCU_DMAx_CLK);

	dma_deinit(DMAx, USARTx_RX_DMA_CHANNEL);

	dma_init_struct.direction                             = DMA_PERIPH_TO_MEMORY;
	dma_init_struct.memory0_addr                          = (uint32_t)usart3_recv_buf;
	dma_init_struct.memory_inc                            = DMA_MEMORY_INCREASE_ENABLE;
	dma_init_struct.periph_memory_width                   = DMA_PERIPH_WIDTH_8BIT;
	dma_init_struct.number                                = USART3_RECV_BUFF_LEN;
	dma_init_struct.periph_addr                           = USART3_DR_ADDR;
	dma_init_struct.periph_inc                            = DMA_PERIPH_INCREASE_DISABLE;
	dma_init_struct.priority                              = DMA_PRIORITY_ULTRA_HIGH;		

	dma_single_data_mode_init(DMAx, USARTx_RX_DMA_CHANNEL, &dma_init_struct);

	/* configure DMA mode */
	dma_circulation_enable(DMAx, USARTx_RX_DMA_CHANNEL);

	dma_channel_subperipheral_select(DMAx, USARTx_RX_DMA_CHANNEL, USARTx_DMA_SUBPERI4);


	nvic_irq_enable(USARTx_IRQn, USART3_NVIC_PREEMPTIONPRIORITY, USART3_NVIC_SUBPRIORITY);

	usart_dma_receive_config(USARTx, USART_DENR_ENABLE);
	dma_channel_enable(DMAx, USARTx_RX_DMA_CHANNEL);

	usart_interrupt_enable(USARTx,USART_INT_IDLE);	
	usart_enable(USARTx);
}





//NEC协议软编码
void  IR_Send(uint8_t*buf, uint8_t len)
{		
#ifdef IR_TX_FUNC	
	    uint8_t i                                            = 0;
	    uint8_t j                                            = 0;
	    uint8_t tmp                                          = 0;


	    //发送9ms引导码 低电平
	    IR_TX(0);
        IR_DELAY(90);
			
	
	    //发送4.5ms结果码 高电平
	    IR_TX(1);           
        IR_DELAY(45);
        IR_TX(0);
	    
				
        for(i=0;i < len;i++)
        {
				   
		 tmp = buf[i];
		 
		 //数据从低位向高位发送
		 for(j=0;j < 8;j++)
		 {
             //发送逻辑1
		     if(tmp & 0x01)
		     {
			      IR_TX(0);
                  IR_DELAY(5);
			      Delay_US(60);
			     //共计560us 低电平
								 
			      IR_TX(1);
                  IR_DELAY(16);
			      Delay_US(90);
			      IR_TX(0);
			      //共计1.690ms 高电平
		     }
		     //发送逻辑0
		     else
		     {
			      IR_TX(0);
                  IR_DELAY(5);
			      Delay_US(60);
			      //共计560us 低电平
								 
			      IR_TX(1);
                  IR_DELAY(5);
			      Delay_US(60);
			      IR_TX(0);
			      //共计560us 高电平
		      }
							 
		      tmp >>= 1;
		  }
	     }
			
			
	    //最后发送一个结束560us低电平,实验得到非常重要
	    IR_TX(0);
        IR_DELAY(5);
	    Delay_US(60);
			
	   //波形两端拉高
	   IR_TX(1);
#endif			
}





//串口3DMA空闲中断处理函数,用于接收BC7120A硬解码的红外数据。
void USARTx_IRQHandler(void)
{	
	uint16_t tmp;

	dma_channel_disable(DMAx, USARTx_RX_DMA_CHANNEL);
	usart_interrupt_flag_clear(USARTx,USART_INT_FLAG_IDLE);	
	usart_data_receive(USARTx);


	if(USART3_RECV_BUFF_LEN != dma_transfer_number_get(DMAx,USARTx_RX_DMA_CHANNEL))   goto USART3_IRQEND;
  
	tmp                    =  usart3_recv_buf[0];
	if(usart3_recv_buf[1] != (uint8_t)~tmp)       goto USART3_IRQEND;
	usart3_recv_buf[2]    ^= (uint8_t)(tmp * 5);
 
 
	if(!Is_Raygunled_Hurt(usart3_recv_buf[2],&tmp)) goto USART3_IRQEND;

	shooted_bullet         = tmp;

	is_be_shooted          = TRUE;		


USART3_IRQEND:	

	dma_deinit(DMAx, USARTx_RX_DMA_CHANNEL);
	dma_single_data_mode_init(DMAx, USARTx_RX_DMA_CHANNEL, &dma_init_struct);
	dma_circulation_enable(DMAx, USARTx_RX_DMA_CHANNEL);
	dma_channel_subperipheral_select(DMAx, USARTx_RX_DMA_CHANNEL,   USARTx_DMA_SUBPERI4);
	dma_channel_enable(DMAx, USARTx_RX_DMA_CHANNEL);
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在51单片机中,可以通过使用定时器和外部中断来实现NEC红外编码的发送。以下是一个简单的示例代码,你可以根据自己的需求进行修改: ```c #include <reg51.h> #define FREQ_OSC 12000000UL // 晶振频率 #define T_US (1.0 / FREQ_OSC * 12) // 1个机器周期所用的时间(us) #define IR_PORT P2 // 红外发射器连接的端口 #define IR_PIN 0 // 红外发射器连接的引脚 #define IR_OUT 0 // 红外发射器输出高电平的时间(单位:us) #define IR_HEADER_MARK 9000 // NEC协议头部的引导码的高电平时间(us) #define IR_HEADER_SPACE 4500 // NEC协议头部的引导码的低电平时间(us) #define IR_BIT_MARK 560 // NEC协议数据位的高电平时间(us) #define IR_ONE_SPACE 1690 // NEC协议数据位为1的低电平时间(us) #define IR_ZERO_SPACE 560 // NEC协议数据位为0的低电平时间(us) #define IR_END_MARK 560 // NEC协议结束码的高电平时间(us) unsigned char ir_data[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF}; void delay_us(unsigned int t) { while (t--) { _nop_(); _nop_(); } } void ir_send_bit(unsigned char bit) { if (bit) { IR_PORT |= (1 << IR_PIN); delay_us(IR_OUT); IR_PORT &= ~(1 << IR_PIN); delay_us(IR_ONE_SPACE - IR_OUT); } else { IR_PORT |= (1 << IR_PIN); delay_us(IR_OUT); IR_PORT &= ~(1 << IR_PIN); delay_us(IR_ZERO_SPACE - IR_OUT); } } void ir_send(unsigned char *data, unsigned char len) { unsigned char i, j; // 发送头部的引导码 IR_PORT &= ~(1 << IR_PIN); delay_us(IR_HEADER_SPACE); IR_PORT |= (1 << IR_PIN); delay_us(IR_HEADER_MARK - IR_OUT); IR_PORT &= ~(1 << IR_PIN); delay_us(IR_HEADER_SPACE); // 发送数据位 for (i = 0; i < len; i++) { for (j = 0; j < 8; j++) { ir_send_bit((data[i] >> j) & 0x01); } } // 发送结束码 IR_PORT &= ~(1 << IR_PIN); delay_us(IR_END_MARK); } void main() { while (1) { ir_send(ir_data, sizeof(ir_data) / sizeof(unsigned char)); delay_ms(1000); // 发送间隔1秒钟 } } ``` 在上述代码中,我们定义了红外发射器连接的端口和引脚,并且定义了NEC协议编码格式。然后使用`ir_send()`函数来发送红外编码,该函数会将数据位和结束码按照NEC协议的格式发送出去。 你可以将`ir_data`数组替换为你要发送的数据,然后将代码烧录进51单片机中即可。注意在使用前需要根据实际情况进行修改端口和引脚号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值