您尚未登录。

楼主 # 2021-06-22 11:16:17

tigger
Moderator
注册时间: 2021-06-18
已发帖子: 172
积分: 111

N76E003 红外解码 / 长短按键 / 旋转编码器

转载: https://blog.csdn.net/cssBIS/article/details/105745025

最近学习了网上的红外解码程序保存学习一下
使用的是N76E003芯片
借鉴了好多地方
只是简单的启动LED灯
使用的是日本 NEC协议

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

#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;
						}
					}
				}
		}
}

离线

楼主 #1 2021-06-22 11:16:22

tigger
Moderator
注册时间: 2021-06-18
已发帖子: 172
积分: 111

Re: N76E003 红外解码 / 长短按键 / 旋转编码器

上面是之前多次写的这里添加按键长短按程序,抄写了其他人的程序
原文网址: http://www.51hei.com/bbs/dpj-58436-1.html

#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();
}  

离线

楼主 #2 2021-06-22 11:58:16

tigger
Moderator
注册时间: 2021-06-18
已发帖子: 172
积分: 111

Re: N76E003 红外解码 / 长短按键 / 旋转编码器

转载: https://blog.csdn.net/u014798590/article/details/95913702

电路图
如下图所示
2019071419331537_.png

其中EC11_A接P17、EC11_B接P30;电容103为0.01uf

信号分析
在这里插入图片描述
由上图中可以看出,当我们使用A相上升沿触发中断时,B相如果为高电平,则是顺时针旋转,反之则是逆时针旋转。
20190714193706805.png

#include "N76E003.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "Common.h"
#include "Delay.h"
#include <intrins.h>

#define uchar unsigned char
#define uint  unsigned int

sbit LED =P0^5;
			int temp;

void main (void) 
{
		 	Set_All_GPIO_Quasi_Mode;//所有引脚配置为双向模式
			P17_Input_Mode;//编码器A设定为输入
			P30_Input_Mode;//编码器B设定为输入
			LED=0;//初始化LED端口

			set_EA;	//开启总中断
			set_EPI;	//开启管脚中断(位于拓展中断中)

	
			clr_PIPS1;
			set_PIPS0;//选择P1.7为中断输入源
			

//Enable_BIT7_HighLevel_Trig;	//高电平
//Enable_BIT7_FallEdge_Trig;	//下降沿		
Enable_BIT7_RasingEdge_Trig;//上升沿
//Enable_BIT7_LowLevel_Trig;	//低电平

	while(1)
	{
	}
}

//-------管脚中断中断服务程序---------
void PinInterrupt (void) interrupt 7
{
		if(PIF==0x80&&P17)//P11位于一通道
		{
			Timer0_Delay1ms(1);//消抖
			if(P17)
			{
				if(P30)temp++;//顺时针
				else{temp--;}//逆时针
			}	
		}
				PIF=0;//清除外部中断标志
				LED=~LED;
}

离线

楼主 #3 2021-06-22 14:12:29

tigger
Moderator
注册时间: 2021-06-18
已发帖子: 172
积分: 111

Re: N76E003 红外解码 / 长短按键 / 旋转编码器

转载 https://blog.csdn.net/qq_29246181/article/details/105438180

