本帖最后由 nyjm2021 于 2021-3-20 16:51 编辑
我用的是51单片机,想用NEC协议的红外遥控来设置定时器,这个阶段想要实现的功能是这样的:1.数码管前4位显示ds1302芯片设置的时间(已实现)。
2.长按遥控的电源键5s(编码为0x45),定时功能打开,这时数码管前两位显示小时,后两位显示分钟,初始值都为0.(已实现)
3.再按下遥控的电源键(小于5s),代表小时的前两位闪烁。(有问题)
4.再次按下遥控的电源键(小于5s),代表分钟的后两位闪烁。(有问题)
我用计算红外遥控的连发码数量来算电源键长按下的时间,连发码一个约108ms,5s需要达到46个连发码。
最开始按下电源键,达到46个连发码时可以打开定时器,小时和分钟都不闪烁,数码管上显示00:00。再按电源键可以让小时闪烁,再按可以让分钟闪烁。但如果打开定时器后,按下的时间比较长,一直没有松开,按理说闪烁的部分是不应该有变化的,但是实际上在20个连发码的时候,闪烁的小时或者分钟会自动交换一次,等到35个连发码时又会自动交换一次,等到46个连发码时定时器没有再次打开(小时或者分钟还会闪烁),等到50个连发码以上时定时器才会重新打开。
想问下有人知道这是什么原因导致的,怎样才能改掉这个问题吗?谢谢!感觉问题应该出在EX0_ISR()函数或者ir_process()函数:————————————————————————————————————————————————
解决方案:因为每次是在到20个连发码的时候出现这个问题,所以我后来在ir_process()函数中把短按的最长时间从小于46个连发码改到了小于15个连发码,虽然没有找到这个问题出现的原因,但也让这个问题不再出现了。
下面是我的单片机main.c文件代码:
- #include "reg52.h"
- #include "ds1302.h"
- #include <intrins.h> //此文件中定义了单片机的一些特殊功能寄存器
- #define uint unsigned int //对数据类型进行声明定义
- #define uchar unsigned char
- #define ulong unsigned long
- bit timer_on_flag,hour_flash,min_flash; //定时器开启,时钟闪烁,分钟闪烁
-
- uint hour,min;
- sbit lsa = P2^4; //数码管位选
- sbit lsb = P2^3;
- sbit lsc = P2^2;
- sbit IRIN = P3^2; //红外遥控
- uint irtime; //检测红外高电平持续时间
- bit irpro_ok,irok;
- uchar IRcord[4]; //储存数据码
- uchar irdata[33]; //1引导码 8位客户1 8位客户2 8位操作码 8位操作反码
- bit shortpress; //红外遥控短按和长按
- uint long_press_time; //红外遥控连发码数量
- uchar code duan[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
- uint flag1ms,flag5ms,flag100ms;
- uchar n4,n5,n6,n7;
- uchar n0,n1,n2,n3;
- bit dig_on; //数码管打开
- void Ircordpro();
- void ir_process();
- /*------------------------------------------------------------------------------
- 数码管位选、赋值、闪烁
- ------------------------------------------------------------------------------*/
- void flash_display(uchar seta,uchar setb,uchar setc,uchar num,bit check) //数码管闪烁
- {
- static uchar flash = 0;
- lsa = seta; lsb = setb; lsc = setc;
- if(check)
- {
- if(++flash>10) flash = 0;
- else if(flash<=4) P0 = duan[num];
- else if(flash>4) P0 = 0x00;
- }else{
- P0 = duan[num];
- }
- }
- /*------------------------------------------------------------------------------
- 数码管显示
- ------------------------------------------------------------------------------*/
- void display(){
- static uchar i = 0;
- if(dig_on)
- {
- switch(i)
- {
- case 0: flash_display(1,1,1,n7,hour_flash);break;
- case 1: flash_display(1,1,0,n6,hour_flash);break;
- case 2: flash_display(1,0,1,n5,min_flash);break;
- case 3: flash_display(1,0,0,n4,min_flash);break;
- case 4: lsa = 0;lsb = 1;lsc = 1;P0 = duan[n3];break;
- case 5: lsa = 0;lsb = 1;lsc = 0;P0 = duan[n2];break;
- case 6: lsa = 0;lsb = 0;lsc = 1;P0 = duan[n1];break;
- case 7: lsa = 0;lsb = 0;lsc = 0;P0 = duan[n0];break;
- }
- i++;
- if(i>7) i=0;
- }
- else
- {
- P0 = 0x00;
- }
- }
- /*------------------------------------------------------------------------------
- 定时器1初始化
- ------------------------------------------------------------------------------*/
- void Timer1Init()
- {
- TMOD &= 0x0F; //清0 T1的控制位
- TMOD |= 0x10; //定时器1的工作方式为1
- TH1 = (65536-921)/256; //晶振频率为11.0592MHz,机器周期为12/11059200*1000000 = 1.08506944us,周期为1ms,N为1000/1.08506944 = 921.6
- TL1 = (65536-921)%256;
- EA = 1; //打开总中断
- ET1 = 1; //打开定时器1中断
- TR1 = 1; //打开定时器1
- }
- /*------------------------------------------------------------------------------
- 定时器1中断服务函数
- ------------------------------------------------------------------------------*/
- void timer1() interrupt 3
- {
- TH1 = (65536-921)/256;
- TL1 = (65536-921)%256;
- flag1ms = 1; //定时器周期为1ms
- P0 = 0x00; //消抖
- }
- /*------------------------------------------------------------------------------
- (红外)定时器0初始化
- ------------------------------------------------------------------------------*/
- void Timer0Init() //256*(1/11.0592MHz)*12 = 0.278ms
- {
- TMOD &= 0xF0; //清零T0的控制位
- TMOD |= 0x02; //定时器0工作方式2
- TH0 = 0x00; //高位初始化
- TL0 = 0x00; //低位初始化
- ET0 = 1; //定时器0中断
- TR0 = 1; //启动定时器
- }
- /*------------------------------------------------------------------------------
- (红外)外部中断0初始化
- ------------------------------------------------------------------------------*/
- void Int0Init() //外部中断0初始化
- {
- IT0 = 1; //设置外部中断0为下降沿触发
- EX0 = 1; //启动外部中断0
- EA = 1; //总中断允许
- }
- /*------------------------------------------------------------------------------
- (红外)定时器0中断服务函数
- ------------------------------------------------------------------------------*/
- void timer0() interrupt 1
- {
- irtime++; //检测脉宽,一次位278us
- }
- /*------------------------------------------------------------------------------
- (红外)外部中断0服务函数
- ------------------------------------------------------------------------------*/
- void EX0_ISR() interrupt 0
- {
- static uchar i; //把33次高电平持续时间存入irdata
- static bit startflag; //开始存储脉宽标志位
- if(startflag) //开始接收脉宽检测
- {
- if(irtime<63 && irtime>=45) //判断是否引导码,低电平9ms+高电平4.5ms
- {
- i = 0; //如果是存入irdata的第一位
- shortpress = 1;
- long_press_time = 0;
- }
- else if(irtime>33 && irtime <45) //判断是否为连发码,低电平9ms+高电平2.25ms
- {
- shortpress = 0;
- long_press_time++; //计算连发码的数量
- }
- if(shortpress)
- {
- irdata[i] = irtime;
- }
- irtime = 0; //计数清零,下一个下降沿的时候再存入脉宽
- i++; //计算脉宽存入的次数
- if(i==33) //如果存入34次
- {
- irok = 1; //脉宽检测完毕
- i = 0; //脉宽计数清零准备下次存入
- }
- }
- else
- {
- irtime = 0; //计数清零
- startflag = 1; //开始处理
- }
- }
- /*------------------------------------------------------------------------------
- (红外)码值处理函数
- ------------------------------------------------------------------------------*/
- void Ircordpro() //提取33次脉宽进行数据解码
- {
- uchar i, j, k,cord,value; //k用于33次脉宽中的哪一位
- k=1; //从第一位开始,丢弃引导码脉宽
- for(i=0;i<4;i++) //处理4个字节
- {
- for(j=1;j<=8;j++) //处理1个字节8位
- {
- cord=irdata[k]; //把脉宽存入cord
- if(cord>5) //脉宽大于11.0592的T0溢出率位约278us*5=1390那么判断为1
- {
- value=value|0x80; //接收时先接收最低位
- }
- if(j<8)
- {
- value>>=1; //value位左移依次接收8位数据
- }
- k++; //每执行一次脉宽数加一
- }
- IRcord[i]=value; //每处理完一个字节把它放入ircord数组中
- value=0; //清零value方便下次存入数据
- }
- irpro_ok=1; //接受完4个字节后irpro_ok置1表示红外解码完成
- }
- /*------------------------------------------------------------------------------
- (红外)功能实现函数
- ------------------------------------------------------------------------------*/
- void ir_process()
- {
- if(irok) //如果红外信号接收完毕
- {
- Ircordpro(); //对红外信号进行解码
- irok = 0;
- shortpress = 0;
- }
- if(irpro_ok) //如果对红外信号解码完毕
- {
- if(IRcord[2]==0x45 ) //如果按键是45H
- {
- if(long_press_time >= 46) //长按打开定时器
- {
- timer_on_flag = 1; //打开定时器
- hour = 0;
- min = 0;
- hour_flash = 0; //小时不闪烁
- min_flash = 0; //分钟不闪烁
- }
- else if( (1<=long_press_time && long_press_time <46)) //短按对时间进行选择,设置超过20时会自动跳变
- {
- if(timer_on_flag) //如果定时器处于打开状态
- {
- if(!min_flash && !hour_flash) //小时分钟均不闪烁,让小时闪烁
- {
- hour_flash = 1;
- irpro_ok = 0;
- }
- else if(hour_flash && !min_flash) //小时已经在闪烁,短按一下让分钟闪烁
- {
- hour_flash = 0;
- min_flash = 1;
- irpro_ok = 0;
- }
- else if(min_flash && !hour_flash)
- {
- hour_flash = 1; //小时没有闪烁,短按一下让小时闪烁,分钟不闪烁
- min_flash = 0;
- irpro_ok = 0;
- }
-
- }
- }
- }
- }
-
- }
- /*------------------------------------------------------------------------------
- 数码管显示内容设置函数
- ------------------------------------------------------------------------------*/
- void calculate_num()
- {
-
- n3 = long_press_time / 10;
- n2 = long_press_time % 10;
- n1 = IRcord[2]>>4;
- n0 = IRcord[2]&0x0F;
-
- if(timer_on_flag) //定时器打开,数码管显示定时的倒计时
- {
- n7 = hour / 10;
- n6 = hour % 10;
- n5 = min / 10;
- n4 = min % 10;
- }else if(!timer_on_flag) //定时器未开,数码管显示时钟芯片实时时间
- {
- Ds1302ReadTime();
- n7 = TIME[2]/16; //时
- n6 = TIME[2]&0x0f;
- n5 = TIME[1]/16; //分
- n4 = TIME[1]&0x0f;
- }
- }
- /*------------------------------------------------------------------------------
- 主函数
- ------------------------------------------------------------------------------*/
- void main( )
- {
- dig_on = 1;
- Timer0Init();
- Timer1Init();
- Ds1302Init();
- Int0Init();
- while(1)
- {
- if(flag1ms)
- {
- flag1ms = 0;
- display(); //数码管显示
- if(++flag5ms>=5) //1ms * 5 = 5ms
- {
- flag5ms = 0;
- ir_process(); //红外控制
- calculate_num();
- }
- }
- }
- }
复制代码
|