当前位置:   article > 正文

基于89c52的八位竞赛抢答器_基于at89c52单片机的8位竞赛抢答器

基于at89c52单片机的8位竞赛抢答器

目录


   

1.设计要求

   以单片机为核心,设计一个8位竞赛抢答器:同时供8名选手或8个代表队比赛,分别用8个按钮S0S7表示。

   设置一个系统清除和抢答控制开关S,开关由主持人控制。

  抢答器具有锁存与显示功能。即选手按按钮,锁存相应的编号,并在优先抢答选手的编号一直保持到主持人将系统清除为止。

   抢答器具有定时抢答功能,且一次抢答的时间由主持人设定(如30秒)。

   当主持人启动开始键后,定时器进行减计时,同时扬声器发出短暂的声响,声响持续的时间为0.5s左右。

   参赛选手在设定的时间内进行抢答,抢答有效,定时器停止工作,显示器上显示选手的编号和抢答的时间,并保持到主持人将系统清除为止。

   如果定时时间已到,无人抢答,本次抢答无效,系统报警并禁止抢答,定时显示器上显示00

2. 实验原理

   通过键盘改变抢答的时间,原理与闹钟时间的设定相同,将定时时间的变量置为全局变量后,通过键盘扫描程序使每按下一次按键,时间加1(超过30时置0)。同时单片机不断进行按键扫描,当参赛选手的按键按下时,用于产生时钟信号的定时计数器停止计数,同时将选手编号(按键号)和抢答时间分别显示在LED上。

3. 电路设计(Proteus仿真通过)

4. 单片机运行结果

5.流程图展示