sbit EC_B = P0 ^ 0;   // 编码器 P0.0 端口
sbit EC_A = P1 ^ 3;   // 编码器 P1.3 端口
static uint8_t EC_A_Val = 0, EC_B_Val = 0;
static uint8_t EC_A_old = 0, EC_B_old = 0;
/*********************************************
函数名:EncoderReading
功  能:读取编码器数据
形  参:
返回值:0--无动作 1--正转  2--反转
备  注:
作  者:薛建强
时  间:2019/06/11
**********************************************/
uint8_t EncoderReading(void)
{
    /*捕获一次*/
    EC_A_Val = EC_A;
    EC_B_Val = EC_B;
    /*************EC_B上升沿*******************/
    if (EC_A_Val == EC_A_old && EC_B_Val > EC_B_old)
    {
        /*重新给旧值赋值*/
        EC_B_old = EC_B_Val;
        EC_A_old = EC_A_Val;
        if (EC_A_Val == 0) //反转
        {
            return 2;
        }
    }
    /*************EC_B下升沿*******************/
    if (EC_A_Val == EC_A_old && EC_B_Val < EC_B_old)
    {
        /*重新给旧值赋值*/
        EC_B_old = EC_B_Val;
        EC_A_old = EC_A_Val;
        if (EC_A_Val == 1) //反转
        {
            return 2;
        }
    }
    /*************EC_A上升沿*******************/
    if (EC_B_Val == EC_B_old && EC_A_Val > EC_A_old)
    {
        /*重新给旧值赋值*/
        EC_B_old = EC_B_Val;
        EC_A_old = EC_A_Val;
        if (EC_B_Val == 0) //正转
        {
            return 1;
        }
    }
    /*************EC_A下升沿*******************/
    if (EC_B_Val == EC_B_old && EC_A_Val < EC_A_old)
    {
        /*重新给旧值赋值*/
        EC_B_old = EC_B_Val;
        EC_A_old = EC_A_Val;
        if (EC_B_Val == 1) //正转
        {
            return 1;
        }
    }
    return 0;
}
使用方式:
        KEY_state = EncoderReading(); //编码器调光度
        switch (KEY_state)
        {
          case 1://正转
                 break;
          case 2://反转
                 break;
        }

IO电平轮询法驱动编码器。

离线

楼主 #4 2021-06-22 14:19:57

tigger
Moderator
注册时间: 2021-06-18
已发帖子: 172
积分: 111

Re: N76E003 红外解码 / 长短按键 / 旋转编码器

转载: https://bbs.21ic.com/icview-2556720-1-1.html

用timer 2 capture作抓pwm


初始化:

                P05_Input_Mode;
                TIMER2_CAP0_Capture_Mode;
                IC6_P05_CAP0_BothEdge_Capture;
               
                set_ECAP;//Enable Capture interrupt
               
                set_TR2;//Triger Timer2
               
               
                set_EA;//enable interrupts

中断:

void Capture_ISR (void) interrupt 12
{
        clr_CAPF0; //clear capture0 interrupt flag
        if(P05==0)
        {
                input_capture_state=1;
                low_input        = (C0H<<8)&0xff00;       
                low_input |= C0L; //For capture mode CxL/CxH with data capture from I/O pin                                                                                                        
        }else
        {
                input_capture_state=2;
                high_input        = (C0H<<8)&0xff00;       
                high_input |= C0L;
        }
                               
        clr_TF2;
}

离线

楼主 #5 2021-06-22 14:38:24

tigger
Moderator
注册时间: 2021-06-18
已发帖子: 172
积分: 111

Re: N76E003 红外解码 / 长短按键 / 旋转编码器

https://bbs.21ic.com/icview-2556850-1-1.html

大家看看我理解双边沿捕获是否正确

捕获有双边沿和单边沿触发。
单边我们都知道可以测出一个信号的周期。这个周期包含高电平部分和低电平部分。
而双边沿触发,测到的可能是低电平的部分或者是高电平的部分。
以上理解都没错,OK?
单独讨论双边沿:
当一个信号触发后,比如从一个边沿进入了另外一个边沿的时候,打个比方,从高电平开始,进入了低电平。这个时候会捕获一个值,这个值是不是就是高电平的长度?而这个时候进入了低电平是不是可以判断一下,如果是低电平那么刚才测的数据属于高电平部分?

最后作者自己找到了答案:

对不起,楼主你的分析是正确的,今晚上我加班把timer2的相关寄存器都实际运行检查了一遍,终于查到了原因,原来我也是这样理解的,但今天我用厂家的BSP1.03的例程库改写测试了几遍,三种模式的结果都一模样,才提出这个问题。结果今晚上检查的结果是厂家的例程库的头文件有问题,我觉得厂家的提供的例程库不够严谨。原头文件

#define        IC2_P10_CAP0_BothEdge_Capture                                CAPCON0|=SET_BIT4;CAPCON1|=0x30;CAPCON1&=0xBF;CAPCON2|=SET_BIT4;CAPCON3&=0xF0;CAPCON3|=0x02;

改为
#define        IC2_P10_CAP0_BothEdge_Capture                                CAPCON0|=SET_BIT4;CAPCON1|=0x32;CAPCON1&=0xBF;CAPCON2|=SET_BIT4;CAPCON3&=0xF0;CAPCON3|=0x02;

就正常了,本来想减少时间,结果给厂家的例程库给陷害了

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn