標題: 51單片機開發(fā)板定時器中斷和外部中斷沖突 [打印本頁]

作者: Menida    時間: 2021-2-21 22:08
標題: 51單片機開發(fā)板定時器中斷和外部中斷沖突
想做一個四自由度的機械臂,如果不加上紅外的外部中斷的話舵機是可以好好轉(zhuǎn)動的,加上了外部中斷就有幾率轉(zhuǎn)的斷斷續(xù)續(xù)的

是定時器中斷和外部中斷沖突了嗎?(霧)還是我的代碼有問題?


至于定時器為什么設(shè)置為0.2ms,然后PWM給的數(shù)值也很奇怪,是因為我從某寶上面買的sg90不知道怎么的,給接近于高電平為0ms的PWM波到0度,接近于2ms的PWM波到180度(也可能是這里的問題?)

下面貼上單片機源代碼,還請各位大佬多多指教


/******************************************************************************

操控方式:紅外遙控和矩陣按鍵操控

舵機PWM接口接 P20\P21\P22\P23
                    
******************************************************************************/
  1. #include<reg52.h>

  2. typedef unsigned int uint;
  3. typedef unsigned char uchar;

  4. #define GPIO_KEY P1//P1交給矩陣鍵盤

  5. sbit dj1=P2^0;
  6. sbit dj2=P2^1;
  7. sbit dj3=P2^2;
  8. sbit dj4=P2^3;
  9. sbit key1=P3^1;
  10. sbit key2=P3^0;
  11. sbit IR=P3^2;    //將紅外接收引腳和外部中斷0引腳定義在一起,這樣一旦接收到信號就進入中斷函數(shù)進行解碼
  12.                  //紅外接收引腳和外部中斷0的引腳是一個

  13. uchar irdata[4];//irdata[4]存的是一組用戶碼和數(shù)據(jù)碼、數(shù)據(jù)反碼

  14. uchar KeyValue;//定義鍵值,確定按下按鍵
  15. uint time;      //定義紅外時間判斷
  16. uchar count=0;
  17. uchar PWM_count1=1;    //此數(shù)據(jù)是多次試驗得到的結(jié)果
  18. uchar PWM_count2=1;
  19. uchar PWM_count3=1;
  20. uchar PWM_count4=1;

  21. /*延時函數(shù)*/
  22. void delay(uint n)      //延時一次約為0.01ms 用來判斷脈沖時間
  23.                                                              /*注意:0到65535*/
  24.     {
  25.         while(n--);
  26.     }

  27. /*獨立按鍵*/
  28. void key()
  29. {
  30.      if(key1==0)
  31.     {
  32.         delay(1000);
  33.         if(key1==0)
  34.         {
  35.             KeyValue=0;
  36.             PWM_count1=PWM_count2=PWM_count3=PWM_count4=1;
  37.         }
  38.         while(!key1);
  39.     }

  40.     if(key2==0)
  41.     {
  42.          delay(1000);
  43.          if(key2==0)
  44.          {
  45.              KeyValue=0;       //待編寫固定動作


  46.          }

  47.     }
  48. }

  49. /*矩陣鍵盤*/
  50. void KeyDown()
  51. {
  52.     char a=0;
  53.     GPIO_KEY=0x0f;        
  54.     if(GPIO_KEY!=0x0f)        //讀取按鍵是否按下
  55.     {
  56.         delay(1000);        //延時10ms進行消抖
  57.         if(GPIO_KEY!=0x0f)    //再次檢測鍵盤是否按下
  58.         {   
  59.             //測試列
  60.             GPIO_KEY=0X0F;
  61.             switch(GPIO_KEY)
  62.             {
  63.                 case(0X07):    KeyValue=1;break;         
  64.                 case(0X0b):    KeyValue=2;break;           
  65.                 case(0X0d): KeyValue=3;break;         
  66.                 case(0X0e):    KeyValue=4;break;         
  67.             }
  68.             //測試行
  69.             GPIO_KEY=0XF0;     
  70.             switch(GPIO_KEY)
  71.             {
  72.                 case(0X70):    KeyValue=KeyValue;break;     
  73.                 case(0Xb0):    KeyValue=KeyValue+4;break;     
  74.                 case(0Xd0): KeyValue=KeyValue+8;break;     
  75.                 case(0Xe0):    KeyValue=KeyValue+12;break;   
  76.             }
  77.             
  78.         }
  79.     }
  80.     while((a<50)&&(GPIO_KEY!=0xf0))     
  81.     {                                
  82.         delay(100);
  83.         a++;
  84.     }
  85. }

  86. /*紅外遙控函數(shù)*/
  87. void IR_init()         //紅外遙控初始化
  88. {                       
  89.     IT0=1;             //外部中斷0觸發(fā)方式選擇位
  90.     EX0=1;             //打開外部中斷0允許位
  91.     EA=1;             //總中斷允許位
  92.     IR=1;             //相當(dāng)于打開外部中斷0 此處意義為紅外接收器打開
  93. }

  94. void Read_IR() interrupt 0    //執(zhí)行中斷:進行讀取信號  最后產(chǎn)生鍵值
  95. {
  96.     uint i,j,k;
  97.     delay(700);//能進入中斷函數(shù)就代表IR已經(jīng)為0,此處的延時是為了判斷延時的大體時間
  98.     if(IR==0)
  99.     {
  100.             k=1000;
  101.             while(IR==0&&(k>0))//檢測引導(dǎo)碼中9ms低電平
  102.             {
  103.                 delay(1);
  104.                 k--;
  105.             }
  106.         if(IR==1)//判斷高電平
  107.         {
  108.             k=500;
  109.             while(IR==1&&(k>0))//檢測引導(dǎo)碼中4.5ms高電平
  110.             {
  111.                 delay(1);
  112.                 k--;
  113.             }
  114.             for(i=0;i<4;i++)    //開始讀取用戶碼和數(shù)據(jù)和數(shù)據(jù)反碼,因為用戶碼和數(shù)據(jù)碼、數(shù)據(jù)反碼共有4組,所以外層有四組循環(huán)
  115.             {
  116.                 for(j=0;j<8;j++)//每組數(shù)據(jù)有八位,故內(nèi)層循環(huán)有八組,每次循環(huán)讀一位
  117.                     {
  118.                          if(IR==0)
  119.                          {
  120.                              k=70;
  121.                              while(IR==0&&(k>0))//檢測0.56ms的低電平
  122.                              {
  123.                                 k--;
  124.                                  delay(1);
  125.                              }
  126.                          }
  127.                          if(IR==1)//進入高電平時間,這一塊比較核心,它判斷了高電平持續(xù)時間的長短
  128.                          {
  129.                              time=0;
  130.                              k=500;
  131.                              while(IR==1&&k>0)//開始檢測高電平
  132.                              {
  133.                                  delay(10);
  134.                                  time++;//time是以0.1ms為單位,因為dy(10);
  135.                                  k--;
  136.                              }
  137.                              if(time>30)
  138.                             return;            //充當(dāng)break
  139.                              irdata[i]>>=1;    //移位運算,空出最高為為下一次采集做準備
  140.                             if(time>=8)//如果高電平持續(xù)時間超過0.85ms代表位是“1”
  141.                              irdata[i]|=0x80;//或運算,給最高為置1
  142.                              time=0;//重置
  143.                         }
  144.                     }
  145.             }
  146.     }
  147.     if(irdata[2]!=~irdata[3])//irdata[2]與irdata[3]分別是數(shù)據(jù)碼和數(shù)據(jù)反碼 ,此操作是檢驗數(shù)據(jù)準確性(~取反)
  148.     return;
  149.     }
  150.     switch(irdata[2])//反饋鍵值所對應(yīng)的數(shù)值
  151.     {
  152.         case 0x44:KeyValue=1;break;
  153.         case 0x40:KeyValue=2;break;
  154.         case 0x43:KeyValue=3;break;
  155.         case 0x07:KeyValue=4;break;
  156.         case 0x15:KeyValue=5;break;
  157.         case 0x09:KeyValue=6;break;
  158.         case 0x16:KeyValue=7;break;
  159.         case 0x19:KeyValue=8;break;
  160.         case 0x0d:KeyValue=9;break;
  161.         case 0x0c:KeyValue=10;break;
  162.         case 0x18:KeyValue=11;break;
  163.         case 0x5e:KeyValue=12;break;
  164.         case 0x08:KeyValue=13;break;
  165.         case 0x1c:KeyValue=14;break;
  166.         case 0x5a:KeyValue=15;break;
  167.         case 0x42:KeyValue=16;break;
  168.         default:break;
  169.     }

  170. }

  171. /*定時器中斷初始化*/

  172. void Timer_Init() //定時器中斷初始化
  173. {
  174.   TMOD=0x01;      //T0定時方式1
  175.   TH0=0xff;          //設(shè)置定時器初值
  176.   TL0=0x48;       //計數(shù)初值設(shè)置為0.2ms      每0.2ms進入一次中斷,晶振頻率:11.0592MHZ 200微秒
  177.   ET0=1;          //打開定時器0的中斷
  178.   TR0=1;          //打開定時器0
  179.   EA=1;
  180. }


  181. /*中斷發(fā)送PWM舵機控制函數(shù)*/
  182. void Timer() interrupt 1                          //定時器中斷發(fā)生,每0.2ms一次,count來記錄中斷次數(shù)
  183.                                                  //100次中斷為20ms
  184.                                                  //0--外部中斷0,1--定時器中斷0,2--外部中斷1,3--定時器中斷1,4--串行口中斷1
  185. {
  186.   TR0=0;          //關(guān)閉定時器
  187.   TH0=0xff;
  188.   TL0=0x48;       //重新賦計數(shù)初值為0.1ms

  189.   if(count<=PWM_count1)    //舵機1
  190.   {
  191.     dj1=1;
  192.   }
  193.   else
  194.   {
  195.     dj1=0;
  196.   }

  197. if(count<=PWM_count2) //舵機2
  198. {
  199.      dj2=1;
  200. }
  201. else
  202. {
  203.      dj2=0;
  204. }

  205.   if(count<=PWM_count3) //舵機3
  206. {
  207.      dj3=1;
  208. }
  209. else
  210. {
  211.      dj3=0;
  212. }

  213.   if(count<=PWM_count4) //舵機4
  214. {
  215.      dj4=1;
  216. }
  217. else
  218. {
  219.      dj4=0;
  220. }

  221.    count++;
  222.   if(count>=100)
  223.   {
  224.     count=0;
  225.   }
  226.   TR0=1;            //打開定時器
  227. }

  228. /*main函數(shù)*/
  229. void main()
  230. {
  231.     IR_init();         //紅外遙控初始化  PS:紅外接收引腳P3^2
  232.     Timer_Init();     //定時器中斷初始化

  233.     while(1)
  234.     {
  235.         KeyDown();

  236.         key();                          //舵機復(fù)位和自動動作

  237.         switch(KeyValue)
  238.         {
  239.             case 1:PWM_count1=1;break;//舵機1
  240.             case 2:PWM_count1=3;break;
  241.             case 3:PWM_count1=7;break;
  242.             case 4:PWM_count1=9;break;

  243.             case 5:PWM_count2=1;break;//舵機2
  244.             case 6:PWM_count2=3;break;
  245.             case 7:PWM_count2=7;break;
  246.             case 8:PWM_count2=9;break;

  247.             case 9:PWM_count3=1;break;//舵機3
  248.             case 10:PWM_count3=3;break;
  249.             case 11:PWM_count3=7;break;
  250.             case 12:PWM_count3=9;break;

  251.             case 13:PWM_count4=1;break;//舵機4
  252.             case 14:PWM_count4=3;break;
  253.             case 15:PWM_count4=7;break;
  254.             case 16:PWM_count4=9;break;
  255.             default:break;   
  256.         }

  257.     }   
  258. }
復(fù)制代碼


作者: wulin    時間: 2021-2-22 06:26
本帖最后由 wulin 于 2021-2-22 09:51 編輯

單片機玩的就是時間和邏輯。你T0中斷周期200us,EX0中斷任務(wù)完成需近百ms。外部中斷優(yōu)先于定時中斷,定時中斷當(dāng)然會頻繁丟失。所有不是必須在中斷中處理的事務(wù)都要放在主函數(shù)中處理。
作者: 黃youhui    時間: 2021-2-22 09:23
你的按鍵咋就這么奇葩呢

51hei截圖20210222092219.png (67 KB, 下載次數(shù): 45)

51hei截圖20210222092219.png

作者: npn    時間: 2021-11-29 23:11
請配置外部中斷、定時器中斷優(yōu)先級控制寄存器 :PX0、PT0




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1