打印
[应用方案]

N76E003红外解码程序

[复制链接]
601|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wang6623|  楼主 | 2023-2-28 23:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近学习了网上的红外解码程序保存学习一下
使用的是N76E003芯片
借鉴了好多地方
只是简单的启动LED灯
使用的是日本 NEC协议

外部定时器中断1
定时器模式2,8位自动重装 256步溢出一次
16M晶振
判断语句那里自己集合了好多想了一个案例
定义一个16位数字
将代码的用户码反码和键码正码一起判断
嘿嘿嘿
        uint i;
        i = IRcord[2] << 8;
        i |=  IRcord[1];//将第一个用户反码和按键码结合判断

使用特权

评论回复
评论
wang6623 2023-2-28 23:21 回复TA
———————————————— 版权声明:本文为CSDN博主「cssBIS」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/cssBIS/article/details/105745025 
沙发
wang6623|  楼主 | 2023-2-28 23:21 | 只看该作者
这里就是我写的全部的程序
只是一个简单的驱动程序

使用特权

评论回复
板凳
wang6623|  楼主 | 2023-2-28 23:22 | 只看该作者
#include "N76E003.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "Common.h"
#include "Delay.h"


#define uchar unsigned char
#define uint  unsigned int

sbit      IR = P1^7;                //定义红外脉冲数据接口        外部中断1输入口
sbit          SCLK = P3^0;                //初始时钟
sbit     RST = P1^6;                //CE端
sbit          DATA = P0^7;                //数据读写端

uchar IRtime;                //检测红外高电平持续时间(脉宽)
uchar IRcord[4];        //此数组用于储存分离出来的4个字节的数据(用户码2个字节+键值码2个字节)
uchar IRdata[33];        //此数组用于储存红外的33位数据(第一位为引导码用户码16+键值码16)
bit  IRpro_ok, IRok;        //第一个用于红外接收4个字节完毕。IRok用为检测脉宽完毕

void Init_T1()
{
                TIMER1_MODE2_ENABLE;//定时器0和定时器1工作方式2,8位自动重装
                TH1 = 0X00;//高8位装入0那么定时器溢出一次的时间是256个机器周期
                TL0 = 0X00;
               
                EA = 1;                        //总中断
                ET1 = 1;                  //定时器1中断
                TR1 = 1;                //启动定时器1
       
                IT1 = 1;        //设置外部中断1为跳沿触发方式,来一个下降沿触发一次
                EX1 = 1;         //启动外部中断1
       
}

void Time1() interrupt 3 //定义定时器1
{
                IRtime++;                //检测脉宽,1次为192uS
}

void EXT1_T1() interrupt 2        //定义外部中断1
{
        static uchar i;
        static bit startflag;
        if(startflag)
        {
                        if((IRtime < 78) &&(IRtime >= 63))
/*判断是否是引导码,低电平电平9000us+高4500us       
这个自己可以算我以11.0592来算了NEC协议的引导码低8000-10000+高4000-5000
如果已经接收了引导码那么i不会被置0就会开始依次存入脉宽*/
                                        i = 0;//如果是引导码那么执行i=0把他存到IRdata的第一个位
                                        IRdata[i] = IRtime; //以T0的溢出次数来计算脉宽,把这个时间存到数组里面到后面判断
                                        IRtime = 0; //计数清零,下一个下降沿的时候在存入脉宽
                                        i++;                //计数脉宽存入的次数
                                if(i == 33)         //如果存入34次 数组的下标是从0开始i等于33表示执行了34次
                                {
                                                IRok = 1;
                                                i = 0;         //把脉宽计数清零准备下次存入
                                }                               
        }
        else
        {
                IRtime = 0;                                 //引导码开始进入把脉宽计数清零开始计数
                startflag = 1;                        //开始处理标志位置1
        }
}

