找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4471|回复: 4
打印 上一主题 下一主题
收起左侧

求解——红外解码,键码数码管显示问题

[复制链接]
跳转到指定楼层
楼主
ID:88716 发表于 2015-9-24 13:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*******************************infrared************************************/
#include <reg52.h>

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

bit irflag = 0;  //红外接收标志,收到一帧正确数据后置1
unsigned char ircode[4];  //红外代码接收缓冲区

void InitInfrared()
{       
        IR_INPUT = 1;    //释放红外引脚
        TMOD &= 0X0F;
        TMOD |= 0x10;         //配置定时器1定时1模式
        TR1 = 0;
        ET0 = 0;
        IT0 = 1;                  //外部 *下降沿* 产生外部中断
        EX0 = 1;
}
/*获取当前高电平的持续时间*/
unsigned int GetHighTime()                 
{
        TH1 = 0;
        TL1 = 0;
        TR1 = 1;
        while(IR_INPUT)                     //当红外引脚为1时,循环检测等待,变为0时,
        {                                                 //则结束本循环
                if(TH1 > 0x40)                 //当T1大于0x40即高电平持续时间超过约18ms时,强制退出循环,
                {                                         //是为了避免信号异常是,程序假死在这里
                        break;
                }
        }
        TR1 = 0;

        return(TH1 * 256 + TL1);
}
/*获取当前低电平的持续时间*/
unsigned int GetLowTime()
{
        TH1 = 0;
        TL1 = 0;
        TR1 = 1;
        while(!IR_INPUT)
        {
                if(TH1 > 0x40)
                {
                        break;
                }
        }
        TR1 = 0;

        return(TH1 * 256 + TL1);
}
/*外部中断INT1中断服务程序,执行红外接收及解码*/
void EXINT0_ISR() interrupt 0
{
        unsigned char i, j;
        unsigned int time;
        unsigned char byt;

        time = GetLowTime();                                   //接收并判定引导码的9ms低电平
        if((time <7833) || (time > 8755))          //时间在8.5-9.5ms内,如果不在范围内,关闭外部中断,即关闭红外接收,退出检测
        {
                IE0 = 0;
                return;       
        }

        time = GetHighTime();                             //接收并判定引导码4.5ms
        if((time<3686) || (time > 4608))   //如果接收高电平的时间不在4ms-5ms之间
        {                                                                  
                IE0= 0;                                           //关闭外部中断,退出红外检测
                return;
        }
        for(i=0; i<4; i++)                                 //如果满足上述引导码电平时间要求,进入数据0,1判定
        {
                for(j=0; j<8; j++)                         //循环8次,获取1 个字节
                {
                        time = GetLowTime();          //获取低电平时间
                        if((time<313) ||(time >718))         //判断电平时间是否在340us-780之内,因为比特值0:560us+560us的空闲
                        {                                                                 //如果不满足要求,退出外部中断服务程序
                                IE0 = 0;
                                return;
                        }                                                                                                               
                        time = GetHighTime();           //获取高电平时间(空闲时间)
                        if((time>313) && (time <718))         //判断空闲时间是否在340-780us之内,如果是的话,说明发送了1位  0
                        {
                                byt >>= 1;                                               //先获取位(0),
                        }
                        else if((time>1345) && (time<1751))                 //如果在此获取的空闲时间(高电平时间)在此范围内,说明发送了1位  1
                        {
                                byt >>= 1;                                                         //获取位1 操作
                                byt |= 0x80;
                        }
                        else                                                                 //否则 既不是发送了0 也不是发送了 1 ,无效,退出外部中断服务程序
                        {
                                IE0 = 0;
                                return;
                        }
                }
                ircode[i] = byt;
        }
        irflag = 1;
        IE0 = 0;
}
/******************************************main*****************************************/

#include <reg52.h>
#include <intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit du=P2^6;
sbit we=P2^7;
uchar num,jianma1,jianma2;
unsigned char code dofly_DuanMa[]={  0x3F,          //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义
                                };// 显示段码值0~9
unsigned char T0RH = 0;  //T0重载值的高字节
unsigned char T0RL = 0;  //T0重载值的低字节

