打印

8051红外解码(汇编语言)超级精简

[复制链接]
2535|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
erhohen|  楼主 | 2013-9-21 08:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 erhohen 于 2013-9-27 08:20 编辑

/*        --------------------------------------------------------------------------------------
         ; PT2221发送的红外编码最前面为13.5ms的引导码,而后为32位的数据,32位数据的前16位为用户码,      
   ;用于区别各个厂家的遥控器的不同,而后16位为数据码,分前8位和后8位,前后8位互为反码,用于检验   
   ;这里我们接收了32位的数据, 【用户码】、【用户反码】;【操作码】、【操作反码】   
   ;一体化接P0.0,  我用的是查询P0.0这个普通IO口检测红瓦信号的。   
   ;数码管: P1口送段码,     
   ;程序中采用12M晶振        
--------------------------------------------------------------------------------------*/        
            ORG 0000H
            AJMP MAIN     ;转入主程序
MAIN:   
   SETB IT0  ;设定的触发方式(CLA IT0也行,反正设置了IT0就行)。(没有这个条指令,就会没反应)                        
             ;我纳闷的地反是这里,我根本没有使用什么中断,要设置IT0干嘛?               
        
        SETB P0.0
        JNB  P0.0,$                 
        ACALL  DECODE_START              
DECODE_START:            
        MOV R6,#10
LOOP:   ACALL Delay_882uS    ;调用882微秒延时子程序
        JB P0.0,EXIT               ;延时882微秒后判断P0.0脚是否出现高电平如果有就退出解码程序,
                             ;(882uS就出现高电平说明是干扰信号)
        DJNZ R6, LOOP        ;重复10次,目的是检测在8820微秒内如果出现高电平就退出解码程序
        ;=======以上完成对遥控信号的9ms的初始低电平信号的识别======================
        JNB P0.0, $                ;等待高电平避开9毫秒低电平引导脉冲
        ACALL Delay_4740uS   ;延时4.74毫秒避开4.5毫秒的结果码
        ;==============到此为止,已跳过13.5ms的引导码=====================
        MOV R1,#1AH               ;设定1AH为起始RAM区
        MOV R2,#4            ;接收从1AH到1DH的4个内存,用于存放:
                         ;【用户码】、【用户反码】;【操作码】、【操作反码】
        
SHIFT8BIT:  MOV R3,#8    ;每组数据为8位
BIT_DETECT:   
        JNB P0.0,$           ;等待地址码第一位的高电平信号
        LCALL Delay_882uS    ;高电平开始后用882微秒的时间尺去判断信号此时的高低电平状态
        MOV C,P0.0           ;将P0.0引脚此时的电平状态0或1存入C中
        JNC STORE_DATA       ;如果为0就跳转到STORE_DATA
        LCALL Delay_1mS      ;检测到高电平1的话延时1毫秒等待脉冲高电平结束,然后把C中的1存入R1
STORE_DATA:   
        MOV A,@R1            ;将R1中的数据给A
        RRC A                ;将C中的值0或1移入A中的最低位
        MOV @R1,A            ;将A中的数暂时存放在R1数值的内存中
        DJNZ R3,BIT_DETECT   ;接收满8位换一个内存
        INC R1               ;对R1中的值加1,换下一个RAM
        DJNZ R2,SHIFT8BIT    ;接收完8位数据码和8位数据反码,存放在1AH/1BH中

       ;==================上面的程序已完成了32位数据码的接收工作,下面进行检验==================
                MOV A,1CH
                CPL A         ;对1AH取反后和1BH比较
                CJNE A,1DH,EXIT       ;如果不等表示接收数据发生错误,放弃
;====================校验正确则继续执行下面程序,不正确则作为干扰丢弃===================
                MOV P1,1CH           ;操作码传P1口
                CPL P0.1      ; P0.0口上的LED闪烁一次,表示解码成功
                 ;==================退出子程序,解码出错时退出解码子程序========================
EXIT:   RETI          ;退出解码子程序
   
     ;=============延时子程序1,精确延时882微秒=======================================        
Delay_882uS:    ;MOV R4,#17    ;11.0592M晶振请用此句延时
                MOV R4,#20           ;12M晶振请用此句延时
        D1:     MOV R5,#20
        DJNZ R5,$
        DJNZ R4,D1
        RET
        ;============延时子程序2,精确延时4740微秒==========================================
Delay_4740uS:    MOV R4,#10
        D2:     ;MOV R5,#217   ;11.0592M晶振请用此句延时
                 MOV R5,#235    ;12M晶振请用此句延时
                 DJNZ R5,$
                 DJNZ R4,D2
                 RET
     ;=============延时程序3,精确延时1000微秒===========================================
Delay_1mS:    MOV R4,#2
     D3:     ;MOV R5,#230   ;11.0592M晶振请用此句延时
              MOV R5,#248    ;12M晶振请用此句延时
              DJNZ R5,$
              DJNZ R4,D3
              RET
        ;=========================
        END

相关帖子

沙发
erhohen|  楼主 | 2013-9-21 10:18 | 只看该作者
SETB IT0  ;这个指令不用为什么不行?

使用特权

评论回复
板凳
otheric| | 2013-9-21 11:02 | 只看该作者
不懂路过,你外接什么电路:lol,

使用特权

评论回复
地板
很忙| | 2013-9-21 11:11 | 只看该作者
你这个玩玩可以,大学实习可以,但是用在商品上就麻烦了。如果只有这个接遥控的功能,没有其他的代码也还好点,但是如果有其它的功能。那这个就是一个很不稳定的东西,没有什么可以移植性。首先你不用中断的话,可能遥控信号过来了,你还在执行别的代码,没有判断信号。还有就是你接收的时候,如果中断过来了,系统去处理中断信号了,等中断返回的时候,32位数据可能被丢掉了几个字节也可能。也可能把1判断为0了。呵呵!!!

