九齐NY8A051D硬件IR模块的配置和使用以及解码处理

写在前面

最近在群里有看到有小伙伴在问九齐的硬件IR模块,突然想起来我好像用过,找了半天才把项目找出来,写篇博客记录一下方便下次使用和寻找。

按道理来说九齐所有内置硬件IR模块的MCU都是可以用类似的方法配置和使用的,举一反三哈。

发码

寄存器介绍

在这里插入图片描述
其实就是用到这个IRCR寄存器,通过配置IRCSEL可以选择通过PB1的什么电平来输出IR波。

红外管端代码

代码也很简单,全部贴出来自取吧:

/* =========================================================================
 *  Project:       发送端
 *  File:          main.c
 *  Description:   051D
 *  
 * 
 *  Author:        Pd
 *  Version:       V1.0
 *  Date:          2022/4/20	
 =========================================================================*/
#include <ny8.h>
#include "ny8_constant.h"

#define  u16  unsigned int
#define  u8   unsigned char

void delay_us(int);
void delay_ms(int);

/* =======================================================================*/

#define  LED       PORTBbits.PB5            //红外LED


/* =======================================================================*/

u16 t_200ms=0;
u8  f_send=0;
u8  f_start=0;
u8  t_start=0;
u8  send_data=0x89;
u8  i=0;
u8  j=0;

/* =======================================================================*/
void delay_us(int count)  //@16M  2T   2.5us
{
	for(;count>0;count--);

}

void delay_ms(int count) //@16M  2T
{
	int i;for(;count>0;count--){for(i=0;i<=330;i++);}
}

void sys_init(void)
{
	PCON &= ~(1<<3);  //关闭LVR  需要在IC_CONFIG里面设置寄存器配置
}

/* =======================================================================*/

void io_init(void)
{
	IOSTB|=((1<<4)|(1<<3)|(1<<2)|(1<<0));      //B4输入

    IOSTB&=~(1<<1);     //B1输出
    IOSTB&=~(1<<2);     //B2输出
    IOSTB&=~(1<<5);     //B5输出
	BPHCON=0;           //开启B口所有上拉电阻
	PB1=0;LED=0;
}


void timer1_init(void)
{
    T1CR1=0X02;                                     //当下溢发生,定时器 1 初始值从TMR1 寄存器被重新加载并继续下数
    T1CR2=0X03;                                     //分频

    TMR1 =123;
    INTE  |=(1<<3);                                 //开启T1中断
    T1CR1 |=0x01;                                   //开启T1
}

void ir_init(void)
{
    IRCR=0X05;
}

/* =======================================================================*/

void isr(void) __interrupt(0)
{
    if(INTFbits.T1IF)	//定时器1中断  //500us
    {
        INTFbits.T1IF=0;  
             
        t_200ms++;
        if(t_200ms>=1000)
        {
            t_200ms=0;
            f_send=1;
            f_start=1;
        }

        if(f_send==1)
        {
            if(f_start==1)
            {
                t_start++;
                if(t_start<22)
                {
                    PB1=0;
                }
                else
                {
                    PB1=1;
                }
            }
            if(t_start>=30)
            {
                t_start=0;
                f_start=0;
            }
        }
    }
}

void main(void)
{
    io_init();
	delay_ms(50);
	
    timer1_init();
    ir_init();
	INTF = 0;         //清除所有中断标志
    DISI();     	  //关闭总中断
	ENI();	    	  //开启总中断

    while(1)
    {
        if(f_send==1 && f_start==0)
        {
        	j++;
            if(j<=8)
            {
                i=send_data&0x01;
                if(i==0)
                {
                	PB1=1;
                    delay_us(500);
                    PB1=0;
                    delay_us(500);
                    PB1=1;
                }
                else
                {
                	PB1=1;
                    delay_us(500);
                    PB1=0;
                    delay_us(1500);
                    PB1=1;
                }
                send_data=send_data>>1;
            }
            if(j==9) {j=0;send_data=0x89;f_send=0;}
        }
    }
}

代码是比较简单的,当时写的协议忘记是通用协议还是私有协议了。

无非就是先发头码,然后发数据。

用硬件IR的好处就是不再需要自己通过硬件PWM去配初值了,不过局限性也很明显,这个硬件IR模块也就只支持38K和57K,而且亲测误差是比较大的,38K量出来实际好像到40多K了。如果要求特别精确,还是只能使用硬件PWM去调。

解码

解码逻辑

实在是忘记了当时的协议了,自己读了下代码推测发射端是,数据“1”是由0.5ms的低电平+1.5ms的38K载波,数据“0”是由0.5ms的低电平+0.5ms的38K载波。

看接收端硬件是将接收头的输出脚接了上拉电阻,也就是说接收头的空闲状态,输入到MCU的电平信号是高电平,当有接收到发射端的38K信号之后,输出一个低电平给到MCU。

那么对于接收端MCU的IO来说:
数据“0” = 0.5ms的高电平 + 0.5ms的低电平 (因为没有收到38K载波,IO会被上拉到高电平。收到载波之后会被拉低)
数据“1” = 0.5ms的高电平 + 1.5ms的低电平

两者的区别就是低电平的时间,那么只需要判定低电平的时间就可以判断出发射端发过来的数据是什么。

那么我的处理方式是开启IO中断,在进入中断后判断IO信号,如果IO信号为0,那么开启计数,当下次进中断判断IO如果为高电平,说明载波数据已经结束,这时候就可以判断低电平(载波时间)是多少,就可以判断出发射端是要传输“0”还是“1”了。

接收端代码

