这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 我用51单片机实现红外解码的程序不能工作,啥问题呢?

共5条 1/1 1 跳转至

我用51单片机实现红外解码的程序不能工作,啥问题呢?

工程师
2021-09-14 22:23:56     打赏

实验目的:利用计数器0和外部中断0进行红外解码,将20键红外遥控器键码显示在两位数码管上
遇到问题:将hex文件下载到单片机按下按键数码管显示键码与遥控器键码不一致。例如按下按键“+”,数码管显示41,但是正确键码为40;又如按下遥控器播放按钮,数码管显示1C,标准键码为15.


请论坛的各位前辈、大佬帮我看看是哪里出错误了,谢谢!



我的单片机程序代码如下:

#include <REGX52.H>


sbit IR_INPUT=P3^2;                                        //红外接收引脚

unsigned char ircode[4];                //红外代码接收缓冲区

unsigned char NixeTable[]=   //共阴数码管键码

{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};


/*软件生成的延时函数,延时xms*/

void Delay(unsigned int xms)                //@12.000MHz

{

        unsigned char i, j;


        while(xms--)

        {

                i = 12;

        j = 169;

        do

        {

                while (--j);

        } while (--i);

        }

        

}


/*数码管显示函数,用两位数码管显示红外控制码*/

void Nixie(unsigned char Location,Number)

{

        switch(Location)  //位选

        {

                case 1:

                        P2_4=1;P2_3=1;P2_2=1;break; 

                case 2:

                        P2_4=1;P2_3=1;P2_2=0;break;

        }

        P0=NixeTable[Number];                        //段选

        Delay(1);                                                                        //这里没有延时数码管会很暗

        P0=0x00;                                                                        //消隐

}


/*计数器0初始化函数*/

void Timer0_Init(void)                

{

        TMOD &= 0xF0;                //设置定时器模式

        TMOD |= 0x01;                //设置定时器模式

        TL0 = 0;                //设置定时初值

        TH0 = 0;                //设置定时初值

        TF0 = 0;                //清除TF0标志

        TR0 = 0;                //定时器0不计时

}


/*外部中断0初始化函数*/

void Int0_Init(void)

{

        IT0=1;                        //设置INT0下降沿触发

        IE0=0;                        //清空外部中断0中断请求标志位

        EX0=1;                        //打开外部中断0

        EA=1;                                //打开总中断开关

        PX0=1;                        //设置外部中断优先级

}



/*获取高电平时间*/

unsigned int GetHighTime()

{

        TH0=0;                                                                                //清零T0计数器初值

        TL0=0;

        TR0=1;                                                                                //启动T0计数

        while(IR_INPUT)                                                //红外输入引脚为1时循环检测等待,遇到下降沿时结束循环

        {

                if(TH0>=0x40) {break;}        //当T0计数值大于18ms强制退出,避免程序死在这里

        }

        TR0=0;                                                                                //停止计数

        return(TH0*256+TL0);                        //计数值合成16位整形数

}


/*获取低电平时间*/

unsigned int GetLowTime()

{

        TH0=0;

        TL0=0;

        TR0=1;

        while(!IR_INPUT)

        {

                if(TH0>=0x40) {break;}

        }

        TR0=0;

        return(TH0*256+TL0);

}



/*主函数*/

void main()

{

        Timer0_Init();

        Int0_Init();

        while(1)

        {

                        Nixie(1,ircode[2]>>4);

                        Nixie(2,ircode[2]&0x0F);

        }

}


/*外部中断服务子函数,执行红外接收和解码*/

void Int0_Routine() interrupt 0

{

        unsigned char i,j;

        unsigned char byt;

        unsigned int time;

        

        //接收并判定引导码的9ms低电平

        time=GetLowTime();                                                

        if((time<7833)||(time>8755))        //时间判定范围为8.5ms~9.5ms,超出范围则为误码

        {

                IE0=0;                                                                                        //退出前清零INT0中断标志

                return;

        }

        //接收并判定引导码的4.5ms低电平

        time=GetHighTime();

        if((time<3686)||(time>4608))        //时间判定范围为4.0ms~5.0ms,超出范围则为误码

        {

                IE0=0;                                                                                        //退出前清零INT0中断标志

                return;

        }

        

        //接收并判定后续的4字节数据

        for(i=0;i<4;i++)                                                        //循环接收4个字节

        {

                for(j=0;j<8;j++)                                                 //循环接收判定每个字节的八位

                {

                        time=GetLowTime();

                        if((time<313)||(time>718))        //时间判定范围为340us~780us,超出范围则为误码

                        {

                                IE0=0;

                                return;

                        }

                        time=GetHighTime();

                        if((time>313)&&(time<718))        //时间判定范围为340us~780us,在此范围内说明该位为0

                        {

                                byt>>=1;                                                                        //低位在先,数据右移,高位置零

                        }        

                        else if((time>1345)&&(time<1751)) //时间判定范围为1460us~1900us,在此范围内说明该位为1

                        {

                                byt>>1;                                                                                        //低位在先,数据右移        

                                byt|=0x80;                                                                        //高位置1

                        }

                        else

                        {

                                IE0=0;

                                return;

                        }

                }

                ircode[i]=byt;                                                                                //接收完一个字节后保存到数组

        }

        IE0=0;                                                                                                                        //清零INT0标志

}





关键词: 单片机     红外     解码     中断    

工程师
2021-09-14 22:47:08     打赏
2楼
少一个 = 号
要么写成: byt >>= 1;
要么写成: byt =  byt >> 1



工程师
2021-09-14 22:54:51     打赏
3楼
运算后的答案要有个去处,要么存入变量或寄存器、要么作为函数参数传递。



工程师
2021-09-14 23:52:34     打赏
4楼

学到了


工程师
2021-09-15 23:45:38     打赏
5楼

问题还是蛮大的


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]