使用特权

评论回复
5
yirongfu| | 2013-9-21 11:13 | 只看该作者
RETI是中断返回用的,会涉及堆栈操作,这个程序设计思路比较有意思。

ACALL  DECODE_START              
DECODE_START:   
这样用感觉很有C语言特色

按照程序结构,“SETB IT0  ;”刚好放在了/INT0的ROM入口位置,兴许后面有了个RETI让程序反倒正常了(假设如楼主所言此程序运行正常的话)

高深

使用特权

评论回复
6
林志财| | 2013-9-21 12:12 | 只看该作者
看汇编真的头晕

使用特权

评论回复
7
erhohen|  楼主 | 2013-9-23 20:10 | 只看该作者
本帖最后由 erhohen 于 2013-9-23 20:11 编辑
yirongfu 发表于 2013-9-21 11:13
RETI是中断返回用的,会涉及堆栈操作,这个程序设计思路比较有意思。

ACALL  DECODE_START              

:D  我也是参考别人的再改改的。 我试过以下方式:(1)将RETI改成 RET,SETB IT0  保留,程序解码运行完全正确。(2)将RETI改成 RET,SETB IT0  删除,程序不运行了。        

使用特权

评论回复
8
erhohen|  楼主 | 2013-9-23 20:15 | 只看该作者
很忙 发表于 2013-9-21 11:11
你这个玩玩可以,大学实习可以,但是用在商品上就麻烦了。如果只有这个接遥控的功能,没有其他的代码也还好 ...

你说得很对的,这种解码方式会占用很多系统时间。目前我正在寻找别的方法。  因为我是打算用PIC12F508编写,这个IC没有定时中断,也没有外部中断,所以挺郁闷的,

使用特权

评论回复
9
erhohen|  楼主 | 2013-9-23 20:17 | 只看该作者
本帖最后由 erhohen 于 2013-9-27 08:21 编辑
林志财 发表于 2013-9-21 12:12
看汇编真的头晕

呵呵,确实是,我从新用c语言编了个,烧录进单片机去了,稳定运行,你可以看看,欢迎批评指正
#include "reg52.h"
#include "intrins.h"

sbit led=P0^1;
sbit IR=P0^0;
int IR_CODE[4];
void Delay882us()                //@12.000MHz
{
        unsigned char i, j;

        i = 2;
        j = 180;
        do
        {
                while (--j);
        } while (--i);
}

void Delay1ms()                //@12.000MHz
{
        unsigned char i, j;

        i = 2;
        j = 239;
        do
        {
                while (--j);
        } while (--i);
}


void Delay740us()                //@12.000MHz
{
        unsigned char i, j;

        i = 2;
        j = 109;
        do
        {
                while (--j);
        } while (--i);
}



IR_ISR()
{  
  char i,n,m;
  i=0;
  n=0;
  m=0;
  for(i=0;i<6;i++)        //延时882微秒后判断P0.0脚是否出现高电平如果有就退出解码程序,(882um就出现高电平说明是干扰信号)
  {                                        //重复10次以内,目的是检测在8820微秒内如果出现高电平就退出解码程序
    Delay882us();
        if(1==IR) return;
          }
  //=======以上完成对遥控信号的9ms的初始低电平信号的识别======================
  
  while(0==IR);//等待高电平避开9毫秒低电平引导脉冲
  Delay1ms();  //延时4.74毫秒避开4.5毫秒的结果码
  Delay1ms();
  Delay1ms();
  Delay1ms();
  Delay740us();  
//==============到此为止,已跳过13.5ms的引导码=====================

//===============下面开始解码=====================================
    for(n=0;n<4;n++)//为什么是4次?
     {
      for(m=0;m<8;m++) //为什么是8次?
                        {
                           while(0==IR);
               Delay882us();
                           
                           IR_CODE[n]>>=1;
                        
                         if(0==IR){            IR_CODE[n]=IR_CODE[n]|0x00; }

                           if(1==IR){Delay1ms(); IR_CODE[n]=IR_CODE[n]|0x80; }
                        
                        }
            }
//====解码结束,得到【用户码】【用户反码】【操作码】【操作反码】=====         

      if(0x46==IR_CODE[2]) {led=0; P1=IR_CODE[2];}
      if(0x15==IR_CODE[2]) {led=1; P1=IR_CODE[3];}
          P1=IR_CODE[2];
}


void main()
{
          led=0;
           P1=0xFF;
    while (1)
    {
                  if(0==IR) IR_ISR();      
    }
}

使用特权

评论回复
10
很忙| | 2013-9-24 08:57 | 只看该作者
楼主还不错,汇编和C都会,这样对理解问题有很大的好处。没有中断的MCU我没有用过,像你C这样写也是没有避免占用系统时间多的问题。你的这个遥控处理只能算是一个应用,遥控还有一个功能就是REPEAT,就是一个按键一直按住不放。开始发的是正常的遥控码,后面你就接收不到了,后面的码是一个特殊的波形。就像家里电视机的遥控音量一样,你一直按住音量键,音量会一直加上去,你松开按键,音量就停下来。如果用你这个思想做这个功能,那完蛋了,一个按键长按住,整个系统其它的没有办法跑了。你有空把重复按键的功能也实现下。

使用特权

评论回复
11
outstanding| | 2013-9-24 09:12 | 只看该作者

使用特权

评论回复
12
xpt| | 2013-9-25 17:30 | 只看该作者
程序都是由简入繁的,先把基本功能搞透,再完善。以后碰到应用时就容易了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

44

帖子

1

粉丝