首页 > 单片机练习-RC-5红外遥控器程序及简单制造DIY PC遥控器

单片机练习-RC-5红外遥控器程序及简单制造DIY PC遥控器

本程序采用的芯片为SAA3010, 参考资料有:

1. 常用红外遥控接收头引脚图解

2. 红外遥控编码资料

3. RC-5红外遥控程序

4. GIRDER中文教程与电脑遥控器制作资料

5. Girder网站 (一个需要钱买的遥控)

6. 再度出击,20元打造经典PC遥控器!

7. SAA3010 DataSheet



这次主要是完成单片机接收红外摇控器发出的数据. 在此基础上, 我们可DIY出自己的PC摇控器, 也可自行发挥一些, 做出类似于很多Club里的点歌系统的硬件外红信号转换装置....



本次实验依旧采用TX-1B实验板, 只需增加一个一体化红外接收头, 如下图:





本程序中, DataOut引脚接到P3.2口. 在接收头的电源和地端接上滤波电容会使误码率更加低....



SAA3010芯片:





(图中位时间1.688ms, 而根据DataSheet里描述的位时间为1.788ms,  但实际中我使用的时间为1.651ms )



我使用的键盘编码如下:



键盘外观:



编码:





一体化红外接收头的数据输出的判断思路: (手画, 太难看也别见怪:) )

Tb = 1.778ms = 1.780ms (实际中测试为1.651ms)

T1/4b = 445us (实际中413ms)

T3/4b = 1.335ms (实际1.239ms)





在等待第一次低电平到来后, 定时器开始第一次定时T1/4b时间, 然后到达第一次数据的T3/4b时刻, 读取该位电平状态;

以后定时器每次定时Tb时间, 这样到达对应每位的T3/4时刻, 并可读取该位电平状态.



具体逻辑请看代码中的详细注释:

 采用程序查询方式:

SAA3010_RC5

//接收红外遥控器(Infrared remote control transmitter)发出的数据

//芯片型号: SAA3010, 它采用RC-5协议

//芯片资料: http://www.alldatasheet.com/datasheet-pdf/pdf/18953/PHILIPS/SAA3010.html



//利用与P1口相连的发光二极管输出接收到的按键对应码, 并将它输出到串口, 用于遥控

//PC使用了Girder来触发自定义的功能



#include 
"reg51.h"

#include 
" intrins.h "



#define uchar unsigned char



/*********************IRC RC-5****************************************/



uchar YKDatas[
3];   //遥控码(一帧14位),YKDatas[0]: 0,1为start bits, 2 为control bit, YKtype=0

                    
//YKDatas[1]: 3~7为system bits, YKtype=1

                    
//YKDatas[2]: 8~13为command bits, YKtype=2

sbit YKIn = P3^2;     //数据输入位



uchar YKcount, YKtype;            
//遥控已接收位数, 一帧的各段标志

bit YKend; //接收结束标志



//延时 a * 1ms

void delayMs(unsigned int a)

{

    unsigned 
int i, j;

    
for(i = a; i > 0; i--)

        
for(j = 100; j > 0; j--);

}



void YKInit()                  //遥控接收初始化

