打印
[研电赛技术支持]

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

[复制链接]
434|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2023-7-10 13:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在物联网产品的开发过程中经常需要基于无线的简单交互通讯,红外通讯比较适合近距离低速的

交换数据场景,红外协议比较多,比如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;
                 
                 //数据从低位向高位发送
                 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);
}






————————————————
版权声明:本文为CSDN博主「麦德泽特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44470384/article/details/131310202

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2028

主题

15903

帖子

14

粉丝