本帖最后由 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();
- }
- }
- }
- }
復制代碼
|