{

    YKDatas[
0= YKDatas[1= YKDatas[2= 0;

    YKcount 
= 0;

    YKtype 
= 0;

    YKend 
= 0;

}



void time0() interrupt 1 

{

    
//第一次进入中断前, 定时1/4位的时间:445us, 以后则定时一位时间1.778ms

    
//即在3/4位时间时, 判断该位是1还是0

    
//实际测试中, 位时间只在1.651ms(+- 1ms), 定时1/4位的时间:413us

    bit in = ~YKIn; //一体化解码后, 有载频部分变为低电平, 即低电平实际为1, 高电平实际为0

    
//设置定时器初值

    
//模式1: TH0 = (2^16 - (1651/1.085)) / 2^8 = (65536 - 1651/1.085) / 256 =  250;

    
//TL0 = (65536 - 1651/1.085) % 256 = 14

    TH0 = 250;

     TL0 
= 14;

    

    YKDatas[YKtype] 
= YKDatas[YKtype] | in//将数据放入最低位

    YKcount++;

    
if(YKcount == 3//获取完Start bits 和control bit, 共3位

    {

        YKtype 
= 1;

    }

    
else if(YKcount == 8//获取完system bits, 共5位

    {

        YKtype 
= 2;

    }

    
else if(YKcount == 14//获取完commond bits, 共6位

    {

        YKtype 
= 3;

    }

    
else if(YKtype == 3//等待最后1/4位时间结束, 实际延时1位时间

    {

        YKend 
= 1;

        YKcount 
= 0;

        YKtype 
= 0;

        TR0 
= 0//接收结束, 停止定时器0

        return

    }

    
else  //将数据左移一位, 以便将一下位数据并于最低位

    {

        YKDatas[YKtype] 
= YKDatas[YKtype] << 1;

    }

}



/*********************IRC RC-5****************************************/





/*********************RS232****************************************/

//初始化串口

void RSInit()

{

    TMOD 
|= 0x20//T1工作方式2

    TH1 = TL1 = 0xfd//装入初值, 以后是自动重载的8位计数器

    TR1 = 1//启动T1

    SM0 = 0;

    SM1 
= 1//方式1

    REN = 1//允许接收

    EA = 1;    //开中断

    ES = 1//允许串口中断

    PCON = 0x00//串口波特率不加倍. 即设置SMOD = 0;

}



//写一字节数据到串口, 使用程序查询方式检测发送情况

void RsWriteByte(unsigned char byte)

{

    ES 
= 0//关中断

    SBUF = byte;

    
while(!TI); //检测是否发送完

    TI = 0//清0发送中断标志

    ES = 1//开中断, 以允许接收数据时使用中断方式

}



void serial() interrupt 4 //串口中断是4

{

    P1 
= SBUF;

    RI 
= 0//清0接收中断标志

}



/*********************RS232****************************************/

void display() //显示接收的数据

{

    P1 
= ~YKDatas[2];

/*    switch(YKDatas[2])

    {

        case 0x3f :

        case 0x0c : RsWriteByte(YKDatas[0]); break;

        default : break;

    }
*/

//    RsWriteByte(YKDatas[1]);

    RsWriteByte(YKDatas[2]);

}





void main(void)

{

    TMOD
=0x01;                //T0选用方式1(16位定时)

    IE = 0x82//开总中断, 开定时器0中断 

    YKIn = 1;

    RSInit();

    
while(1)                

    {    

        YKInit();    

        
//模式1: TH0 = (2^16 - (413/1.085)) / 2^8 = (65536 - 381) / 256 =  255;

        
//TL0 = (65536 - 381) % 256 = 131

        TH0 = 255;

        TL0 
= 131;

        
while(YKIn); //等待低电平, 一帧开始

        TR0 = 1//启动定时器0, 接收红外遥控器发来的数据

        while(!YKend); //等待接收结束

        display();

        delayMs(
200);

    }

}





改进代码: 由原来的程序查询方式, 换成中断方式:  成功接收到数据后, 会自动调用YKSuccess()方法.

IRC_RC5_Interrupt_module

//接收红外遥控器(Infrared remote control transmitter)发出的数据

//芯片型号: SAA3010, 它采用RC-5协议

//芯片资料: http://www.alldatasheet.com/datasheet-pdf/pdf/18953/PHILIPS/SAA3010.html



//利用与P1口相连的发光二极管输出接收到的按键对应码, 并将它输出到串口, 用于遥控

//PC使用了Girder来触发自定义的功能



#include 
"reg51.h"

#include 
" intrins.h "



#define uchar unsigned char



void display();



/*********************IRC RC-5****************************************/



uchar YKDatas[
3];   //遥控码(一帧14位),YKDatas[0]: 0,1为start bits, 2 为control bit, YKtype=0

                    
//YKDatas[1]: 3~7为system bits, YKtype=1

                    
//YKDatas[2]: 8~13为command bits, YKtype=2

sbit YKIn = P3^2;     //数据输入位

uchar YKcount, YKtype;            //遥控已接收位数, 一帧的各段标志



//延时 a * 1ms

void delayMs(unsigned int a)

{

    unsigned 
int i, j;

    
for(i = a; i > 0; i--)

        
for(j = 100; j > 0; j--);

}



//重置所有数据

void YKReset()

{

    delayMs(
200); //去重复

    YKDatas[0= YKDatas[1= YKDatas[2= 0;

    YKcount 
= 0;

    YKtype 
= 0;

    EX0 
= 1//开外部中断0, 检测是否有数据输入

}



void YKInit()                  //遥控接收初始化

{

    TMOD 
= 0x01;                //T0选用方式1(16位定时)

    IE = 0x82;                  //开总中断, 开定时器0中断 

    YKIn = 1;

    YKReset();

}



void YKSuccess()  //接收到数据后会自动被调用

{

    display();

    YKReset();

}



void ex0() interrupt 0

{

    EX0 
= 0;  //关闭外部中断0

    
//模式1: TH0 = (2^16 - (413/1.085)) / 2^8 = (65536 - 381) / 256 =  255;

    
//TL0 = (65536 - 381) % 256 = 131

    TH0 = 255;

    TL0 
= 131;

    TR0 
= 1;  //启动定时器0, 定时1/4位周期

}



void time0() interrupt 1 

{

    
//第一次进入中断前, 定时1/4位的时间:445us, 以后则定时一位时间1.778ms

    
//即在3/4位时间时, 判断该位是1还是0

    
//实际测试中, 位时间只在1.651ms(+- 1ms), 定时1/4位的时间:413us

    bit in = ~YKIn; //一体化解码后, 有载频部分变为低电平, 即低电平实际为1, 高电平实际为0

    
//设置定时器初值

    
//模式1: TH0 = (2^16 - (1651/1.085)) / 2^8 = (65536 - 1651/1.085) / 256 =  250;

    
//TL0 = (65536 - 1651/1.085) % 256 = 14

    TH0 = 250;

    TL0 
= 14;

    

    YKDatas[YKtype] 
= YKDatas[YKtype] | in//将数据放入最低位

    YKcount++;

    
if(YKcount == 1 || YKcount == 2)

    {

        
if(in == 0)  //起始两位必须都为1

        {

            TR0 
= 0;

            EX0 
= 1;

            
return;

        }

    }

    
if(YKcount == 3//获取完Start bits 和control bit, 共3位

    {

        YKtype 
= 1;

    }

    
else if(YKcount == 8//获取完system bits, 共5位

    {

        
if(YKDatas[1!= 0//系统码全为0才是正确的

        {

            TR0 
= 0;

            EX0 
= 1;

            
return;

        }

        YKtype 
= 2;

    }

    
else if(YKcount == 14//获取完commond bits, 共6位

    {

        YKtype 
= 3;

    }

    
else if(YKtype == 3//等待最后1/4位时间结束, 实际延时1位时间

    {

        TR0 
= 0//接收结束, 停止定时器0

        YKSuccess();

        
return

    }

    
else  //将数据左移一位, 以便将一下位数据并于最低位

    {

        YKDatas[YKtype] 
= YKDatas[YKtype] << 1;

    }

}



/*********************IRC RC-5****************************************/





/*********************RS232****************************************/

//初始化串口

void RSInit()

{

    TMOD 
|= 0x20//T1工作方式2

    TH1 = TL1 = 0xfd//装入初值, 以后是自动重载的8位计数器

    TR1 = 1//启动T1

    SM0 = 0;

    SM1 
= 1//方式1

    REN = 1//允许接收

    EA = 1;    //开中断

    ES = 1//允许串口中断

    PCON = 0x00//串口波特率不加倍. 即设置SMOD = 0;

}



//写一字节数据到串口, 使用程序查询方式检测发送情况

void RsWriteByte(unsigned char byte)

{

    ES 
= 0//关中断

    SBUF = byte;

    
while(!TI); //检测是否发送完

    TI = 0//清0发送中断标志

    ES = 1//开中断, 以允许接收数据时使用中断方式

}



void serial() interrupt 4 //串口中断是4

{

    P1 
= SBUF;

    RI 
= 0//清0接收中断标志

}



/*********************RS232****************************************/



void display() //显示接收的数据

{

    P1 
= ~YKDatas[2];

    RsWriteByte(YKDatas[
2]);

}





void main(void)

{

    YKInit(); 

    RSInit();

    
while(1);

}





效果图:

按下9键:





PC上利用Girder响应事件:



转载于:https://www.cnblogs.com/fengmk2/archive/2007/04/01/Infrared_remote_control_transmitter_rc5.html

更多相关:

  • 中断延迟  (Interrupt Latency) 中断延迟 是指从硬件中断发生到开始执行中断处理程序第一条指令之间的这段时间。 也就是: 计算机接收到中断信号到操作系统作出响应,并完成换到转入中断服务程序的时间。 不严格地,也可以表述为: (外部)硬件(设备)发生中断,到系统执行中断服务子程序(ISR)的第一条指令的时间。...

  • 系统环境 (一)  硬件环境 CPU:S3C4510B SDRAM:W981216DH 16M FLASH:MX29LV160AB 2M (二)  软件环境 tornado2.01 for arm(AKA的FTP上有tornado2.2需要的可以自己去下载:)) (三)  调试环境...

  • 点击打开链接 一,linux软中断的概念软中断(softirq)常常表示可延迟函数的所有种类,目前linux上使用的软中断个数是有限的,linux最多注册32个,目前使用了10个,在interrupt.h中定义,中断上下文:表示内核当前正在执行一个中断处理程序或者一个可延迟函数。软中断(即使同一类型的软中断)可以并发运行在多个CPU上...