6.代码展示

  1. #include <reg52.h> // 包含reg52头文件
  2. #define uchar unsigned char // 定义uchar为无符号字符型
  3. #define uint unsigned int // 定义uint为无符号整型
  4. #define GPIO_DIG P0 // 定义GPIO_DIG为P0
  5. #define GPIO_KEY P1 // 定义GPIO_KEY为P1
  6. sbit en = P2^7; // 使能引脚
  7. sbit rs = P2^6; // 寄存器选择引脚
  8. sbit rw = P2^5; // 读/写选择引脚
  9. sbit beep = P1^5; // 蜂鸣器引脚
  10. sbit K0 = P3^0; // K0引脚
  11. sbit K1 = P3^1; // K1引脚
  12. sbit K2 = P3^2; // K2引脚
  13. sbit K3 = P3^3; // K3引脚
  14. sbit P20 = P2^0; // P20引脚
  15. // 数码管显示字符的编码
  16. uchar code start[] = "Welcome to game"; // 开始游戏提示语
  17. uchar code time[] = "0123456789";
  18. uchar name_time[] = "00";
  19. uchar name_time1[] = "00";
  20. uchar timer[] = {0, 0}; // 计时器数组,用于显示时间
  21. uint count = 0; // 定时器中断计数器
  22. uchar KeyValue = 0; // 键值
  23. uchar name1 = 0; // 名称
  24. uchar str1[] = {"012345678"};
  25. uchar str0[] = {"name"};
  26. uchar str2[] = {"replied"};
  27. void delay(uint z); // 延时函数声明
  28. void write_com(uchar com); // 写命令函数声明
  29. void init(); // 初始化函数声明
  30. void write_data(uchar date); // 写数据函数声明
  31. void LCD_SetCursor(uchar Line, uchar Columu); // 设置LCD光标函数声明
  32. void LCD_ShowString(unsigned char Line, unsigned char Columu, unsigned char* String); // LCD显示字符串函数声明
  33. void T0_init(); // 定时器T0初始化函数声明
  34. void T1_init(); // 定时器T1初始化函数声明
  35. void KeyDown(); // 按键检测函数声明
  36. void sound(); // 蜂鸣器函数声明
  37. void start_game(); // 游戏开始函数声明
  38. void timer_init(); // 计时器初始化函数声明
  39. void shijian();
  40. void main()
  41. {
  42. init(); // LCD初始化
  43. T0_init(); // 初始化定时器0
  44. T1_init(); // 初始化外部中断
  45. timer_init();
  46. write_com(0x80); // 设置LCD显示位置
  47. while(1)
  48. {
  49. start_game(); // 游戏开始
  50. }
  51. }
  52. // 延时函数
  53. void delay(uint z)
  54. {
  55. uint x, y;
  56. for (x = z; x > 0; x--)
  57. for (y = 110; y > 0; y--);
  58. }
  59. void delay1(unsigned int i) //延时函数
  60. {
  61. while (i--)
  62. ;
  63. }
  64. // 写命令
  65. void write_com(uchar com) {
  66. rs = 0; // 设置为命令寄存器
  67. rw = 0; // 写操作
  68. P0 = com; // 将命令写入数据口
  69. delay(10);
  70. en = 1; // 使能LCD
  71. en = 0; // 禁用LCD
  72. }
  73. // LCD初始化
  74. void init() {
  75. rw = 0; // 写操作
  76. en = 0; // 禁用LCD
  77. write_com(0x38); // 设置为8位数据接口,显示模式为2行显示,字符大小为5x8
  78. write_com(0x0c); // 开启显示,关闭光标
  79. write_com(0x06); // 光标右移,字符不移动
  80. write_com(0x01); // 清屏
  81. }
  82. // 写数据
  83. void write_data(uchar date) {
  84. rs = 1; // 设置为数据寄存器
  85. rw = 0; // 写操作
  86. P0 = date; // 将数据写入数据口
  87. delay(10);
  88. en = 1; // 使能LCD
  89. en = 0; // 禁用LCD
  90. }
  91. // 1s定时器
  92. void timer0() interrupt 1 {
  93. TH0 = (65536 - 50000) / 256; // 设置定时器初值高位
  94. TL0 = (65536 - 50000) % 256; // 设置定时器初值低位
  95. count++;
  96. if (count >= 20) { // 每计数20次(约1秒)
  97. count = 0;
  98. if (timer[0] == 0 && timer[1] == 0)
  99. {
  100. TR0 = 0;
  101. init(); // 清屏
  102. LCD_ShowString(1 , 1 , "no replied");
  103. } else
  104. {
  105. if (timer[1] == 0)
  106. {
  107. if (timer[0] > 0)
  108. {
  109. timer[0]--; // 减少十位
  110. timer[1] = 9; // 设置个位为9
  111. }
  112. } else
  113. {
  114. timer[1]--; // 仅减少个位
  115. }
  116. }
  117. }
  118. }
  119. //停止与继续中断函数
  120. void INT_1() interrupt 2 {
  121. if (!K3) {
  122. delay(10);
  123. if (!K3) {
  124. TR0 = !TR0; // 切换定时器启停状态
  125. while (!K3);
  126. }
  127. }
  128. }
  129. // 定时器T0初始化
  130. void T0_init() {
  131. TMOD = 0x01; // 定时器0工作在方式1(16位定时器)下
  132. TH0 = (65536 - 50000) / 256;
  133. TL0 = (65536 - 50000) % 256;
  134. EA = 1; // 允许中断
  135. ET0 = 1; // 允许定时器0中断
  136. }
  137. // 定时器T1初始化
  138. void T1_init() {
  139. EA = 1; // 开启总中断
  140. EX1 = 1; // 开启1号外部中断
  141. IT1 = 1; // 设置外部中断0为下降沿触发
  142. }
  143. // lcd显示函数
  144. void LCD_ShowString(uchar Line, uchar Columu, uchar* String)
  145. {
  146. unsigned char i = 0;
  147. // 设置LCD光标位置
  148. LCD_SetCursor(Line, Columu);
  149. // 遍历字符串并逐个显示字符
  150. for (i = 0; String[i] != '\0'; i++)
  151. {
  152. write_data(String[i]);
  153. }
  154. }
  155. // 设置LCD光标位置
  156. void LCD_SetCursor(uchar Line, uchar Columu)
  157. {
  158. if (Line == 1)
  159. {
  160. write_com(0x80 | (Columu - 1));
  161. }
  162. else
  163. {
  164. write_com(0x80 | (Columu - 1) + 0x40);
  165. }
  166. }
  167. // 蜂鸣器
  168. void sound()
  169. {
  170. uchar i = 50;
  171. // 循环控制蜂鸣器的开关以产生声音
  172. while (i--)
  173. {
  174. beep = ~beep;
  175. delay(200);
  176. }
  177. }
  178. // 矩阵键盘扫描
  179. void KeyDown()
  180. {
  181. GPIO_KEY = 0x0f;
  182. if (GPIO_KEY != 0x0f) // 如果按键按下
  183. {
  184. delay(10); // 延时10ms消抖
  185. if (GPIO_KEY != 0x0f) // 按键确实按下
  186. {
  187. // 判断按键所在列,以所在列的第一行的按键键值赋给KeyValue
  188. GPIO_KEY = 0X0F;
  189. switch (GPIO_KEY)
  190. {
  191. case (0X07): KeyValue = 1; break; // 第一列按下
  192. case (0X0b): KeyValue = 2; break; // 第二列按下
  193. case (0X0d): KeyValue = 3; break; // 第三列按下
  194. case (0X0e): KeyValue = 4; break; // 第四列按下
  195. }
  196. // 判断按键所在行
  197. GPIO_KEY = 0XF0;
  198. switch (GPIO_KEY)
  199. {
  200. case (0X70): KeyValue = KeyValue; break; // 第一行按下
  201. case (0Xb0): KeyValue = KeyValue + 4; break; // 第二行按下
  202. case (0Xd0): KeyValue = KeyValue + 8; break; // 第三行按下
  203. case (0Xe0): KeyValue = KeyValue + 12; break; // 第四行按下
  204. }
  205. while (GPIO_KEY != 0xf0); // 按键松手后退出
  206. }
  207. }
  208. }
  209. //蜂鸣器函数
  210. void beep1()
  211. {
  212. unsigned char i;
  213. for (i = 0; i < 100; i++)
  214. {
  215. delay1(100);
  216. beep = ~beep;
  217. }
  218. }
  219. //抢答器函数
  220. void xianshiqiangda()
  221. {
  222. unsigned int i = 0;
  223. unsigned int j;
  224. j = KeyValue;
  225. write_com(0x80);
  226. delay(1000);
  227. // 遍历字符串str0并逐个显示字符
  228. while (str0[i] != '\0')
  229. {
  230. write_data(str0[i]);
  231. i++;
  232. }
  233. TR0 = 0;
  234. // 计算name_time[0]的值
  235. name1 = name_time[0] * 10 - timer[0] * 10 - timer[1];
  236. name_time[0] = name1 / 10;
  237. name_time[1] = (name1 % 10)-1;
  238. write_com(0x80 + 0x06);
  239. delay(10);
  240. write_data(str1[j]);
  241. delay(10);
  242. // 在LCD上显示"name_number:"
  243. LCD_ShowString(2, 1, "name_number:");
  244. // 在LCD上显示name_time[0]和name_time[1]对应的时间
  245. write_data(time[name_time[0]]);
  246. delay(5);
  247. write_data(time[name_time[1]]);
  248. while (1);
  249. }
  250. // 开始函数
  251. void start_game()
  252. {
  253. if (!K2)
  254. {
  255. delay(5);
  256. if (!K2)
  257. {
  258. // 在LCD上显示"start"
  259. LCD_ShowString(1, 1, start);
  260. delay(10);
  261. // 在LCD上显示"time:"
  262. LCD_ShowString(2, 1, "time:");
  263. TR0 = 1;
  264. while (1)
  265. {
  266. // 在LCD上显示当前计时器的值
  267. write_com(0x80 + 0x40 + 0x07);
  268. write_data(time[timer[0]]);
  269. delay(5);
  270. write_data(time[timer[1]]);
  271. delay(5);
  272. if (GPIO_KEY != 0xf0)
  273. {
  274. break;
  275. }
  276. }
  277. }
  278. while (!K2);
  279. }
  280. if (timer[0] != 0 && timer[1] != 0)
  281. {
  282. write_com(0x01);
  283. KeyDown();
  284. beep1();
  285. if (KeyValue < 8)
  286. {
  287. while (1)
  288. {
  289. xianshiqiangda();
  290. }
  291. }
  292. }
  293. }
  294. //设置初时函数
  295. void timer_init()
  296. {
  297. // 在LCD上显示"set the time:"
  298. LCD_ShowString(1, 1, "set the time:");
  299. // 初始化计时器数组
  300. timer[0] = 0; // 初始化第一个元素
  301. timer[1] = 0; // 初始化第二个元素
  302. while (1)
  303. {
  304. KeyDown();
  305. // 获取按键值并赋给timer[0]
  306. timer[0] = KeyValue;
  307. name_time[0] = KeyValue;
  308. name_time[1] = 0;
  309. if (timer[0] != 0)
  310. {
  311. init();
  312. // 在LCD上显示"Countdown time:"
  313. LCD_ShowString(1, 1, "Countdown time:");
  314. // 在LCD上显示设置的倒计时时间
  315. write_com(0x80 + 0x40 + 0x03);
  316. write_data(time[timer[0]]);
  317. delay(5);
  318. write_data(time[timer[1]]);
  319. delay(5);
  320. KeyValue = 0;
  321. break;
  322. }
  323. }
  324. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/164324
推荐阅读
相关标签
  

闽ICP备14008679号