单片机实验(十四)红外遥控

80S52:红外遥控模块

功能:显示遥控按键对应用户码毫无作用

红外遥控是类似于之前的串口通信但没有波特率的说法,主要就是按照红外遥控器发出信号的时序进行分析。

如我实验使用的DT9122D遥控器可从说明书中查得其信号时序(如下图)
信号时序图
图中的引导码前9ms为高电平后4.5ms为低电平表示红外信号的开始,是用于过滤噪声的。后面的用户码和键位码组成的32位信号才是表征键位的,键数据反码主要起到验证信号真伪的作用。

而用户编码的组成方式很有意思,图上读入的低(高)八位的用户编码的1、2、3、4…位 是真正的低(高)用户编码的8、7、6、5…位,键位码也一样。

注意:信号读入后经过接收器处理,高低电平会倒置(如下图)在这里插入图片描述

其次,信号读入的关键在0、1的判别。0、1在红外遥控信号中用一组高低电平表示,其区别在于“接收解码”中高电平的持续时间(即宽度),在DT9122D遥控器上0持续0.56ms,1持续1.69ms,思路是每次接收完位信号前半段的低电平,并接收的高点平后延时tms(0.56ms<t<1.69ms),之后若信号仍为高电平则该位为1反之为0。

下面是具体代码实现。

准备工作

数码管显示模块我抄我自己

#define date P0//用于数码管显示
#define place P2//用于数码管显示
typedef unsigned int u16;
typedef unsigned char u8;
sbit IRIN=P3^2;//红外信号i/o,利用了外部中断
u8 code number[]={0x28,0x7e,0xa2,0x62,0x74,0x61,0x21,0x7a,0x20,0x60,0x30,0x25,0xa9,0x26,0xa1,0xb1};
//数码管显示字库
u8 code where[]={0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//数码管显示位库
u8 k1,k2;//记录用户码
void delay(u16 num){
	u16 i,j;
	for(i=1;i<=num;++i)
	for(j=110;j>0;--j)
	;
}

void display(u16 x,u16 y){//第x个数码管显示数字y(1、2...a、b...f)
    place=where[x];
		delay(2);
		date=number[y];
		delay(2);
	  date=0xff;
}

void initalize(void){//初始化函数
	IRIN=1;//因为引导码一开始是0,所以置1
	TCON=0x01;//设置外部中断方式
	TMOD=0x10;//设置T1定时
	EA=1;//总中断开启
	EX0=1;//外部中断开启
}

延时代码

为了信号读入的精确,将51芯片内置的T1定时/计数器作为参照。(推荐使用单片机小精灵)
*不使用T1的中断

在信号读入中需要三个延时:引导码判别9ms、引导码结束4.5ms、位布尔判别(取0信号和1信号宽度的中值为佳)0.84ms

void time_9000us(void)
{
    TH1 = 0x0DC;//(0xff-9000)
    TL1 = 0x0D8;
    TR1 = 1;//开始计时
	  while(!TF1);//溢出标识
	  TF1=0;//手动重置
	  TR1=0;
}
void time_4500us(void)
{
    TH1 = 0x0EE;
    TL1 = 0x6C;
    TR1 = 1;
	  while(!TF1);
	  TF1=0;
	  TR1=0;
}

void time_840us(void)
{
    TH1 = 0x0FC;
    TL1 = 0x0B8;
    TR1 = 1;
	  while(!TF1);
	  TF1=0;
	  TR1=0;
}

八位数据读入

关键是时序、时序和时序

u8 get_code(void){
	u8 n;
	static temp=0;
	for(n=0;n<8;n++){
		while(!IRIN);//等到低电平的宽度结束
		time_840us();
		if(IRIN){
			temp=(0x80|(temp>>1));// 将temp的其余位右移,第一位置1
			while(IRIN);//准备读入下一位起始的低电平
		}
		else
			temp=(0x00|(temp>>1));//同理
	}
	return temp;	
}

外部中断

*注意对中断开关的操作。

void interr(void) interrupt 0{
  u8 a1,a2,n1,n2;//32位数据
	EA=0;//关闭中断,防止干扰
	time_9000us();
	if(!IRIN){//若引导码错误则说明是干扰信号
	  EA=1;
		return;
	}
	while(!IRIN);//以防万一的小设计
	time_4500us();
	if(IRIN){
	  EA=1;
		return;
	}
	a1=get_code();//低八位用户码
	a2=get_code();//高八位用户码
	n1=get_code();//机器码
	n2=get_code();//机器反码
	if(n1!=~n2){//利用反码判断真伪
	  k1=14;
		EA=1;
	  return;
	}
  k1=n2;//用于显示
	k2=a2;//同上
	EA=1;
}

无聊的土味main

void main(){
  initalize();//初始化
  while(1){
	  display(1,((k1&0xf0)>>4)&0x0f);//我随意找了一些位显示
	  display(2,(k1&0x0f));
	}
}

附上效果图:
在这里插入图片描述
在这里插入图片描述

发布了4 篇原创文章 · 获赞 4 · 访问量 202

猜你喜欢

转载自blog.csdn.net/SuperRabbit007/article/details/104310084