void IRcordpro()
{
                uchar i,j, k,cord,value;/*i用于处理4个字节,j用于处理一个字节中每一位,k用于33次脉宽中的哪一位
                                                                cord用于取出脉宽的时间判断是否符合1的脉宽时间*/
                k = 1;                                //从第一位脉宽开始取,丢弃引导码脉宽
        for(i = 0; i < 4;i++)
        {
                for(j = 0; j < 8; j++)
                {
                        cord = IRdata[k];                         //把脉宽存入cord
                        if(cord > 7)                                //如果脉宽大于我11.0592的t0溢出率为约278us*5=1390那么判断为1//1.3ms
                                value = value |0x80;        /*接收的时候是先接收最低位,
                                                                                把最低位先放到value的最高位在和0x08按位或一下
                                                                                这样不会改变valua的其他位的数值只会让他最高位为1*/
                        if(j < 7)//限制条件
                                value = value >> 1;        //value位左移依次接收8位数据。
                        k++;//每执行一次脉宽位加1
                }
                IRcord[i] = value;//每处理完一个字节把它放入IRcord数组中。
                value = 0;//清零value方便下次在存入数据
        }
        IRpro_ok = 1;//接收完4个字节后IRpro ok置1表示红外解码完成
}
void Init_GPIO()
{
                        Set_All_GPIO_Quasi_Mode;//所有口设置为双向口
                        P01_PushPull_Mode;//左路输出
                        P02_PushPull_Mode;//左路输出
                        P03_PushPull_Mode;//左路输出
                        P04_PushPull_Mode;//左路输出
                        P10_PushPull_Mode;//左路输出
                        P00_PushPull_Mode;//左路输出
                        P11_PushPull_Mode;//左路输出
                       
                    P17_Input_Mode;//P17输入上拉模式
                        clr_P00;
                        clr_P01;
                        clr_P02;
                        clr_P03;
                        clr_P04;
                        clr_P10;
                        clr_P11;
                        clr_P12;
                        clr_P13;
}

void main ()
{

                Init_T1();
                Init_GPIO();
                while(1)
                {
                        if(IRok)        //判断脉宽是否检测完毕
                                {
                                        IRcordpro();        //根据脉宽解码出4个字节的数据
                                        IRok = 0;                //重新等待脉宽检测
                                        if(IRpro_ok)        //解码完成
                                        {
                                                uint i;
                                                i = IRcord[2] << 8;
                                                i |=  IRcord[1];//将第一个用户反码和按键码结合判断
                                                switch(i)
                                                {
                                                        case 0x45ff: P04 = ~P04;break;
                                                        case 0x44ff: P03 = ~P03;break;
                                                        case 0x40ff: P10 = ~P10;break;
                                                        case 0x43ff: P11 = ~P11;break;
                                                        case 0x47ff: P02 = ~P02;break;
                                                        case 0x15ff: P00 = ~P00;break;
                                                        default:break;
                                                }
                                        }
                                }
                }
}

使用特权

评论回复
地板
wang6623|  楼主 | 2023-2-28 23:22 | 只看该作者
上面是之前多次写的这里添加按键长短按程序,抄写了其他人的程序
原文网址:http://www.51hei.com/bbs/dpj-58436-1.html

使用特权

评论回复
5
wang6623|  楼主 | 2023-2-28 23:22 | 只看该作者
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"

//【用户必填项:USER_H、USER_L、Check_EN、CPU_Fosc、IR】
#define  USER_H     0x80                         //用户码高8位
#define  USER_L     0x7F                         //用户码低8位
#define  Check_EN   0                             //是否要校验16位用户码:不校验填0,校验则填1       
#define  CPU_Fosc   16000000             //输入主频,自适应解码(单位:Hz,范围:6MHz ~ 40MHz)
#define  CA_S       8                             //长按时间设置,单位:108mS(即 108mS整数倍,10倍以上为宜)

sbit          IR = P1^7;                //定义红外脉冲数据接口        外部中断1输入口

//无符号类型
#define   uint8     unsigned char                       
#define   uint16    unsigned int

/*┈┈┈┈┈┈┈┈┈┈ 基准 ┈┈┈┈┈┈┈┈┈┈┈*/
#define  Boot_Limit                        (((9000+4500) +2000)/Step)          //引导码周期上限   
#define  Boot_Lower                        (((9000+4500) -2000)/Step)          //引导码周期下限   
#define  Bit1_Limit                        ((2250 +800)/Step)                  //“1”周期上限
#define  Bit0_Limit                        ((1125 +400)/Step)                          //“0”周期上限

#define Step    400                 //红外采样步长:400us
#define TH_H   ((65536 - Step*(CPU_Fosc/300)/40000)/256)  //定时器高8位基准赋值
#define TH_L   ((65536 - Step*(CPU_Fosc/300)/40000)%256)  //定时器低8位基准赋值

uint8   IR_BT;                         //解码效果返回:0无效,1有效,2短按,3长按
uint8   NEC[4] = 0;                         //解码存放:16位用户码、操作码正反码
uint8   cntCA;                         //长按计数
uint16  cntStep;                         //步数计
bit     IRa,IRb;                         //电位状态保存
bit     IRsync;                                 //同步标志
uint8   BitN;                //位码装载数

void KZ0();      //短按处理
void KZ1();      //长按处理
void IR_Init();
void  IR_NEC();


/***************** 主函数 ********************/
void main(void)
{
        Set_All_GPIO_Quasi_Mode;//所有口设置为双向口
        P17_Input_Mode;
        P15 = 0;
        P14 = 0;
        IR_Init();                           //红外线解码初始化
        NEC[4] = 0;

        while(1)
        {
          //遥控检测
          if((IR_BT==2)||(IR_BT==3))                          
      {
                if(IR_BT==2)
                {
                 switch(NEC[2])             
                   {
                          case 0x45:  P15 = ~P15; break;
                          default:break;
                   }       
                }                       
                 else        
                {
                   switch(NEC[2])             
                           {
                                  case 0x45: P14 = ~P14;break;
                                 default:break;
                           }
                }
                IR_BT =0;                        //清有效标志
          }
}
void IR_Init()
{

                TMOD &= 0xF0;           //清定时器0
                TMOD |= 0x01;           //定时器0:16位定时器
                TH0 = TH_H;                //每一步的时间       
                TL0 = TH_L;
                EA = 1;                                //总中断
                //ET1 = 1;                          //定时器1中断
                ET0 = 1;
       
                //TR1 = 1;                        //启动定时器1
                TR0 = 1;
/*IT1 = 1;                        //设置外部中断1为跳沿触发方式,来一个下降沿触发一次
                EX1 = 1;                         //启动外部中断1*/
               
}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:红外线NEC周期采样解码法(定时中断,下降沿查询周期时间)
全局变量:IR_BT = 0无效
                  1有效,待继续判断长、短按(如不需要判断长、短按,则直接使用)
                              2短按
                              3长按
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/

void  IR_NEC()
{
        TL0 = TH_L;  //重赋值
        TH0 = TH_H;         
       
        cntStep++;        //步数采样
        if(IR_BT == 1)if(cntStep>300)IR_BT = 2;//解码有效后,如果无长按,120ms(400us×300)后默认短按
       
        IRb = IRa;                   //上次电位状态
        IRa = IR;                   //当前电位状态
       
        if(IRb && !IRa)                //是否下降沿(上次高,当前低)判断动作
        {
                if(cntStep > Boot_Limit) //超过同步时间
                {
                         if(IR_BT==1)if(++cntCA>CA_S)IR_BT=3; //解码有效后,继续按住遥控>CA_S即长按
                                IRsync=0;                                  //同步位清0
                }
                else if(cntStep > Boot_Lower){IRsync = 1;BitN = 32; }//同步位置1,装载位码数
                else if(IRsync)
                {
                        if(cntStep > Bit1_Limit)IRsync = 0;
                        else
                        {
                                NEC[3] >>= 1;
                                if(cntStep > Bit0_Limit)NEC[3] |= 0x80;    //“0”与“1”
                                if(--BitN == 0)
                                {
                                        IRsync = 0;
                                        #if (Check_EN == 1)                                       
                                        if((NEC[0]==USER_H)&&(NEC[1]==USER_L)&&(NEC[2]==~NEC[3])) //校验16位用户码、操作码正反码
                                         {  IR_BT=1; cntCA=0;  }             //解码有效,接下来判断:短按?长按?
                                        #else
                                        if(NEC[2]==~NEC[3]){ IR_BT=1; cntCA=0; } //校验操作码正反码
                                        #endif       
                                }
                                else if((BitN & 0x07)== 0)       //NEC[3]每装满8位,移动保存一次(即 BitN%8 == 0)
                                {        NEC[0]=NEC[1]; NEC[1]=NEC[2]; NEC[2]=NEC[3];   }
                        }
                }
                cntStep = 0;   //步数计清0
        }
}



/********************** 定时器1断函数************************/
void time0(void) interrupt 1
{
   IR_NEC();
}  

使用特权

评论回复
6
hudi008| | 2023-4-16 22:31 | 只看该作者
N76E003 可以通过 GPIO 模拟红外解码器实现红外信号的接收和解码。

使用特权

评论回复
7
hudi008| | 2023-4-18 14:36 | 只看该作者
配置 N76E003 的 GPIO 引脚为输入模式,连接红外解码器的输出引脚到该引脚上。
使用定时器或外部中断等方式触发红外信号的接收过程,启动 GPIO 输入捕获功能。
在输入捕获事件中,使用软件计算红外信号的高低电平持续时间,并将其转换成对应的二进制数据。
对解码后的二进制数据进行校验和解析,得到红外信号的具体内容。
根据红外信号的解码结果执行相应的操作。

使用特权

评论回复
8
hudi008| | 2023-4-18 19:17 | 只看该作者
在实际应用中,还需要考虑到红外解码器的协议类型、波特率、编码格式等因素对解码效果的影响,针对不同的红外协议采取相应的解码策略。

使用特权

评论回复
9
mikewalpole| | 2023-4-18 20:39 | 只看该作者
还需要进行诸如噪声滤波、重复码处理等方面的优化,以提高解码精度和稳定性。

使用特权

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

本版积分规则

67

主题

435

帖子

0

粉丝