当前位置: 首页 > 编程日记 > 正文

单片机练习-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

相关文章:

《iOS9开发快速入门》——导读

本节书摘来自异步社区《iOS9开发快速入门》一书中的目录&#xff0c;作者 刘丽霞 , 邱晓华&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 目 录前 言 第1章 iOS 9开发概述 1.1 iOS 9新特性 1.2 构建开发环境—Xcode 7.0 1.3 编写第一个iOS 9应用 1.4 小…

C#语言与面向对象技术(4)

本图文主要掌握以下问题&#xff1a; 1. 为什么要引入属性的概念&#xff1f; 2. 属性的get与set方法是怎样定义的&#xff1f; 3. 什么是索引器&#xff1f; 4. 索引器是如何实现的&#xff1f;

使用wsdl2java命令生成webservice本地调用代码

使用wsdl2java命令生成webservice本地调用代码 如果没有设置环境变量&#xff0c;就要先进入cxf的bin目录 例子&#xff1a; wsdl2java -d . http://localhost:7890/hello?wsdl 它包含以下参数&#xff1a; &#xff0d;d参数&#xff0c;指定代码生成的目录。 &#xff0d…

js表单验证大全

js验证表单大全1. 长度限制<script>function test() {if(document.a.b.value.length>50){alert("不能超过50个字符&#xff01;");document.a.b.focus();return false;}}</script><form namea οnsubmit"return test()"><textarea…

《为iPad而设计:打造畅销App》——大胆创意

本节书摘来自异步社区《为iPad而设计&#xff1a;打造畅销App》一书中的大胆创意作者【英】Chris Stevens&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 大胆创意为iPad而设计&#xff1a;打造畅销App其他的应用开发者都在做什么呢&#xff1f;或许应该在应…

Matlab与线性代数 -- 对数化间隔向量

这段时间有同学给我后台留言&#xff0c;希望能够推送与Matlab相关的内容&#xff0c;本学期该微信号承担了数理系信息教研室线性代数课程内容推送和通知的任务&#xff0c;想来想去&#xff0c;就以此为契机&#xff0c;把Matlab和线性代数的内容结合起来吧&#xff0c;希望对…

ContentProvider访问问题

问题解决一&#xff1a; 写了一个类&#xff0c;实现了ContentProvider&#xff0c;在清单文件中也注册了。 <provider android:name".provider.MyProvider" android:authorities"mytest" /> 但是访问的时候出现异常&#xff1a; j…

《C++面向对象高效编程(第2版)》——3.11 类名、成员函数名、参数类型和文档...

本节书摘来自异步社区出版社《C面向对象高效编程&#xff08;第2版&#xff09;》一书中的第3章&#xff0c;第3.11节&#xff0c;作者&#xff1a; 【美】Kayshav Dattatri&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 3.11 类名、成员函数名、参数类型…

一个GDIPlus的Bug -- OutofMemory异常

今天发现 framework2.0中的一个GDIPlus的Bug: 在Form的OnPaint事件里面写如下代码&#xff1a; private void Form1_Paint(object sender, PaintEventArgs e) { Pen p new Pen(Color.Red); p.Width 1; p.DashStyle DashStyl…

前后端分离的探索(五)

文桥&#xff0c;13级机械工程系&#xff0c;机械电子工程专业&#xff0c;大四学生。在LSGO软件技术团队负责前端部分&#xff0c;本图文是介绍目前流行的前后端分离技术的第五篇&#xff08;一共六篇&#xff09;&#xff0c;希望大家能够对这块有所了解。

从一道面试题分析Thread.interrupt方法

阿里面试题&#xff1a; public class TestThread {public static void main(String[] args) {Thread t1 new Thread() {Overridepublic void run() {try {int i 0;while (i < 100000000) {// nothing}System.out.println("A1");} catch (Exception e) {System.…

对联广告,带关闭,可以移动

在网页中加入以下代码 两个图的&#xff0c;一个是关闭用到的&#xff0c;一个是广告图 <script languageJavaScript src"js/scroll.js"></script> js代码如下&#xff1a; suspendcode"<DIV idlovexin1 styleZ-INDEX: 10; LEFT: 6px; POSITION…

u一点·料:阿里巴巴1688ued体验设计践行之路. 导读

U一点料 阿里巴巴1688UED体验设计践行之路 阿里巴巴1688用户体验部著 前言 既赶路&#xff0c;也感受路 文 / 汪方进 用户体验设计师作为一个职能岗位&#xff0c;在国内互联网公司中存在已有十几年的时间了&#xff0c;早期的互联网公司设计师大都是无所不能的多面手&#xff…

Matlab与线性代数 -- 显示格式的设置

打磨一项技能最需要的就是耐心&#xff0c;我们知道做一件事情不会一蹴而就&#xff0c;需要长时间的积累。关于Matlab的打磨会持续很长的时间&#xff0c;每天学习一个知识点&#xff0c;一年下来就不得了。要有耐心&#xff0c;要有耐心&#xff0c;跟着小编每天花5分钟的时间…

java初始化顺序

java初始化顺序

值得收藏的经典网页代码(1)

1. 将彻底屏蔽鼠标右键,无右键菜单 <body οncοntextmenu"event.returnfalse"> 也可以用于网页中Table框架中&#xff1a;<table border οncοntextmenureturn(false)><td>no</table> 2.取消选取、防止复制 <body onselectstart"r…

五款漂亮的 GNOME 3.4 主题-PPA

