找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2699|回复: 4
收起左侧

51单片机开发板定时器中断和外部中断冲突

[复制链接]
ID:883416 发表于 2021-2-21 22:08 | 显示全部楼层 |阅读模式
想做一个四自由度的机械臂,如果不加上红外的外部中断的话舵机是可以好好转动的,加上了外部中断就有几率转的断断续续的

是定时器中断和外部中断冲突了吗?(雾)还是我的代码有问题?


至于定时器为什么设置为0.2ms,然后PWM给的数值也很奇怪,是因为我从某宝上面买的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引脚定义在一起,这样一旦接收到信号就进入中断函数进行解码
  12.                  //红外接收引脚和外部中断0的引脚是一个

  13. uchar irdata[4];//irdata[4]存的是一组用户码和数据码、数据反码

  14. uchar KeyValue;//定义键值,确定按下按键
  15. uint time;      //定义红外时间判断
  16. uchar count=0;
  17. uchar PWM_count1=1;    //此数据是多次试验得到的结果
  18. uchar PWM_count2=1;
  19. uchar PWM_count3=1;
  20. uchar PWM_count4=1;

  21. /*延时函数*/
  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. /*红外遥控函数*/
  87. void IR_init()         //红外遥控初始化
  88. {                       
  89.     IT0=1;             //外部中断0触发方式选择位
  90.     EX0=1;             //打开外部中断0允许位
  91.     EA=1;             //总中断允许位
  92.     IR=1;             //相当于打开外部中断0 此处意义为红外接收器打开
  93. }

  94. void Read_IR() interrupt 0    //执行中断:进行读取信号  最后产生键值
  95. {
  96.     uint i,j,k;
  97.     delay(700);//能进入中断函数就代表IR已经为0,此处的延时是为了判断延时的大体时间
  98.     if(IR==0)
  99.     {
  100.             k=1000;
  101.             while(IR==0&&(k>0))//检测引导码中9ms低电平
  102.             {
  103.                 delay(1);
  104.                 k--;
  105.             }
  106.         if(IR==1)//判断高电平
  107.         {
  108.             k=500;
  109.             while(IR==1&&(k>0))//检测引导码中4.5ms高电平
  110.             {
  111.                 delay(1);
  112.                 k--;
  113.             }
  114.             for(i=0;i<4;i++)    //开始读取用户码和数据和数据反码,因为用户码和数据码、数据反码共有4组,所以外层有四组循环
  115.             {
  116.                 for(j=0;j<8;j++)//每组数据有八位,故内层循环有八组,每次循环读一位
  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)//进入高电平时间,这一块比较核心,它判断了高电平持续时间的长短
  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;            //充当break
  139.                              irdata[i]>>=1;    //移位运算,空出最高为为下一次采集做准备
  140.                             if(time>=8)//如果高电平持续时间超过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]分别是数据码和数据反码 ,此操作是检验数据准确性(~取反)
  148.     return;
  149.     }
  150.     switch(irdata[2])//反馈键值所对应的数值
  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;          //设置定时器初值
  176.   TL0=0x48;       //计数初值设置为0.2ms      每0.2ms进入一次中断,晶振频率:11.0592MHZ 200微秒
  177.   ET0=1;          //打开定时器0的中断
  178.   TR0=1;          //打开定时器0
  179.   EA=1;
  180. }


  181. /*中断发送PWM舵机控制函数*/
  182. void Timer() interrupt 1                          //定时器中断发生,每0.2ms一次,count来记录中断次数
  183.                                                  //100次中断为20ms
  184.                                                  //0--外部中断0,1--定时器中断0,2--外部中断1,3--定时器中断1,4--串行口中断1
  185. {
  186.   TR0=0;          //关闭定时器
  187.   TH0=0xff;
  188.   TL0=0x48;       //重新赋计数初值为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函数*/
  229. void main()
  230. {
  231.     IR_init();         //红外遥控初始化  PS:红外接收引脚P3^2
  232.     Timer_Init();     //定时器中断初始化

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

  236.         key();                          //舵机复位和自动动作

  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. }
复制代码

回复

使用道具 举报

ID:213173 发表于 2021-2-22 06:26 | 显示全部楼层
本帖最后由 wulin 于 2021-2-22 09:51 编辑

单片机玩的就是时间和逻辑。你T0中断周期200us,EX0中断任务完成需近百ms。外部中断优先于定时中断,定时中断当然会频繁丢失。所有不是必须在中断中处理的事务都要放在主函数中处理。
回复

使用道具 举报

ID:592807 发表于 2021-2-22 09:23 | 显示全部楼层
你的按键咋就这么奇葩呢
51hei截图20210222092219.png

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:57657 发表于 2021-11-29 23:11 | 显示全部楼层
请配置外部中断、定时器中断优先级控制寄存器 :PX0、PT0
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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