找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5812|回复: 3
打印 上一主题 下一主题
收起左侧

基于51单片机的4人抢答器代码

[复制链接]
跳转到指定楼层
楼主
ID:498742 发表于 2019-4-30 19:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. /*
  2. 此程序为4人抢答器。
  3. 抢答者4人对应,K1-4的按钮
  4. 裁判可操作Ks,Kr,Kc,Ka4个按钮
  5. Ks:按下就进入抢答倒计时
  6. Kr:按下复位,准备下次抢答
  7. Kc,Ka:用于调整倒计时。
  8. 在复位之前使用,且当前的操作是对复位之后的倒计时有用
  9. 保证没有人按下除了Kc,Ka之外的按钮。
  10. 最大设置为1分钟,最小10s
  11. 按一次Kc加1s
  12. 操作步骤:按下Kr,后要按住Ka不松的状态按Kc加时间,然后再次按下Kr

  13. 显示器第一行显示倒计时的时间
  14. 例如:countdown:10s
  15. 显示器第二行显示违规者和抢答成功者的对应按钮
  16. 例如:error:0 win:2  表示:无人违规,2号抢答成功
  17. 例如:error:2 win:0  表示:有人违规,2号违规
  18. */

  19. #include "reg52.h"
  20. #include "lcd.h"

  21. #define uchar unsigned char
  22. #define uint unsigned int

  23. sbit K1=P1^0;
  24. sbit K2=P1^1;
  25. sbit K3=P1^2;
  26. sbit K4=P1^3;
  27. sbit Ks=P3^0;   //按下就进入抢答倒计时
  28. sbit Kr=P3^2;   //按下复位,准备下次抢答
  29. sbit Kc=P3^3;   //按下调整倒计时,注意事项见timeset()
  30. sbit Ka=P3^4;   //配合Kc
  31. sbit beep=P3^7;
  32. sbit led=P3^1;

  33. uchar fallflag=0,sflag=0,jflag=0,sjflag=0;
  34. uchar win,time=10;     //time为倒计时秒数,num为程序中控制倒计时的变量,win为抢答成功的按钮
  35. uchar num,numf;        //numf为配合num来显示lcd

  36. uchar Disp1[16]="countdown:00s   ";
  37. uchar Disp2[16]="error:0 win:0   ";

  38. void judge();
  39. void search();

  40. void delay(uchar ms)
  41. {
  42.         uchar y;
  43.         for(;ms>0;ms--)
  44.                 for(y=120;y>0;y--);
  45. }



  46. void T0_Init()
  47. {
  48.         TMOD=0X11;
  49.         TH0=(65536-1000)/256;
  50.         TL0=(65536-1000)%256;
  51.         TH1=(65536-1000)/256;
  52.         TL1=(65536-1000)%256;
  53.         ET0=1;
  54.         ET1=1;
  55.                                 TR0=1;    //定时器0开
  56.                                 TR1=0;    //定时器1关
  57.         EA=1;
  58. }
  59. /*lcd1602显示程序*/
  60. void display(uchar date1,uchar date2)
  61. {
  62.         uchar i,a;
  63.         LcdInit();
  64.         Disp1[10]=num/10+'0';
  65.         Disp1[11]=num%10+'0';
  66.         Disp2[6]=date1+'0';
  67.         Disp2[12]=date2+'0';
  68.         for(i=0;i<16;i++)
  69.         {
  70.                 LcdWriteData(Disp1[i]);        
  71.         }
  72.         LcdWriteCom(0x80+0x40);
  73.         for(a=0;a<16;a++)
  74.         {
  75.                 LcdWriteData(Disp2[a]);        
  76.         }
  77. }

  78. /*
  79. 开始准备抢答,开始倒计时
  80. */
  81. void Ks_Scan()
  82. {
  83.         if(Ks==0)
  84.         {
  85.                 delay(10);
  86.                 if(Ks==0)
  87.                 {
  88.                         TR1=1;              //开启倒计时
  89.                         sjflag=1;           //开启犯规判断
  90.                         while(num!=0)      //如果在期间有人抢答,fallflag=1,此程序执行完后,后续程序会判犯规
  91.                         {
  92.                                 if(num==numf-1)
  93.                                 {
  94.                                         numf=numf-1;
  95.                                         display(0,0);  //不能显示num=0时
  96.                                 }
  97.                         }
  98.                         sflag=1;       //抢答开始
  99.                         if(sjflag==0)  //有人犯规
  100.                         {
  101.                                 sflag=0;
  102.                         }
  103.                         sjflag=0;        //关闭犯规判断
  104.                         display(0,0);    //显示num=0时
  105.                         beep=0;             //蜂鸣
  106.                 }
  107.                 while(!Ks);
  108.         }
  109. }
  110. /*
  111. 复位
  112. */
  113. void restoration()
  114. {
  115.         if(Kr==0)
  116.         {
  117.                 delay(10);
  118.                 if(Kr==0)
  119.                 {
  120.                         sflag=0;
  121.                         sjflag=0;
  122.                         jflag=0;
  123.                         win=0;
  124.                         fallflag=0;
  125.                         TR1=0;
  126.                         num=time;
  127.                         numf=num;
  128.                         beep=1;
  129.                         led=1;
  130.                         display(0,0);              //清除显示屏
  131.                 }
  132.                 while(!Kr);
  133.         }
  134. }
  135. /*
  136. 在复位之前使用,且当前的操作是对复位之后的倒计时有用
  137. 保证没有人按下除了Kc,Ka之外的按钮。
  138. 最大设置为1分钟,最小10s
  139. 按一次Kc加1s
  140. 操作步骤:按下Kr,后要按住Ka不松的状态按Kc加时间,然后再次按下Kr
  141. */
  142. void timeset()   //改变抢答时间
  143. {
  144.         uchar a=0;
  145.         if(Ka==0)
  146.         {
  147.                 delay(10);
  148.                 if(Ka==0)
  149.                 {
  150.                         while(!Ka)
  151.                         {
  152.                         if(Kc==0)
  153.                         {
  154.                         delay(10);
  155.                         if(Kc==0)
  156.                         {
  157.                                 a++;
  158.                         }
  159.                         while(!Kc);
  160.                         }
  161.                         }
  162.                         time=time+a;
  163.                 }
  164.         }
  165.         if(time>=60)
  166.         {
  167.                 time=10;
  168.         }
  169. }


  170. void main()
  171. {
  172.         T0_Init();
  173.         while(1)
  174.         {
  175.                 Ks_Scan();
  176.                 if((sflag==0)&(fallflag==0))   //没开始没人抢答
  177.                 {
  178.                         timeset();
  179.                 }
  180.                 if((sflag==0)&(fallflag!=0))  //有人违规抢答
  181.                 {
  182.                         led=0;   //亮灯警告
  183.                         beep=1;  //关闭蜂鸣
  184.                         display(fallflag,0);         //显示有人犯规,并显示犯规按钮,根据fallflag
  185.                 }
  186.                 if((sflag==1)&(fallflag==0))   //无人违规
  187.                 {
  188.                         while(jflag==0)
  189.                         {
  190.                                 judge();
  191.                         }
  192.                         judge();  //防止jflag=1时,judge()没执行
  193.                         beep=1;  //关闭蜂鸣
  194.                         display(0,win);         //显示抢答成功按钮,根据win
  195.                 }
  196.                 restoration();  //复位
  197.         }
  198. }

  199. /*不停的扫描k1-4的状态,每隔1ms扫描一次*/
  200. void timer0() interrupt 1
  201. {
  202.         TH0=(65536-1000)/256;
  203.   TL0=(65536-1000)%256;
  204.         search();
  205. }


  206. void timer1() interrupt 3
  207. {
  208.         static i;
  209.         TH0=(65536-1000)/256;
  210.   TL0=(65536-1000)%256;
  211.         i++;
  212.         if(i==1000)
  213.         {
  214.                 i=0;
  215.                 num--;
  216.                 //display(0,0);     //为什么此时加上这个程序就报warning
  217.                 if(num==0)          //放在内部保证定时器的准确性
  218.                 {
  219.                         TR1=0;
  220.                 }
  221.         }
  222. }




  223. //先丢后面的代码


  224. /*
  225. 配合定时器0使用
  226. 如果k1-4有按键按下,fallflag=1
  227. */
  228. void search()
  229. {
  230.         if((K1==0)&(sjflag==1))   //按下Ks开始后(sjflag=1)如果有人按了K1就会进入程序
  231.         {
  232.                 delay(10);
  233.                 if(K1==0)
  234.                 {
  235.                         fallflag=1;
  236.                         sjflag=0;             //互锁,并配合Ks_Scan()中的犯规判断语句
  237.                 }
  238.                 while(!K1);
  239.         }
  240.         if((K2==0)&(sjflag==1))
  241.         {
  242.                 delay(10);
  243.                 if(K2==0)
  244.                 {
  245.                         fallflag=2;
  246.                         sjflag=0;
  247.                 }
  248.                 while(!K2);
  249.         }
  250.         if((K3==0)&(sjflag==1))
  251.         {
  252.                 delay(10);
  253.                 if(K3==0)
  254.                 {
  255.                         fallflag=3;
  256.                         sjflag=0;
  257.                 }
  258.                 while(!K3);
  259.         }
  260.         if((K4==0)&(sjflag==1))
  261.         {
  262.                 delay(10);
  263.                 if(K4==0)
  264.                 {
  265.                         fallflag=4;
  266.                         sjflag=0;
  267.                 }
  268.                 while(!K4);
  269.         }
  270. }

  271. void judge()           
  272. {
  273.         if((K1==0)&(jflag==0))
  274.         {
  275.                 delay(10);
  276.                 if((K1==0)&(jflag==0))
  277.                 {
  278.                         win=1;
  279.                         jflag=1;    //锁住其他按钮
  280.                 }
  281.                 while(!K1);
  282.         }
  283.         if((K2==0)&(jflag==0))
  284.         {
  285.                 delay(10);
  286.                 if((K2==0)&(jflag==0))
  287.                 {
  288.                         win=2;
  289.                         jflag=1;    //锁住其他按钮
  290.                 }
  291.                 while(!K2);
  292.         }
  293.         if((K3==0)&(jflag==0))
  294.         {
  295.                 delay(10);
  296.                 if((K3==0)&(jflag==0))
  297.                 {
  298.                         win=3;
  299.                         jflag=1;    //锁住其他按钮
  300.                 }
  301.                 while(!K3);
  302.         }
  303.         if((K4==0)&(jflag==0))
  304.         {
  305.                 delay(10);
  306.                 if((K4==0)&(jflag==0))
  307.                 {
  308.                         win=4;
  309.                         jflag=1;    //锁住其他按钮
  310.                 }
  311.                 while(!K4);
  312.         }
  313. }

  314. 以下是“lcd.c”
  315. #include "lcd.h"

  316. /*******************************************************************************
  317. * 函 数 名         : Lcd1602_Delay1ms
  318. * 函数功能                   : 延时函数,延时1ms
  319. * 输    入         : c
  320. * 输    出         : 无
  321. * 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
  322. *******************************************************************************/

  323. void Lcd1602_Delay1ms(uint c)   //误差 0us
  324. {
  325.     uchar a,b;
  326.         for (; c>0; c--)
  327.         {
  328.                  for (b=199;b>0;b--)
  329.                  {
  330.                           for(a=1;a>0;a--);
  331.                  }      
  332.         }
  333.             
  334. }

  335. /*******************************************************************************
  336. * 函 数 名         : LcdWriteCom
  337. * 函数功能                   : 向LCD写入一个字节的命令
  338. * 输    入         : com
  339. * 输    出         : 无
  340. *******************************************************************************/
  341. #ifndef         LCD1602_4PINS         //当没有定义这个LCD1602_4PINS时
  342. void LcdWriteCom(uchar com)          //写入命令
  343. {
  344.         LCD1602_E = 0;     //使能
  345.         LCD1602_RS = 0;           //选择发送命令
  346.         LCD1602_RW = 0;           //选择写入
  347.         
  348.         LCD1602_DATAPINS = com;     //放入命令
  349.         Lcd1602_Delay1ms(1);                //等待数据稳定

  350.         LCD1602_E = 1;                  //写入时序
  351.         Lcd1602_Delay1ms(5);          //保持时间
  352.         LCD1602_E = 0;
  353. }
  354. #else
  355. void LcdWriteCom(uchar com)          //写入命令
  356. {
  357.         LCD1602_E = 0;         //使能清零
  358.         LCD1602_RS = 0;         //选择写入命令
  359.         LCD1602_RW = 0;         //选择写入

  360.         LCD1602_DATAPINS = com;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  361.         Lcd1602_Delay1ms(1);

  362.         LCD1602_E = 1;         //写入时序
  363.         Lcd1602_Delay1ms(5);
  364.         LCD1602_E = 0;

  365.         LCD1602_DATAPINS = com << 4; //发送低四位
  366.         Lcd1602_Delay1ms(1);

  367.         LCD1602_E = 1;         //写入时序
  368.         Lcd1602_Delay1ms(5);
  369.         LCD1602_E = 0;
  370. }
  371. #endif
  372. /*******************************************************************************
  373. * 函 数 名         : LcdWriteData
  374. * 函数功能                   : 向LCD写入一个字节的数据
  375. * 输    入         : dat
  376. * 输    出         : 无
  377. *******************************************************************************/                  
  378. #ifndef         LCD1602_4PINS                  
  379. void LcdWriteData(uchar dat)                        //写入数据
  380. {
  381.         LCD1602_E = 0;        //使能清零
  382.         LCD1602_RS = 1;        //选择输入数据
  383.         LCD1602_RW = 0;        //选择写入

  384.         LCD1602_DATAPINS = dat; //写入数据
  385.         Lcd1602_Delay1ms(1);

  386.         LCD1602_E = 1;   //写入时序
  387.         Lcd1602_Delay1ms(5);   //保持时间
  388.         LCD1602_E = 0;
  389. }
  390. #else
  391. void LcdWriteData(uchar dat)                        //写入数据
  392. {
  393.         LCD1602_E = 0;          //使能清零
  394.         LCD1602_RS = 1;          //选择写入数据
  395.         LCD1602_RW = 0;          //选择写入

  396.         LCD1602_DATAPINS = dat;        //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
  397.         Lcd1602_Delay1ms(1);

  398.         LCD1602_E = 1;          //写入时序
  399.         Lcd1602_Delay1ms(5);
  400.         LCD1602_E = 0;

  401.         LCD1602_DATAPINS = dat << 4; //写入低四位
  402.         Lcd1602_Delay1ms(1);

  403.         LCD1602_E = 1;          //写入时序
  404.         Lcd1602_Delay1ms(5);
  405.         LCD1602_E = 0;
  406. }
  407. #endif
  408. /*******************************************************************************
  409. * 函 数 名       : LcdInit()
  410. * 函数功能                 : 初始化LCD屏
  411. * 输    入       : 无
  412. * 输    出       : 无
  413. *******************************************************************************/                  
  414. #ifndef                LCD1602_4PINS
  415. void LcdInit()                                                  //LCD初始化子程序
  416. {
  417.          LcdWriteCom(0x38);  //开显示
  418.         LcdWriteCom(0x0c);  //开显示不显示光标
  419.         LcdWriteCom(0x06);  //写一个指针加1
  420.         LcdWriteCom(0x01);  //清屏
  421.         LcdWriteCom(0x80);  //设置数据指针起点
  422. }
  423. #else
  424. void LcdInit()                                                  //LCD初始化子程序
  425. {
  426.         LcdWriteCom(0x32);         //将8位总线转为4位总线
  427.         LcdWriteCom(0x28);         //在四位线下的初始化
  428.         LcdWriteCom(0x0c);  //开显示不显示光标
  429.         LcdWriteCom(0x06);  //写一个指针加1
  430.         LcdWriteCom(0x01);  //清屏
  431.         LcdWriteCom(0x80);  //设置数据指针起点
  432. }
  433. #endif

  434. 以下是“lcd.h”
  435. #ifndef __LCD_H_
  436. #define __LCD_H_
  437. /**********************************
  438. 当使用的是4位数据传输的时候定义,
  439. 使用8位取消这个定义
  440. **********************************/
  441. //#define LCD1602_4PINS

  442. /**********************************
  443. 包含头文件
  444. **********************************/
  445. #include <reg52.h>

  446. //---重定义关键词---//
  447. #ifndef uchar
  448. #define uchar unsigned char
  449. #endif

  450. #ifndef uint
  451. #define uint unsigned int
  452. #endif

  453. /**********************************
  454. PIN口定义
  455. **********************************/
  456. #define LCD1602_DATAPINS P2
  457. sbit LCD1602_E=P0^7;
  458. sbit LCD1602_RW=P0^6;
  459. sbit LCD1602_RS=P0^5;

  460. /**********************************
  461. 函数声明
  462. **********************************/
  463. /*在51单片机12MHZ时钟下的延时函数*/
  464. void Lcd1602_Delay1ms(uint c);   //误差 0us
  465. /*LCD1602写入8位命令子函数*/
  466. void LcdWriteCom(uchar com);
  467. /*LCD1602写入8位数据子函数*/        
  468. void LcdWriteData(uchar dat)        ;
  469. /*LCD1602初始化子程序*/               
  470. void LcdInit();                                                  

  471. #endif
复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:518357 发表于 2019-5-6 08:20 | 只看该作者
感觉不错哦,谢谢大佬分享
回复

使用道具 举报

板凳
ID:743691 发表于 2020-6-20 22:23 | 只看该作者
写的很详细了,谢谢分享
回复

使用道具 举报

地板
ID:785570 发表于 2020-6-21 10:39 | 只看该作者
有仿真图吗?

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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