国外著名开源网站WebUpd8已经把这五款漂亮的Gnome 3.4 的主题制作了PPA&#xff0c;可使用命令轻松实现安装。先来看看这几款主题的截图&#xff1a; adwaita-x-dark Adwaita X dark adwaita-x-light Adwaita X light evolve-gtk3 Evolve theme-ambiance-precise Ambiance-Prec…

Matlab与线性代数 -- 矩阵的加法与减法

打磨一项技能最需要的就是耐心&#xff0c;我们知道做一件事情不会一蹴而就&#xff0c;需要长时间的积累。关于Matlab的打磨会持续很长的时间&#xff0c;每天学习一个知识点&#xff0c;一年下来就不得了。要有耐心&#xff0c;要有耐心&#xff0c;跟着我们每天花5分钟的时间…

备考ocjp有感

看网上好多评论&#xff0c;说什么ocjp的证书很水&#xff0c;复习个一两天&#xff0c;背背题库就能过了。看了之后&#xff0c;有一些感想。 首先&#xff0c;有证书不代表什么&#xff0c;不能说你获得的什么证书&#xff0c;就一定有怎样的能力&#xff0c;有证书不代表什…

买了《精通spring 2.0》

刚才去书店选书&#xff0c;对比了好几本&#xff0c;最后选了这一本。听说第一版有些问题&#xff0c;不过感觉这一版本还可以。理论和实践都有所兼顾。书中的例子是spring自带的例子。转载于:https://www.cnblogs.com/chenge/archive/2007/06/06/774212.html

探索“小数”在计算机中的存储

本文介绍了小数在计算机中的存储方式&#xff0c;第一种为定点方式&#xff0c;这种方式很少遇到&#xff0c;但在Matlab中有涉及&#xff0c;见图文《Matlab与线性代数–显示格式的设置》。第二种为浮点方式&#xff0c;一个浮点数由阶码和尾数构成&#xff0c;一旦明白其中的…

《ELK Stack权威指南(第2版)》一3.8 Docker日志

本节书摘来自华章出版社《ELK Stack权威指南&#xff08;第2版&#xff09;》一书中的第3章&#xff0c;第3.8节&#xff0c;作者 饶琛琳 更多章节内容可以访问云栖社区“华章计算机”公众号查看。 3.8 Docker日志 Docker是目前大规模互联网基础架构解决方案中最热门的技术。…

为什么匿名内部类参数必须为final类型

转自&#xff1a;http://ldzyz007.iteye.com/blog/844380 基础语法&#xff1a;如果定义一个匿名内部类&#xff0c;并且希望它使用一个在其外部定的对象&#xff0c;那么编译器会要求其参数引用是final的。 1.匿名内部类肯定是局部内部类(在一个方法里面定义的内部类)&…

开始升级我的工作流系统

终于做完了自定义工作流审批系统的第一个版本&#xff0c;可以说是熬完的&#xff0c;因为真的费了不少力气。不过也慢慢发现设计和实现中的很多问题&#xff0c;便想把它改进一下&#xff0c;改为用.net2.0和sql server2005开发&#xff0c;并想遵从一定的xpdl规范来定义流程。…

《Python和Pygame游戏开发指南》——2.16 pygame.display.update()函数

本节书摘来自异步社区《Python和Pygame游戏开发指南》一书中的第2章&#xff0c;第2.16节&#xff0c;作者[美]Al Sweigart&#xff08;斯维加特&#xff09;&#xff0c; 李强 译&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 2.16 pygame.display.upda…

Matlab与线性代数 -- 数组的乘法与除法

打磨一项技能最需要的就是耐心&#xff0c;我们知道做一件事情不会一蹴而就&#xff0c;需要长时间的积累。关于Matlab的打磨会持续很长的时间&#xff0c;每天学习一个知识点&#xff0c;一年下来就不得了。要有耐心&#xff0c;要有耐心&#xff0c;跟着我们每天花5分钟的时间…

java实现线性表的顺序存储

今天复习数据结构&#xff0c;按照疯狂java&#xff0c;自己敲了一遍线性表的顺序存储&#xff0c;为了下次看方便&#xff0c;在这里保留一份。 package mysequence;import java.util.Arrays; /*** author lirui* param <T>*/ public class SequenceList<T> {priv…

.Net Framework 3.0 概述

Microsoft .NET Framework 3.0, the managed programming model for Microsoft Windows, includes the .NET Framework 2.0, Windows Presentation Foundation, Windows Communication Foundation, and Windows Workflow Foundation.Microsoft Windows托管编码模型,Microsoft .…

《ABAQUS 6.14超级学习手册》——1.2 ABAQUS分析模块

本节书摘来自异步社区《ABAQUS 6.14超级学习手册》一书中的第1章&#xff0c;第1.2节,作者&#xff1a; 齐威 更多章节内容可以访问云栖社区“异步社区”公众号查看。 1.2 ABAQUS分析模块 ABAQUS包括三个主要的分析模块&#xff1a;ABAQUS/Standard、ABAQUS/Explicit和ABAQUS/…

离散型随机变量的分布律

孔令才&#xff0c;中科院博士&#xff0c;长期致力于传染病空间传播机理的研究。非常开心&#xff0c;他能够加入进来与大家一起分享概率论与数理统计方面的知识。 微信公众平台通常让大家的知识碎片化&#xff0c;而我们要做的事情就是在学习方法论、软件开发、机器学习和数…