/* =========================================================================
 *  Project:       接收端
 *  File:          main.c
 *  Description:   051D
 *  
 * 
 *  Author:        Pd
 *  Version:       V1.0
 *  Date:          2022/4/22	
 =========================================================================*/
#include <ny8.h>
#include "ny8_constant.h"

#define  u16  unsigned int
#define  u8   unsigned char

void delay_us(int);
void delay_ms(int);

/* =======================================================================*/

#define  REC       PORTBbits.PB5            //红外接收
#define  LED       PORTBbits.PB4            //RGB-12V
#define  GLED	   PORTBbits.PB0			//指示灯   收到---0		没收到---1(高电平有效)
/* =======================================================================*/

u8  f_rec=0;
u8  f_head=0;
u8  f_no_rec=0;
u8  f_receive=0;
u8  f_error=0;
u8  f_bit_end=0;
u8  t_error=0;
u16 t_no_rec=0;
u8  t_head1=0;
u8  t_bit_end=0;
u16 t_receive=0;
u8  rec_data=0;
u8  get_data=0;
u8  bit_receive=0;
u8  t_over_time=0;
u16 t_low_time=0;
u8  f_rece_38k=0;
u8  i=0;
u8  j=0;
u8  z=1;

/* =======================================================================*/
void delay_us(int count)  //@16M  2T   2.5us
{
    for(;count>0;count--);

}

void delay_ms(int count) //@16M  2T
{
    int i;for(;count>0;count--){for(i=0;i<=330;i++);}
}

void sys_init(void)
{
    PCON &= ~(1<<3);  //关闭LVR  需要在IC_CONFIG里面设置寄存器配置
}

/* =======================================================================*/

void io_init(void)
{
    IOSTB|=((1<<5)|(1<<3)|(1<<2));      //B4输入

    IOSTB&=~((1<<4)|(1<<0));     //B4输出
    BPHCON=0;           //开启B口所有上拉电阻
    
    REC=1;LED=1;GLED=0;
}


void timer1_init(void)
{
    T1CR1=0X02;                                     //当下溢发生,定时器 1 初始值从TMR1 寄存器被重新加载并继续下数
    T1CR2=0X00;                                     //2分频

    TMR1 =100;
    INTE  |=(1<<3);                                 //开启T1中断
    T1CR1 |=0x01;                                   //开启T1
}


void pb_init(void)
{
    BWUCON|=(1<<5);     //开启PB5电平变化中断
    INTE  |=(1<<1);                                 //开启PB中断
}

/* =======================================================================*/


void isr(void) __interrupt(0)
{
    if(INTFbits.T1IF)	//定时器1中断                //50us
    {
        INTFbits.T1IF=0;

        if(f_rece_38k==1 && REC==0)
        {
            t_low_time++;
        }


        if(t_receive<=25000)						//不停的计时,当超时之后指示灯亮
        {
            t_receive++;							//每次收到一帧正确的数据时候清零超时计数器
        }
        if(t_receive>=10000 && LED==1)
        {
            LED=0;
            GLED=1;									//没受到数据   指示灯亮提醒
            f_head=0;
            t_low_time=0;
            bit_receive=0;
            rec_data=0;
            i=0;j=0;z=0;
        }
    }

    if(INTFbits.PBIF)	    //PB中断
    {
        INTFbits.PBIF=0;

        if(REC==0)
        {
            f_rece_38k=1;
        }
        else
        {
            if(f_head==0)
            {
                if(t_low_time>180 && t_low_time<480)
                {
                    f_head=1;
                    t_low_time=0;
                    bit_receive=0;
                    rec_data=0;
                    i=0;j=0;z=0;
                }
                else
                {
                    f_head=0;
                    t_low_time=0;
                    f_rece_38k=0;
                }
                
                if(t_low_time>1000)
                {
                    t_error++;
                    if(t_error>=10)
                    {
                        f_error=1;
                        LED=0;
                        GLED=1;									//没收到数据   指示灯亮提醒
                    }
                }
            }
            else
            {
            	rec_data=rec_data<<1;
                if(t_low_time>=50 && t_low_time<=200)				
                {
                    rec_data|=0x01;								//收到的数据是1
                    t_low_time=0;
                }
                else if(t_low_time>=20 && t_low_time<50)
                {
                    t_low_time=0;								//收到的数据是0
                }
                else if(t_low_time>200 || t_low_time<20)		//收到的数据电平持续时间不符合规范,推测是出错了
                {
                    f_head=0;
                    t_low_time=0;
                    bit_receive=0;
                    rec_data=0;
                    t_error++;									//错误次数超过10次开始报警
                    if(t_error>=10)
                    {
                        f_error=1;
                        LED=0;
                        GLED=1;									//没收到数据   指示灯亮提醒
                    }
                }
                
                bit_receive++;
                if(bit_receive>=8)
                {
                    f_head=0;
                    bit_receive=0;
                    f_rece_38k=0;
                    t_low_time=0;
                    i=rec_data&0x01;
                    j=rec_data&0x10;
                    j=j>>4;
                    z=rec_data&0x80;
                    z=z>>7;
                    if(i==1 && j==1 && z==1)
                    {
                        f_error=0;
                        t_error=0;
                        t_receive=0;
                        LED=1;
                        GLED=0;									//受到数据   指示灯灭
                    }
                    rec_data=0; 
                }
            }
        }
    }
}

void main(void)
{
    io_init();
    delay_ms(50);
    pb_init();
    timer1_init();
    INTF = 0;         //清除所有中断标志
    DISI();     	  //关闭总中断
    ENI();	    	  //开启总中断
    while(1)
    {
        
    }
}

代码比较垃圾,接受端解码的校验部分不懂当时是怎样设计的,读者自行忽略吧。。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值