找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机定时中断与主循环函数执行问题

[复制链接]
ID:566127 发表于 2019-6-22 19:29 | 显示全部楼层 |阅读模式
显示函数和按键检测放在主循环里,因为中断随时在发生,按键检测和显示就经常被打断,按键有经常检测不到,显示有更新的话,变换很慢。而放在中断里的话,按键检测倒是没有问题,显示更新也快了,但是由于显示需要计算耗费不少时间,导致中断不准,输出波形也就变了。。。

单片机源程序如下:
  1. #include <reg52.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. uchar code Sin[]={"Sine      "};
  5. uchar code Squ[]={"Square    "} ;
  6. uchar code Tri[]={"Triangle  "};
  7. uchar code No[]={"No Signal out "};
  8. uchar code Wave[]={"Wave: "};
  9. uchar code Fre[]={"f="};
  10. uchar code vpp1[]={"V="};
  11. uint vpp;
  12. uint freq;
  13. uchar i;
  14. sbit RS = P1^0;                                                                                //数据/命令选择端(H/L)
  15. sbit RW = P1^1;                                                                                //数/写选择端(H/L)      
  16. sbit EN = P1^2;                                                                                //使能信号  
  17. float  k=0.4;
  18. uint peri=500;
  19. uchar key_wave=1;//键值
  20. unsigned long c;
  21. sbit key1=P2^0;//波形切换按钮
  22. sbit key2=P2^1;//频率加
  23. sbit key3=P2^2;//频率减
  24. sbit key4=P2^3;//幅值加
  25. sbit key5=P2^4;//幅值减

  26. /**************定义数组产生正弦波 64个点******************/
  27. uchar code sine1[]=
  28. {
  29. 0x80,0x8d,0x99,0xa5,0xb1,0xbc,0xc7,0xd1,
  30. 0xda,0xe3,0xea,0xf1,0xf6,0xfa,0xfd,0xff,
  31. 0xff,0xff,0xfd,0xf9,0xf5,0xef,0xe9,0xe1,
  32. 0xd8,0xcf,0xc5,0xba,0xae,0xa2,0x96,0x89,
  33. 0x80,0x72,0x66,0x5a,0x4e,0x43,0x38,0x2e,
  34. 0x25,0x1c,0x15,0x0e,0x09,0x05,0x02,0x00,
  35. 0x00,0x00,0x02,0x06,0x0a,0x10,0x16,0x1e,
  36. 0x27,0x30,0x3a,0x45,0x51,0x5d,0x69,0x76
  37. };
  38. /**************定义数组产生方波 64个点******************/
  39. uchar code Square1[]=
  40. {
  41. 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  42. 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  43. 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  44. 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  45. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  46. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  47. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  48. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  49. };
  50. /**************定义数组产生三角波 64个点******************/
  51. uchar code Triangle1[]=
  52. {
  53. 0xff,0xf7,0xef,0xeb,0xde,0xd6,0xce,0xc5,
  54. 0xbd,0xb5,0xad,0xa4,0x9c,0x94,0x8c,0x84,
  55. 0x76,0x73,0x6b,0x63,0x5a,0x52,0x4a,0x42,
  56. 0x39,0x31,0x29,0x21,0x19,0x10,0x08,0x00,
  57. 0x00,0x08,0x10,0x19,0x21,0x29,0x31,0x39,
  58. 0x42,0x4a,0x52,0x5a,0x63,0x6b,0x73,0x76,
  59. 0x84,0x8c,0x94,0x9c,0xa4,0xad,0xb5,0xbd,
  60. 0xc5,0xce,0xd6,0xde,0xeb,0xef,0xf7,0xff
  61. };

  62. void Delayms(unsigned int n)

  63. {

  64. unsigned int i,j;

  65. for(j=n;j>0;j--)

  66. for(i=112;i>0;i--);

  67. }

  68. //………………………………定时器初始化…………………………………//
  69. void init_Timer0()
  70. {
  71.    TMOD=0x22;
  72.    TH0 = (unsigned int)(65536-peri)/256;
  73.    TL0 = (unsigned int)(65536-peri)%256;    //确定频率
  74.   TR0=1;
  75.    ET0=1;
  76.    EA=1;//开中断
  77. }


  78. /***************************
  79. 测忙函数
  80. *************************/
  81. uchar Busy_Check()
  82. {
  83.         uchar LCD_Status;
  84.         RS=0;  //        寄存器选择
  85.         RW=1; //读状态寄存器
  86.         EN=1;  // 开始读
  87.         
  88.         Delayms(1);
  89.         LCD_Status=P3;//P3作为输出口
  90.         EN=0;
  91.         return  LCD_Status;
  92. }
  93. /***************************
  94. 写入字符
  95. *************************/

  96. void Write_LCD_Command(uchar cmd)
  97. {
  98.            while((Busy_Check()&0x80)==0x80);   //忙等待
  99.            RS=0;  //选择命令寄存器
  100.            RW=0;  //写
  101.            EN=0;
  102.            P3=cmd;
  103.            EN=1;
  104.           Delayms(1);
  105.            EN=0;
  106. }
  107. /***************************
  108. 写入数据
  109. *************************/
  110. void Write_LCD_Data(uchar dat)
  111. {
  112.          while((Busy_Check()&0x80)==0x80);   //忙等待        
  113.           RS=1;
  114.           RW=0;
  115.           EN=0;
  116.           P3=dat;
  117.           EN=1;
  118.           Delayms(1);
  119.           EN=0;        
  120. }
  121. /***************************
  122. 初始化函数
  123. *************************/
  124. void Init_LCD()
  125. {               
  126.         Write_LCD_Command(0x38);
  127.         Delayms(1);
  128.         Write_LCD_Command(0x01); //清屏
  129.         Delayms(1);
  130.         Write_LCD_Command(0x06); //字符进入模式:屏幕不动,字符后移
  131.         Delayms(1);
  132.         Write_LCD_Command(0x0C); //显示开、关光标
  133.         Delayms(1);
  134.         for (i=0;i<sizeof(Wave);i++)//----显示WAVE:
  135.                 {
  136.                         Write_LCD_Data(Wave[i]);
  137.                         Delayms(1);
  138.                 }
  139.             Write_LCD_Command(0x80+0x40);//----显示freq:
  140.      Delayms(1);
  141.     for (i=0;i<sizeof(Fre);i++)
  142.                 {
  143.                         Write_LCD_Data(Fre[i]);
  144.                         Delayms(1);
  145.                 }
  146.                  Write_LCD_Command(0xc0+8);//----显示vpp:
  147.      Delayms(1);
  148.     for (i=0;i<sizeof(vpp1);i++)
  149.                 Write_LCD_Data(vpp1[i]);
  150.                         Delayms(1);
  151.                
  152.         
  153.         
  154. }

  155. /***************************
  156. 写入频率  成功
  157. *************************/
  158. void Write_freq(uint k)
  159. {
  160.         uchar bai,shi,ge;
  161.         bai=k/100%10;
  162.         shi=k/10%10;
  163.         ge=k%10;
  164.   Write_LCD_Command(0xc0+2);
  165.         Write_LCD_Data(0x30+bai);
  166.         Write_LCD_Data(0x30+shi);
  167.         Write_LCD_Data(0x30+ge);
  168.         Write_LCD_Data(0x48);//代表H
  169.         Write_LCD_Data(0x5a);//代表Z
  170. }
  171. /***************************
  172. 写入幅值       成功
  173. *************************/
  174. void Write_vpp(uint u)
  175. {
  176.   uchar Va,Vb,Vc,Vd;
  177.         Va=1000*u/1000%10;
  178.         Vb=1000*u/100%10;
  179.         Vc=1000*u/10%10;
  180.         Vd=1000*u%10;
  181.   Write_LCD_Command(0xc0+10);//位置
  182.         Write_LCD_Data(0x30+Va);
  183.         Write_LCD_Data(0x30+Vb);
  184.         Write_LCD_Data(0x30+Vc);
  185.         Write_LCD_Data(0x30+Vd);
  186.         Write_LCD_Data(0x6d);///显示m
  187.         Write_LCD_Data(0x56);///显示V
  188. }        
  189. /***************************
  190. lcd1602   频率计算   成功
  191. *************************/
  192. void Xianshi()                  
  193. {

  194.      freq=1/(64*peri*0.000001);
  195.          Write_freq(freq);
  196.           vpp=5*k;
  197.          Write_vpp(vpp);

  198. }
  199. /***************************
  200. lcd1602   幅值计算幅值
  201. amplitude  成功
  202. *************************/

  203. void Write_wave(uchar t )
  204. {
  205.         switch(t)
  206.         {
  207.                 case 0:
  208.                                  Write_LCD_Command(0x86);//定位
  209.                                     for (i=0;i<sizeof(No);i++)
  210.                                         {
  211.                                                 Write_LCD_Data(No[i]);//
  212.                                                 Delayms(1);
  213.                                         }
  214.                                         break;
  215.                 case 1:
  216.                                 Write_LCD_Command(0x86);//定位
  217.                                    Delayms(1);
  218.                                     for (i=0;i<sizeof(Sin)-1;i++)
  219.                                         {
  220.                                                 Write_LCD_Data(Sin[i]);
  221.                                                 Delayms(1);
  222.                                         }
  223.                                 break;
  224.                 case 2:
  225.                                 Write_LCD_Command(0x86);//定位
  226.                                    Delayms(1);
  227.                                     for (i=0;i<sizeof(Squ)-1;i++)
  228.                                         {
  229.                                                 Write_LCD_Data(Squ[i]);
  230.                                                 Delayms(1);
  231.                                          }
  232.                         
  233.                                 break;
  234.                 case 3:

  235.                                 Write_LCD_Command(0x86);//定位
  236.                                    Delayms(1);
  237.                                     for (i=0;i<sizeof(Tri)-1;i++)
  238.                                         {
  239.                                                 Write_LCD_Data(Tri[i]);
  240.                                                 Delayms(1);
  241.                                         }
  242.                                 break;
  243.                                 }
  244. }
  245. void key()
  246. {
  247.         if(key1==0)
  248.         {
  249.                 Delayms(10);//延时消抖
  250.                 if(key1==0)
  251.                 {
  252.                         key_wave+=1;
  253.                         if(key_wave>3)
  254.        {
  255.           key_wave=1;
  256.        }
  257.                 }
  258.                 while(!key1);
  259.         }

  260.         if(key2==0)
  261.         {
  262.                 Delayms(10);//延时消抖
  263.                 if(key2==0)
  264.                 {
  265.                         peri+=50;
  266.                         if(peri>=781)
  267.        {
  268.            peri=781;
  269.        }
  270.                 }
  271.                 while(!key2);
  272.         }
  273.         if(key3==0)
  274.         {
  275.                 Delayms(10);//延时消抖
  276.                 if(key3==0)
  277.                 {
  278.                         peri-=50;
  279.                         if(peri<=31)
  280.        {
  281.            peri=31;
  282.        }
  283.                 }
  284.                 while(!key3);
  285.         }
  286.         if(key4==0)
  287.         {
  288.                 Delayms(10);//延时消抖
  289.                 if(key4==0)
  290.                 {
  291.                         k+=0.1;
  292.                         if(k>=1)
  293.        {
  294.            k=1;
  295.        }
  296.                 }
  297.                 while(!key4);
  298.         }
  299.         if(key5==0)
  300.         {
  301.                 Delayms(10);//延时消抖
  302.                 if(key5==0)
  303.                 {
  304.                         k-=0.1;
  305.                         if(k<=0)
  306.        {
  307.            k=0;
  308.        }
  309.                 }
  310.                 while(!key5);
  311.         }
  312. }        



  313. void main()
  314. {
  315.                 Init_LCD();  //LCD初始化
  316.     init_Timer0();//定时器初始化
  317.         
  318.          while(1)
  319.                 {
  320.           key();
  321.                         
  322.             Write_wave(key_wave);//显示波形名字
  323.                   Xianshi();//显示波形大小
  324.                         
  325.           }
  326. }

  327. void Time0_isr(void) interrupt 1  //定时中断
  328. {
  329.          TH0 = (unsigned int)(65536-peri)/256;
  330.    TL0 = (unsigned int)(65536-peri)%256;    //确定频率
  331. //        key();
  332.         c++;
  333.   if(c>=64)
  334.    c=0;
  335. switch(key_wave)
  336. //根据输出哪种波形,从P0口向DAC0832送数字量
  337.         
  338.         {
  339.                
  340.    //无输出
  341.           case 0:
  342.                 P0=0x00;
  343.           break;
  344.         //正弦波
  345.     case 1:
  346.     P0=k*sine1[c];
  347.     break;
  348.    //方波
  349.     case 2:
  350.     P0=k*Square1[c];
  351.           break;
  352.         //三角波
  353.          case 3:
  354.    P0=k*Triangle1[c];
  355.          break;

  356. }
  357.          
  358. }