extern bit irflag;
extern unsigned char ircode[4];
extern void InitInfrared(void);
void ConfigTimer0(unsigned int ms);
void main()
{
    EA = 1;      //开总中断,开始准备接受红外信号
    InitInfrared();   //初始化红外功能
    ConfigTimer0(1);  //配置T0定时1ms
    PT0 = 1;        //配置T0中断为高优先级,启用本行可消除接收时的闪烁

    while (1)
    {
        if (irflag)  //红外接收标志位,1表示接受完毕,
        {
            irflag = 0;
/*                        switch(ircode[2])
                        {
                         case 0x0c:num=dofly_DuanMa[1];break;//1 显示相应的按键值
                         case 0x18:num=dofly_DuanMa[2];break;//2
                         case 0x5e:num=dofly_DuanMa[3];break;//3
                         case 0x08:num=dofly_DuanMa[4];break;//4
                         case 0x1c:num=dofly_DuanMa[5];break;//5
                         case 0x5a:num=dofly_DuanMa[6];break;//6
                         case 0x42:num=dofly_DuanMa[7];break;//7
                         case 0x52:num=dofly_DuanMa[8];break;//8
                         case 0x4a:num=dofly_DuanMa[9];break;//9
                         default :break;       
                        }        */
                        jianma1=dofly_DuanMa[ircode[2] >> 4];
                        jianma2=dofly_DuanMa[ircode[2]&0x0f];
        }
    }
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;  //临时变量

    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 18;           //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
/* 数码管动态扫描刷新函数,需在定时中断中调用 */
void LedScan()
{
/*        du=1;
        P0=num;
        du=0;
        P0=0xff;
        we=1;
        P0=0xfe;
        we=0;        */
       
        du=1;
        P0=jianma1;
        du=0;
        P0=0xff;
        we=1;
        P0=0xbf;
        we=0;
        _nop_();
        du=1;
        P0=jianma2;
        du=0;
        P0=0xff;
        we=1;
        P0=0x7f;
        we=0;
        _nop_();
}
/* T0中断服务函数,执行数码管扫描显示 */
void InterruptTimer0() interrupt 1
{
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
    LedScan();   //数码管扫描显示
}
功能:讲遥控器键码显示在数码管的第7,8位。 问题:第7位数码管,显示不清楚,只是个残影,第八位数码管显示正常,无论我怎么减小延迟函数(最后用_nop_)也无法解决这个现象,求高手 帮我看看。谢谢了


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:79544 发表于 2015-9-24 18:51 | 只看该作者
你试试这个程序,改一下。
  1. /* 51单片机红外遥控解码程序 */

  2.   /* 适用uPD6121系列 */

  3.   #include

  4.   #define DIGPORT P2

  5.   #define WORDPORT P0

  6.   unsigned char code LED_num[]={0x3f,0x18,0x76,0x7c,0x59,0x6d,0x6f,0x38,0x7f,0x7d};

  7.   #define Imax 14000 //此处为晶振为11.0592时的取值,

  8.   #define Imin 8000 //如用其它频率的晶振时,

  9.   #define Inum 1450 //要改变相应的取值。

  10.   unsigned char Im[]={0x00,0x00,0x00,0x00};

  11.   unsigned long m,Tc;

  12.   unsigned char i,IrOK;

  13.   void DelayMy(unsigned int t){

  14.   while(--t);

  15.   }

  16.   void Display_LED(unsigned long num)

  17.   {

  18.   unsigned int ii;

  19.   unsigned int jj=0;

  20.   unsigned long aa,bb;

  21.   unsigned int xx[8]={0,0,0,0,0,0,0,0};

  22.   do {

  23.   bb=num/10;

  24.   aa=num-bb*10;

  25.   xx[jj]=aa;

  26.   num=bb;jj++;

  27.   }

  28.   while(num>0);

  29.   DIGPORT=0x80;

  30.   for(ii=0;ii<8;ii++) {

  31.   WORDPORT=LED_num[xx[ii]];

  32.   DelayMy(60);

  33.   DIGPORT=DIGPORT>>1;

  34.   };

  35.   WORDPORT=0;

  36.   }

  37.   //外部中断解码程序

  38.   void intersvr1(void) interrupt 2 using 1

  39.   {

  40.   Tc=TH0*256+TL0; //提取中断时间间隔时长

  41.   TH0=0; TL0=0; //定时中断重新置零

  42.   if((Tc>Imin)&&(Tc

  43.   if(Tc>Inum) Im[m/8]=Im[m/8]>>1|0x80; else Im[m/8]=Im[m/8]>>1; //取码

  44.   if(m==32) if((Im[2]|0x01)==~Im[3]) IrOK=1; else IrOK=0; //取码完成后判断读码是否正确

  45.   m++; //准备读下一码

  46.   }

  47.   /*演示主程序*/

  48.   void main(void)

  49.   {

  50.   m=0;

  51.   EA=1;

  52.   IT1=1;EX1=1;

  53.   TMOD=0x11;

  54.   TH0=0;TL0=0;

  55.   TR0=1;ET0=1;

  56.   for(;;){

  57.   DelayMy(100);

  58.   if(IrOK==1) for(i=0;i<400;i++) Display_LED(Im[2]);

  59.   IrOK=0;

  60.   }

  61.   }
复制代码
回复

使用道具 举报

板凳
ID:88716 发表于 2015-9-24 20:25 | 只看该作者
腾飞的龙 发表于 2015-9-24 18:51
你试试这个程序,改一下。

谢谢,还是想明白自己上述的程序到底哪里出了问题,放弃了,心里会不安。。。
回复

使用道具 举报

地板
ID:88716 发表于 2015-9-25 18:19 来自手机 | 只看该作者
已经解决了,取消用定时器中断程序来刷新数码管显示,直接在主函数while里不停刷新数码管就ok了
回复

使用道具 举报

5#
ID:84746 发表于 2015-9-25 23:33 来自手机 | 只看该作者
嗯摸摸摸兔兔讲解
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表