找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1366|回复: 5
收起左侧

51单片机红外解码程序哪里错了?

[复制链接]
ID:751320 发表于 2021-9-13 22:41 | 显示全部楼层 |阅读模式
实验目的:利用计数器0和外部中断0进行红外解码,将20键红外遥控器键码显示在两位数码管上
遇到问题:将hex文件下载到单片机按下按键数码管显示键码与遥控器键码不一致。例如按下按键“+”,数码管显示41,但是正确键码为40;又如按下遥控器播放按钮,数码管显示1C,标准键码为15.
请论坛各位前辈大佬帮我看看是哪里出错误了,谢谢
单片机程序代码如下:
  1. #include <REGX52.H>

  2. sbit IR_INPUT=P3^2;                                        //红外接收引脚
  3. unsigned char ircode[4];                //红外代码接收缓冲区
  4. unsigned char NixeTable[]=   //共阴数码管键码
  5. {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
  6. 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

  7. /*软件生成的延时函数,延时xms*/
  8. void Delay(unsigned int xms)                //@12.000MHz
  9. {
  10.         unsigned char i, j;

  11.         while(xms--)
  12.         {
  13.                 i = 12;
  14.         j = 169;
  15.         do
  16.         {
  17.                 while (--j);
  18.         } while (--i);
  19.         }
  20.         
  21. }

  22. /*数码管显示函数,用两位数码管显示红外控制码*/
  23. void Nixie(unsigned char Location,Number)
  24. {
  25.         switch(Location)  //位选
  26.         {
  27.                 case 1:
  28.                         P2_4=1;P2_3=1;P2_2=1;break;
  29.                 case 2:
  30.                         P2_4=1;P2_3=1;P2_2=0;break;
  31.         }
  32.         P0=NixeTable[Number];                        //段选
  33.         Delay(1);                                                                        //这里没有延时数码管会很暗
  34.         P0=0x00;                                                                        //消隐
  35. }

  36. /*计数器0初始化函数*/
  37. void Timer0_Init(void)               
  38. {
  39.         TMOD &= 0xF0;                //设置定时器模式
  40.         TMOD |= 0x01;                //设置定时器模式
  41.         TL0 = 0;                //设置定时初值
  42.         TH0 = 0;                //设置定时初值
  43.         TF0 = 0;                //清除TF0标志
  44.         TR0 = 0;                //定时器0不计时
  45. }

  46. /*外部中断0初始化函数*/
  47. void Int0_Init(void)
  48. {
  49.         IT0=1;                        //设置INT0下降沿触发
  50.         IE0=0;                        //清空外部中断0中断请求标志位
  51.         EX0=1;                        //打开外部中断0
  52.         EA=1;                                //打开总中断开关
  53.         PX0=1;                        //设置外部中断优先级
  54. }


  55. /*获取高电平时间*/
  56. unsigned int GetHighTime()
  57. {
  58.         TH0=0;                                                                                //清零T0计数器初值
  59.         TL0=0;
  60.         TR0=1;                                                                                //启动T0计数
  61.         while(IR_INPUT)                                                //红外输入引脚为1时循环检测等待,遇到下降沿时结束循环
  62.         {
  63.                 if(TH0>=0x40) {break;}        //当T0计数值大于18ms强制退出,避免程序死在这里
  64.         }
  65.         TR0=0;                                                                                //停止计数
  66.         return(TH0*256+TL0);                        //计数值合成16位整形数
  67. }

  68. /*获取低电平时间*/
  69. unsigned int GetLowTime()
  70. {
  71.         TH0=0;
  72.         TL0=0;
  73.         TR0=1;
  74.         while(!IR_INPUT)
  75.         {
  76.                 if(TH0>=0x40) {break;}
  77.         }
  78.         TR0=0;
  79.         return(TH0*256+TL0);
  80. }


  81. /*主函数*/
  82. void main()
  83. {
  84.         Timer0_Init();
  85.         Int0_Init();
  86.         while(1)
  87.         {
  88.                         Nixie(1,ircode[2]>>4);
  89.                         Nixie(2,ircode[2]&0x0F);
  90.         }
  91. }

  92. /*外部中断服务子函数,执行红外接收和解码*/
  93. void Int0_Routine() interrupt 0
  94. {
  95.         unsigned char i,j;
  96.         unsigned char byt;
  97.         unsigned int time;
  98.         
  99.         //接收并判定引导码的9ms低电平
  100.         time=GetLowTime();                                                
  101.         if((time<7833)||(time>8755))        //时间判定范围为8.5ms~9.5ms,超出范围则为误码
  102.         {
  103.                 IE0=0;                                                                                        //退出前清零INT0中断标志
  104.                 return;
  105.         }
  106.         //接收并判定引导码的4.5ms低电平
  107.         time=GetHighTime();
  108.         if((time<3686)||(time>4608))        //时间判定范围为4.0ms~5.0ms,超出范围则为误码
  109.         {
  110.                 IE0=0;                                                                                        //退出前清零INT0中断标志
  111.                 return;
  112.         }
  113.         
  114.         //接收并判定后续的4字节数据
  115.         for(i=0;i<4;i++)                                                        //循环接收4个字节
  116.         {
  117.                 for(j=0;j<8;j++)                                                 //循环接收判定每个字节的八位
  118.                 {
  119.                         time=GetLowTime();
  120.                         if((time<313)||(time>718))        //时间判定范围为340us~780us,超出范围则为误码
  121.                         {
  122.                                 IE0=0;
  123.                                 return;
  124.                         }
  125.                         time=GetHighTime();
  126.                         if((time>313)&&(time<718))        //时间判定范围为340us~780us,在此范围内说明该位为0
  127.                         {
  128.                                 byt>>=1;                                                                        //低位在先,数据右移,高位置零
  129.                         }        
  130.                         else if((time>1345)&&(time<1751)) //时间判定范围为1460us~1900us,在此范围内说明该位为1
  131.                         {
  132.                                 byt>>1;                                                                                        //低位在先,数据右移        
  133.                                 byt|=0x80;                                                                        //高位置1
  134.                         }
  135.                         else
  136.                         {
  137.                                 IE0=0;
  138.                                 return;
  139.                         }
  140.                 }
  141.                 ircode[i]=byt;                                                                                //接收完一个字节后保存到数组
  142.         }
  143.         IE0=0;                                                                                                                        //清零INT0标志
  144. }

复制代码

按下“+”数码管显示

按下“+”数码管显示

按下播放键数码管显示

按下播放键数码管显示

红外遥控器标准键码

红外遥控器标准键码


程序编译后有一个警告:

程序编译信息

程序编译信息



回复

使用道具 举报

ID:624769 发表于 2021-9-14 02:29 | 显示全部楼层
少一个 = 号

要么写成: byt >>= 1;

要么写成: byt =  byt >> 1
回复

使用道具 举报

ID:94031 发表于 2021-9-14 05:44 | 显示全部楼层
将 byt>>1 改为 byt=byt>>1
回复

使用道具 举报

ID:57657 发表于 2021-9-14 07:52 | 显示全部楼层
运算后的答案要有个去处,要么存入变量或寄存器、要么作为函数参数传递。
回复

使用道具 举报

ID:514901 发表于 2021-9-14 09:11 | 显示全部楼层
byt>>=1;
回复

使用道具 举报

ID:751320 发表于 2021-9-14 12:21 | 显示全部楼层
参考了各位大神的回答,我将程序警告语句修改成为 byt >>= 1之后,警告消失,程序顺利达到预期目的,能正确进行红外解码。谢谢各位的回答!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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