复制代码


回复

使用道具 举报

ID:332444 发表于 2019-6-22 19:59 | 显示全部楼层
当按钮操作时暂停中断。51单片机资源毕竟有限,对时间的安排是要注意各方面的关系和逻辑,采样时间也应安排好。
回复

使用道具 举报

ID:213173 发表于 2019-6-22 23:16 | 显示全部楼层
由于你的中断周期太短留给主程序运行的时间非常少,致使按键程序和LCD驱动程序响应迟缓。必须做深度优化,尽量使用简单指令。软件延时的方法根本就不能用。把按键程序和LCD驱动程序打散,放在中断里。每发生一次中断只执行一条按键或LCD驱动程序。实际就是在一个中断周期中分时工作。经过多次中断完成一次按键或LCD驱动程序。
回复

使用道具 举报

ID:401564 发表于 2019-6-24 08:55 | 显示全部楼层
1,LCD的延时尽量的减少,查询的延时就不要,直接不断的去检测忙碌标志位,只要一空闲就返回,有的时候是不用那么多的时间去等等忙碌位的。
2,LCD显示是有缓冲的,显示的频率是可以比较低,1秒显示一两次就可以了,或者是先检测按键,按键没有变化,那么,你的数据也是没有变化的,显示也就不用改变了。
比如:你显示的方波,50HZ,占空比是50%,你是通过按键来控制的,显示一次之后,这个数据是一直保留在LCD上的,按键没有动作的话,LCD就不需要刷新了。

方法是很多的,你可以把LCD的显示放到按键处理函数中,每个按键有一次动作就显示一次,或者是在LCD函数到处加一个按键检测,这样就不会错过按键动作了
回复

使用道具 举报

ID:123289 发表于 2019-6-24 08:57 | 显示全部楼层
经验不足,思路窄,规划得不好。
1、决不用硬延时,延时一定用中断做。
2、事件的处理,尽可能在主程序中做,不要在中断中做。
3、中断服务程序尽可能短,对于要处理的事件,尽可能只做标记,让事件在主程序中依据标记决定是否有事件要处理?并做处理。
4、中断尽可能少发生,例如:中断的时间间隔放长一点。
能做到以上四点,你的问题就解决了。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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