基于单片机红外遥控器
单片机原理及系统课程设计
专业:自动化
班级:自动化1202
姓名:
学号:201209111
指导教师:于晓英
兰州交通大学自动化与电气工程学院
2014年12 月31日
基于单片机的红外遥控器
1方案设计
1.1题目
基于单片机的红外遥控器。
1.2设计目的
通过本次设计对所学的单片机知识有更深入的了解;特别是单片机的红外发送,红外接收,中断,定时,计数,频率,矩阵键盘以及红外遥控NEC协议的理解和掌握。同时也能熟练掌握keil软件和protues仿真软件,主要目的是让我们把所学的基础知识运用到实际当中去。
1.3方案
本设计主要应用了AT89C51单片机作为核心,综合应用了单片机中断系统、定时器、计数器等知识,应用红外线的优点。遥控操作的不同,遥控发射器通过对红外线发射频率的控制来区别不同的操作。遥控接收器通过对红外光接收频率的识别,判断出控制操作,来完成整个红外遥控发射、接收过程。
发射模块:单片机不工作时一直处于低功耗状态,采用了空闲节电工作方式。当遥控器的某一按键被按下以后,外部中断1产生中断,唤醒单片机进入工作状态,查询键盘按下的是哪一个按键,当确认按键后,控制软件启动定时器T0、T1,T1作为发射时间控制器,T0作为红外线发射频率控制器,T0定时溢出时中断程序使红外管接口电平反转一次,写入定时器的初值不同,在输出端口就得到不同的发射频率。T1定时溢出时中断程序关闭T0定时器,停止红外线发射。其设计原理框图如图1所示。
接收模块;利用单片机中的T0作为红外脉冲计数器,T1作为计数时间控制器。当电路中红外接收管接收到第一个红外脉冲时,外部中断1被触发,启动计数器T0和定时器T1。定时溢出,中断程序关闭计数器T0,读入计数值并进行判断,确定操作对象(遥控按键)对其进行反转操作,控制电路对所控制的负载进行开或关。其设计原理框图如图2所示。
1.4模块图
红外发射部分对应模块图如图1所示,红外接收部对应模块图如图2所示,其功能为方案所述。
图1发射部分模块图
图2 接收部分模块图
2硬件设计
2.1单片机最小系统
单片机的最小系统是指用最少的元件组成的单片机可以工作的系统,对51
2.2
线的低为分别为p1.7,p1.3。扫描键盘时通过先扫行再扫列确定按键的位置。
P 14
P 15
P 16
P 17
P10
P11
P12
P13
图3 矩阵键盘电路
2.3红外发射电路
图4为红外发射电路,当原始信号为低电平的时候,38KHZ 载波输出,当信号为低电平的时候不发送载波。用38KHZ 的载波去装载原始信号。
图4 红外发射电路
2.4红外接收电路
图5为红外接收电路,红外接收完成对红外信号的接收、放大、检波、整形,并解调出遥控编码脉冲,为了减少干扰,采用的是一体化红外接收头,它接收的红外信号频率为38KHZ 。
Demodulator
IRL1
IRLINK
红外接收发射管
U3
NOT
图6 仿真发射接收电路
2.6接收状态反映电路
图7所示为输出状态反映电路,当按下矩阵开关的四个不同按键,继电器分别响应开关状态。
P110
P114
P135
RL1
OMIH-SH-105D
RL2
OMIH-SH-105D
Q1
PNP
R6
2.2k D6
LED-RED R7
1k
Q2
PNP
R8
1k
R9
2.2k D7
LED-RED
R10
1k
L1
5V
L2
5V
2.7整体仿真电路
图8所示为整体仿真电路,红外遥控就是把红外线作为载体的遥控方式。由于红外线的波长远小于无线电波的波长,因此在采用红外遥控方式时,不会干扰其他电器的正常工作,也不会影响临近的无线电设备。常用的红外遥控系统一般分发射和接收两个部分。当按下遥控器按钮就会产生具有不同的编码数字脉冲,这种代码指令信号调制在38kHz的截波上,激励红外光二级管产生具有脉冲串的红外波,通过空间的传送到受控机内的遥控接收器。在接收过程中,红外波信号通过光电二级管转换为38kHz的电信号,此信号经过放大、检波、整形、解调、送到解码与接口电路,从而完成相应的遥控功能。但由于proteus仿真软件无法进行无线仿真,故利用中断在单片机产生频率为38KHZ的载波信号,装载原始信号,再在接收部分进行解调。控制继电器的开关。
图8 整体仿真电路
3软件设计
3.1流程图
流程图有两部分组成,分别为发射部分和接收部分。
图9 发送部分(左)接收部分(右)流程图
3.2源程序
源程序见附录。
4系统仿真
4.1仿真截图
图9所示为整体仿真结果,按下矩阵键盘的按键,相应的会有继电器的闭合,LED灯的亮灭。
图10 整体仿真电路
参考文献
[1] 王思明,张金敏,张鑫等.单片机原理及应用系统设计.北京:科学出版社,2012.
[2] 张金敏,董海棠,高博等,单片机原理应用系统设计.成都:西南交通大学出版社,2010.
[3]谭浩强.C程序设计(第四版).北京.清华大学出版社,2010.
附录
原理图
图1 发射过程原理图
源程序
/*******************************************************************
红外发射源程序
*******************************************************************/ #include
#define uint unsigned int
#define uchar unsigned char //宏定义
#define K P1 //键盘使用管脚定义
sbit HL=P3^4;
sbit LED=P3^3; //红外管脚接口
static bit OP; //红外发射管的亮灭控制
static uint count; //延时计数器
static uint endcount; //终止延时计数器
static uchar flag; //红外发送标志
char iraddr1; //16位地址第一字节
char iraddr2; //16位地址第二字节
char Key_=0x10; //发送数据
uchar Data=0x00; //键盘参数
void SendIRdata(char p_irdata); //函数声明红外发送
uchar Key(); //键盘扫描
/********************************************************************
主函数
********************************************************************/ void main()
{ count=0;
flag=0;
OP=0;
HL=0; //初始化
EA=1; //总中断开
TMOD=0x11; //设置定时器0和1为16位模式
ET0=1; //定时器0中断允许
TH0=0xff;
TL0=0xe6; //设定定时大小38K 等加于26us中断一次
TR0=1; //开始计数
iraddr1=3;
iraddr2=252; //写16位地址
while(1) //循环发射
{ Key_=Key(); //检测按键
if(Key_!=0x10) //是否有按键按下
{ SendIRdata(Key_); //发送
Data=Key_; //读取参数显示
while(Key_!=0x10) //等待松开
{ Key_=Key();
}
}
LED=1;
}
}
/******************************************************************
定时器0中断处理函数
*******************************************************************/ void timeint(void) interrupt 1
{ TH0=0xff;
TL0=0xe6; //设定定时器初值
count++; //中断计数累加
if(flag==1)
{ OP=~OP; }
else
{ OP=0; }
HL=OP;
}
/******************************************************************
发送数据函数
*******************************************************************/ //发送的延时时间参数即(endcount)都是在12MHZ的值
void SendIRdata(char p_irdata)
{ int i;
char irdata=p_irdata;
//发送9ms的起始码
endcount=223;
flag=1;
count=0;
while(count //发送4.5ms的结果码 endcount=117; flag=0; count=0; do{}while(count //发送16位地址的前八位 irdata=iraddr1; for(i=0;i<8;i++) { //先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)endcount=10; flag=1; count=0; do{}while(count //停止发送红外信号(即编码中的高电平) if(irdata-(irdata/2)*2) //判断二进制的个位是1还是0 { endcount=41;} //1 else { endcount=15; } //0 flag=0; count=0; do{}while(count irdata=irdata>>1; } //发送16位地址的后八位 irdata=iraddr2; for(i=0;i<8;i++) { //先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)endcount=10; flag=1; count=0; do{}while(count //停止发送红外信号(即编码中的高电平) if(irdata-(irdata/2)*2) //判断二进制的个位是1还是0 { endcount=41; } //1 else { endcount=15; } //0 flag=0; count=0; do{}while(count irdata=irdata>>1; } //发送8位数据 irdata=p_irdata; for(i=0;i<8;i++) { //先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)endcount=10; flag=1; count=0; do{}while(count //停止发送红外信号(即编码中的高电平) if(irdata-(irdata/2)*2) //判断二进制的个位是1还是0 { endcount=41; } //1 else { endcount=15; } //0 flag=0; count=0; do{}while(count irdata=irdata>>1; } //发送8位数据反码 irdata=~p_irdata; for(i=0;i<8;i++) { //先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)endcount=10; flag=1; count=0; do{}while(count //停止发送红外信号(即编码中的高电平) if(irdata-(irdata/2)*2) //判断二进制的个位是1还是0 { endcount=41; } //1 else { endcount=15; } //0 flag=0; count=0; do{}while(count irdata=irdata>>1; } //结束信息 endcount=10; flag=1; count=0; do{}while(count flag=0; } /****************************************************************** 键盘扫描函数 *******************************************************************/ uchar Key() { //扫描键盘 K=0x7f; if(K==0x77) { LED=0; return 0x01; } else if(K==0x7b) { LED=0; return 0x02; } else if(K==0x7d) { LED=0; return 0x03; } else if(K==0x7e) { LED=0; return 0x0A; } //无键盘按下 else { return 0x10; } } /****************************************************************** 红外接收源程序 *******************************************************************/ #include #define uchar unsigned char //宏定义 #define uint unsigned int //时间计算 #define Imax 14000 //此处为晶振为11.0592时的取值, #define Imin 8000 //如用其它频率的晶振时, #define Inum1 1450 //要改变相应的取值。 #define Inum2 700 #define Inum3 3000 unsigned char Im[4]={0x00,0x00,0x00,0x00}; //解码变量 //全局变量 uchar Data=0x00; uchar f; unsigned long m,Tc; unsigned char IrOK; sbit LED1=P1^0; //4个输出 sbit LED2=P1^4; sbit LED3=P3^5; sbit LED4=P3^6; /****************************************************************** 外部中断解码程序_外部中断1 *******************************************************************/ void intersvr1(void) interrupt 2 { TR0=1; Tc=TH0*256+TL0; //提取中断时间间隔时长 TH0=0; TL0=0; //定时中断重新置零 if((Tc>Imin)&&(Tc { m=0; f=1; return; } //找到启始码 if(f==1) { if(Tc>Inum1&&Tc { Im[m/8]=Im[m/8]>>1|0x80; m++; } if(Tc>Inum2&&Tc { Im[m/8]=Im[m/8]>>1; m++; } //取码 if(m==32) //识别出32位 { m=0; f=0; if(Im[2]==~Im[3]) //检验反码 { IrOK=1; TR0=0; //关闭定时器 } else IrOK=0; //取码完成后判断读码是否正确 } //准备读下一码 } } /****************************************************************** 主程序 *******************************************************************/ void main(void) { m=0; f=0; EA=1; //开启总中断 IT1=1; //下降沿有效 EX1=1; //外部中断0开 TMOD=0x11; //定时器初始化 TH0=0; //T0赋初值 TL0=0; TR0=0; //t0开始计时 while(1) //循环执行 { if(IrOK==1) //如果解码成功 { IrOK=0; //清空标志位 Data=Im[2]; //赋值信息 if(Data==0x0d) //判断是哪个按键按下 LED1=!LED1; //控制开关 else if(Data==0x0c) LED2=!LED2; else if(Data==0x0b) LED3=!LED3; else if(Data==0x0a) LED4=!LED4; } } }