找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3247|回复: 0
收起左侧

有倒计时功能的单片机八路抢答器Proteus仿真程序

[复制链接]
ID:371844 发表于 2019-7-30 17:14 | 显示全部楼层 |阅读模式
抢答器正常情况下使用很ok,并且可以调节倒计时时间于LCD1602显示。
非正常情况下,会有些漏洞存在,感兴趣的朋友可以进一步完善。

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)

八路抢答器

八路抢答器


单片机源程序如下:
  1. //有倒计时功能的八路抢答器C语言程序:
  2. #include<reg52.h>
  3. #define  LCDPORT P0                  //LCD数据线
  4. #define  KEY            P3                   //八路抢答按键
  5. typedef        unsigned char uchar;
  6. typedef        unsigned int  uint;
  7. sbit  begin=P1^1;                        //开始键
  8. sbit  set=P1^2;                          //设置时间键
  9. sbit  add=P1^3;                         
  10. sbit  dec=P1^4;                               
  11. sbit  rst=P1^5;                         //复位键
  12. sbit  light=P1^6;                   //开始指示灯
  13. sbit  speaker=P1^7;                   //控制蜂鸣器
  14. sbit  lcdrs=P2^0;
  15. sbit  lcdrw=P2^1;
  16. sbit  lcden=P2^2;
  17. uchar code table[]="00:15";        //初始值的设定
  18. uint  aa=0,bb=0,cc=0,dd=0;  //用于计数
  19. uchar start;                                   //开始标志
  20. uchar stop;                                   //结束标志
  21. uchar reset;                                   //复位标志
  22. uchar miao=15;
  23. uchar fen=0;
  24. bit   lockflag=0;                   //锁定标志,标志着已经有人抢答成功
  25. bit   spflag=0;                           //开始声响标示
  26. bit   ovflag=0;                                //超时声响标志
  27. /****延时z毫秒*******/
  28. void delay(uint z)
  29. {
  30. uchar x,y;
  31. for(x=z;x>0;x--)
  32.      for(y=250;y>0;y--);        //晶振为12MHZ:4*250*z=z ms
  33. }
  34. /***液晶写地址******/
  35. void write_com(uchar com)
  36. {
  37. lcdrs=0;
  38. lcdrw=0;
  39. P0=com;
  40. lcden=1;
  41. delay(3);
  42. lcden=0;
  43. }
  44. /****液晶写数据******/
  45. void write_data(uchar date)
  46. {
  47. lcdrs=1;
  48. lcdrw=0;
  49. P0=date;
  50. lcden=1;
  51. delay(3);
  52. lcden=0;
  53. }
  54. /***液晶初始化********/
  55. void lcd_init()
  56. {
  57. uchar num;
  58. write_com(0X38);                         //初始化
  59. write_com(0X0c);                         //打开光标 0x0c不显示光标,0x0e光标不闪,0x0f光标闪
  60. write_com(0X06);                          //清显示
  61. write_com(0X80);                        //显示第一行,第二行为(0x80+0x40)
  62. for(num=0;num<5;num++)
  63.     {
  64.          write_data(table[num]);
  65.          delay(5);
  66.         }
  67. }
  68. /******定时器初始化*******/
  69. void timer_init()
  70. {
  71.   TMOD=0x11;                             //工作方式的选择
  72.   TH0=(65536-50000)/256;
  73.   TL0=(65536-50000)%256;  //50ms
  74.   ET0=1;

  75.   TH1=(65536-500)/256;
  76.   TL1=(65536-500)%256;    //0.5ms
  77.   ET1=1;

  78.   EA=1;
  79.   TR0=0;
  80.   TR1=0;
  81. }
  82. /*****显示分*****/
  83. void  display1(uchar fen)
  84. {
  85.   uchar shi,ge;
  86.   shi=fen/10;
  87.   ge=fen%10;
  88.   write_com(0X80);
  89.   write_data(0X30+shi);                 //这里要注意,显示的是ASCII码!
  90.   write_data(0X30+ge);
  91. }
  92. /*****显示秒*******/
  93. void display(uchar miao)
  94. {
  95.   uchar shi,ge;
  96.   shi=miao/10;
  97.   ge=miao%10;
  98.   write_com(0X80+3) ;
  99.   write_data(0X30+shi);                //这里要注意,显示的是ASCII码!
  100.   write_data(0X30+ge);
  101. }
  102. /******定时器0的中断服务程序******/
  103. //倒计时
  104. void timer0() interrupt 1
  105. {
  106.   TH0=(65536-50000)/256;
  107.   TL0=(65536-50000)%256;
  108.   aa++;
  109.   if(aa==20)                                //20*50ms=1s
  110.    {
  111.     aa=0;
  112.     miao--;
  113.     if(miao==0)
  114.       {
  115.        if(fen==0)
  116.          {         
  117.           stop=1;                          //时间到了,抢答超时
  118.           TR0=0;                           //关闭定时器
  119.           light=1;                  //把灯也关了
  120.           TR1=1;                    //开启定时器1,响声
  121.           ovflag=1;                   //超时标志
  122.          }
  123.             else
  124.               {
  125.                    fen--;
  126.                miao=59;               
  127.           }
  128.        }
  129.    display(miao);                          //更新显示数据
  130.    display1(fen);
  131.   }
  132. }
  133. /*****键盘扫描程序********/
  134. uchar keyscan()
  135. {
  136. uchar keyn;
  137. if(KEY!=0xff)
  138.    {
  139.     delay(5);                            //延时5ms作消抖处理
  140.     if(KEY!=0xff)                  //确认有按键按下
  141.       {
  142.        switch(KEY)
  143.                       {
  144.                        case 0xfe:keyn=0;break;
  145.                        case 0xfd:keyn=1;break;
  146.                        case 0xfb:keyn=2;break;
  147.                        case 0xf7:keyn=3;break;
  148.                        case 0xef:keyn=4;break;
  149.                        case 0xdf:keyn=5;break;
  150.                        case 0xbf:keyn=6;break;
  151.                        case 0x7f:keyn=7;break;
  152.                       }
  153.        while(KEY!=0xff); //等待松手
  154.              }
  155.    }
  156.   if(begin==0)
  157.    {
  158.      delay(5);                  //延时5m作消抖处理
  159.      if(begin==0)
  160.        {
  161.         keyn=8;
  162.         while(!begin);
  163.        }
  164.     }
  165.   if(set==0)
  166.     {
  167.      delay(5);                          //延时5m作消抖处理
  168.      if(set==0)
  169.        {
  170.         while(!set);
  171.             delay(5);
  172.             while(!set);
  173.             bb++;
  174.            }
  175.          }
  176.   if(bb==1)
  177.     {
  178.            write_com(0x80+4);
  179.      write_com(0x0f);
  180.     }
  181.   if(bb==2)
  182.     {
  183.            write_com(0x80+1);
  184.      write_com(0x0f);
  185.     }
  186.   if(add==0)
  187.     {
  188.      delay(5);                          //延时5m作消抖处理
  189.      if(add==0)
  190.        {
  191.         while(!add);
  192.             delay(5);
  193.             while(!add);
  194.                 //修改秒,增加1
  195.                 if(bb==1)
  196.                   {
  197.                    uchar ge,shi;
  198.                    miao++;
  199.                    shi=miao/10;
  200.                    ge=miao%10;
  201.                    //秒的修整
  202.                    if(miao==60)
  203.                             {
  204.                           ge=0;
  205.                              shi=0;
  206.                          }
  207.                    //显示修整值
  208.                    miao=shi*10+ge;
  209.                    display(miao);
  210.                    write_com(0x80+4);//把光标位置移回来
  211.                   }
  212.                  //修改分钟,加一
  213.                  if(bb==2)
  214.                     {
  215.                      uchar ge,shi;
  216.                      fen++;
  217.                      shi=fen/10;
  218.                      ge=fen%10;
  219.                          if(fen==60)
  220.                            {
  221.                             ge=0;
  222.                                 shi=0;
  223.                            }
  224.                      fen=shi*10+ge;
  225.                      display1(fen);
  226.                      write_com(0x80+1);
  227.                     }
  228.                 }
  229.         }
  230.   if(dec==0)
  231.     {
  232.      delay(5);                          //延时5m作消抖处理
  233.      if(dec==0)
  234.        {
  235.         while(!dec);
  236.             delay(5);
  237.             while(!dec);  
  238.                 if(bb==1)
  239.                         {
  240.                                 uchar ge,shi;
  241.                                 miao--;
  242.                                 shi=miao/10;
  243.                                 ge=miao%10;
  244.                                 if(miao==-1)
  245.                                   {
  246.                                         shi=5;
  247.                                         ge=9;       
  248.                                   }
  249.                                 miao=shi*10+ge;                                                                                               
  250.                                 display(miao);
  251.                                 write_com(0x80+4);
  252.                           }
  253.                         //修改分钟
  254.                         if(bb==2)
  255.                           {
  256.                                 uchar ge,shi;
  257.                                 fen--;
  258.                                 shi=fen/10;
  259.                                 ge=fen%10;
  260.                                 if(fen==-1)
  261.                                   {
  262.                                    shi=5;
  263.                                    ge=9;
  264.                                   }
  265.                                 fen=shi*10+ge;
  266.                                 display1(fen);
  267.                                 write_com(0x80+1);
  268.                           }
  269.               }
  270.    }
  271. if(bb==3)
  272.    {
  273.     bb=0;
  274.     write_com(0x0c);
  275.    }
  276. if(rst==0)
  277.    {
  278.     delay(5);                          //延时5m作消抖处理
  279.     if(rst==0)
  280.     {
  281.      keyn=9;
  282.      while(!rst);
  283.     }
  284.    }   
  285. return(keyn);
  286. }
  287. /*******定时器1的中断服务程序*******/
  288. //喇叭声响
  289. void timer1() interrupt 3
  290. {
  291.   TH1=(65536-500)/256;
  292.   TL1=(65536-500)%256;    //重装初值
  293.   if(spflag)                     //开始时先响500ms
  294.     {
  295.      speaker=!speaker;
  296.      dd++;
  297.      if(dd>1000)                  //0.5ms*1000=500ms
  298.        {
  299.         dd=0;
  300.         TR1=0;                      //停止定时器
  301.                 spflag=0;
  302.        }
  303.     }  
  304.   if(ovflag)                   //超时声响
  305.     {
  306.      dd++;
  307.          if(dd%4==0){speaker=!speaker;}
  308.      if(dd>3000)
  309.        {
  310.         dd=0;
  311.         TR1=0;
  312. //                ovflag=0;
  313.        }     
  314.     }
  315. }
  316. void restart()
  317. {
  318.   uchar num;
  319.   start=0;
  320.   TR0=0;                                    //关闭定时器才能停止计时
  321.   TR1=0;
  322.   miao=0;
  323.   fen=0;
  324.   spflag=0;
  325.   ovflag=0;
  326.   lockflag=0;                                  //各种标志清零
  327.   P1=0XFF;
  328.   P3=0XFF;  
  329.   miao=15;
  330.   fen=0;
  331.   lcd_init();
  332.   timer_init();
  333.   write_com(0x80+0x40);
  334.   write_data(' ');
  335. }
  336. void main()
  337. {
  338.    uchar a;
  339.    lcd_init();
  340.    timer_init();
  341.    while(1)
  342.    {
  343.     a=25;
  344.     a=keyscan();
  345.     if(a!=25)
  346.       {   
  347.        if(a==8)                            //按下开始键
  348.          {
  349.           start=1;                   //第一次按下就要开始抢答
  350.           light=0;                  //灯亮表示开始
  351.           spflag=1;                   //标志开始的声响
  352.                   EA=1;                                //启动定时器
  353.                   TR0=1;            
  354.           TR1=1;         
  355.          }   
  356.        while(start)                         //已经按下开始键后才作下面处理
  357.          {
  358.           a=keyscan();
  359.                   if(a>=0&&a<8&&lockflag==0&&ovflag==0)
  360.              {
  361.               write_com(0x80+0x40) ;
  362.               write_data(0x30+a);
  363.               TR0=0;                  //关闭定时器停止计时
  364.               lockflag=1;          //锁定
  365.                           start=0;
  366.              }
  367.                   if(lockflag==1)start=0;  
  368.          }
  369.                 if(a==9)restart(); //按下复位键
  370.        }
  371.      }
  372. }

复制代码

所有资料51hei提供下载:
有倒计时功能的八路抢答器.zip (57.34 KB, 下载次数: 49)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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