基于89c52的八位竞赛抢答器

目录


   

1.设计要求

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

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

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

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

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

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

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

2. 实验原理

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

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

4. 单片机运行结果

5.流程图展示

6.代码展示

#include <reg52.h> // 包含reg52头文件

#define uchar unsigned char // 定义uchar为无符号字符型
#define uint unsigned int // 定义uint为无符号整型
#define GPIO_DIG P0 // 定义GPIO_DIG为P0
#define GPIO_KEY P1 // 定义GPIO_KEY为P1

sbit en = P2^7;  // 使能引脚
sbit rs = P2^6;  // 寄存器选择引脚
sbit rw = P2^5;  // 读/写选择引脚
sbit beep = P1^5; // 蜂鸣器引脚
sbit K0 = P3^0; // K0引脚
sbit K1 = P3^1; // K1引脚
sbit K2 = P3^2; // K2引脚
sbit K3 = P3^3; // K3引脚
sbit P20 = P2^0; // P20引脚

// 数码管显示字符的编码
uchar code start[] = "Welcome to game"; // 开始游戏提示语
uchar code time[] = "0123456789";
uchar name_time[] = "00";
uchar name_time1[] = "00";
uchar timer[] = {0, 0}; // 计时器数组,用于显示时间
uint count = 0;  // 定时器中断计数器
uchar KeyValue = 0; // 键值
uchar name1 = 0; // 名称
uchar str1[] = {"012345678"};
uchar str0[] = {"name"};
uchar str2[] = {"replied"};

void delay(uint z); // 延时函数声明
void write_com(uchar com); // 写命令函数声明
void init(); // 初始化函数声明
void write_data(uchar date); // 写数据函数声明
void LCD_SetCursor(uchar Line, uchar Columu); // 设置LCD光标函数声明
void LCD_ShowString(unsigned char Line, unsigned char Columu, unsigned char* String); // LCD显示字符串函数声明
void T0_init(); // 定时器T0初始化函数声明
void T1_init(); // 定时器T1初始化函数声明
void KeyDown(); // 按键检测函数声明
void sound(); // 蜂鸣器函数声明
void start_game();  // 游戏开始函数声明
void timer_init(); // 计时器初始化函数声明
void shijian();


void main() 
{
    init();         // LCD初始化
	  T0_init();      // 初始化定时器0
    T1_init();      // 初始化外部中断
		timer_init();
    write_com(0x80); // 设置LCD显示位置
    while(1)
    {
      start_game(); // 游戏开始
    }
}

// 延时函数
void delay(uint z) 
{
    uint x, y;
    for (x = z; x > 0; x--)
        for (y = 110; y > 0; y--);
}
void delay1(unsigned int i) //延时函数
{
    while (i--)
        ;
}
// 写命令
void write_com(uchar com) {
    rs = 0;        // 设置为命令寄存器
    rw = 0;        // 写操作
    P0 = com;      // 将命令写入数据口
    delay(10);
    en = 1;        // 使能LCD
    en = 0;        // 禁用LCD
}

// LCD初始化
void init() {
    rw = 0;        // 写操作
    en = 0;        // 禁用LCD
    write_com(0x38);  // 设置为8位数据接口,显示模式为2行显示,字符大小为5x8
    write_com(0x0c);  // 开启显示,关闭光标
    write_com(0x06);  // 光标右移,字符不移动
    write_com(0x01);  // 清屏
}

// 写数据
void write_data(uchar date) {
    rs = 1;        // 设置为数据寄存器
    rw = 0;        // 写操作
    P0 = date;     // 将数据写入数据口
    delay(10);
    en = 1;        // 使能LCD
    en = 0;        // 禁用LCD
}

// 1s定时器
void timer0() interrupt 1 {
    TH0 = (65536 - 50000) / 256; // 设置定时器初值高位
    TL0 = (65536 - 50000) % 256; // 设置定时器初值低位
    count++;

    if (count >= 20) { // 每计数20次(约1秒)
        count = 0;
    
        if (timer[0] == 0 && timer[1] == 0) 
				{
					TR0 = 0;
					init();  // 清屏
          LCD_ShowString(1 , 1 , "no replied");
        } else 
				{
            if (timer[1] == 0) 
						{
                if (timer[0] > 0) 
								{
									timer[0]--; // 减少十位
									timer[1] = 9; // 设置个位为9
                }
            } else 
						{
                timer[1]--; // 仅减少个位
            }
        }
    }
}

//停止与继续中断函数
void INT_1() interrupt 2 {
    if (!K3) {
        delay(10);
        if (!K3) {
            TR0 = !TR0; // 切换定时器启停状态
            while (!K3);
        }
    }
}

// 定时器T0初始化
void T0_init() {
    TMOD = 0x01;    // 定时器0工作在方式1(16位定时器)下
    TH0 = (65536 - 50000) / 256;
    TL0 = (65536 - 50000) % 256;
    EA = 1;         // 允许中断
    ET0 = 1;        // 允许定时器0中断
}

// 定时器T1初始化
void T1_init() {
    EA = 1;     // 开启总中断
    EX1 = 1;    // 开启1号外部中断
    IT1 = 1;    // 设置外部中断0为下降沿触发
}

// lcd显示函数
void LCD_ShowString(uchar Line, uchar Columu, uchar* String)
{
    unsigned char i = 0;
    
    // 设置LCD光标位置
    LCD_SetCursor(Line, Columu);
    
    // 遍历字符串并逐个显示字符
    for (i = 0; String[i] != '\0'; i++)
    {
        write_data(String[i]);
    }
}

// 设置LCD光标位置
void LCD_SetCursor(uchar Line, uchar Columu)
{
    if (Line == 1)
    {
        write_com(0x80 | (Columu - 1));
    }
    else
    {
        write_com(0x80 | (Columu - 1) + 0x40);
    }
}

// 蜂鸣器
void sound()
{
    uchar i = 50;
    
    // 循环控制蜂鸣器的开关以产生声音
    while (i--)
    {
        beep = ~beep;
        delay(200);
    }
}

// 矩阵键盘扫描
void KeyDown()
{
    GPIO_KEY = 0x0f;
    
    if (GPIO_KEY != 0x0f) // 如果按键按下
    {
        delay(10); // 延时10ms消抖
        
        if (GPIO_KEY != 0x0f) // 按键确实按下
        {   
            // 判断按键所在列,以所在列的第一行的按键键值赋给KeyValue
            GPIO_KEY = 0X0F;
            
            switch (GPIO_KEY)
            {
                case (0X07): KeyValue = 1; break; // 第一列按下
                case (0X0b): KeyValue = 2; break; // 第二列按下
                case (0X0d): KeyValue = 3; break; // 第三列按下
                case (0X0e): KeyValue = 4; break; // 第四列按下
            }
            
            // 判断按键所在行
            GPIO_KEY = 0XF0;
            
            switch (GPIO_KEY)
            {
                case (0X70): KeyValue = KeyValue; break; // 第一行按下
                case (0Xb0): KeyValue = KeyValue + 4; break; // 第二行按下
                case (0Xd0): KeyValue = KeyValue + 8; break; // 第三行按下
                case (0Xe0): KeyValue = KeyValue + 12; break; // 第四行按下
            }
            
            while (GPIO_KEY != 0xf0); // 按键松手后退出
        }
    }
}

//蜂鸣器函数
void beep1()
{
    unsigned char i;
    
    for (i = 0; i < 100; i++)
    {
        delay1(100);
        beep = ~beep;
    }
}

//抢答器函数
void xianshiqiangda()
{
    unsigned int i = 0;
    unsigned int j;
    j = KeyValue;
    write_com(0x80);
    delay(1000);
    
    // 遍历字符串str0并逐个显示字符
    while (str0[i] != '\0')
    {
        write_data(str0[i]);
        i++;
    }
    
    TR0 = 0;
    
    // 计算name_time[0]的值
    name1 = name_time[0] * 10 - timer[0] * 10 - timer[1];
    name_time[0] = name1 / 10;
    name_time[1] = (name1 % 10)-1;
    
    write_com(0x80 + 0x06);
    delay(10);
    write_data(str1[j]);
    delay(10);
    
    // 在LCD上显示"name_number:"
    LCD_ShowString(2, 1, "name_number:");
    
    // 在LCD上显示name_time[0]和name_time[1]对应的时间
    write_data(time[name_time[0]]);
    delay(5);
    write_data(time[name_time[1]]);
    
    while (1);
}

// 开始函数
void start_game()
{
    if (!K2)
    {
        delay(5);
        if (!K2)
        {
            // 在LCD上显示"start"
            LCD_ShowString(1, 1, start);
            delay(10);
            
            // 在LCD上显示"time:"
            LCD_ShowString(2, 1, "time:");
            
            TR0 = 1;
            
            while (1)
            {
                // 在LCD上显示当前计时器的值
                write_com(0x80 + 0x40 + 0x07);
                write_data(time[timer[0]]);
                delay(5);
                write_data(time[timer[1]]);
                delay(5);
                
                if (GPIO_KEY != 0xf0)
                {
                    break;
                }
            }
        }
        
        while (!K2);
    }
    
    if (timer[0] != 0 && timer[1] != 0)
    {
        write_com(0x01);
        KeyDown();
        beep1();
        
        if (KeyValue < 8)
        {
            while (1)
            {
                xianshiqiangda();
            }
            
        }
    }
}

//设置初时函数
void timer_init()
{
    // 在LCD上显示"set the time:"
    LCD_ShowString(1, 1, "set the time:");
    
    // 初始化计时器数组
    timer[0] = 0;  // 初始化第一个元素
    timer[1] = 0;  // 初始化第二个元素
    
    while (1)
    {
        KeyDown();
        
        // 获取按键值并赋给timer[0]
        timer[0] = KeyValue;
        name_time[0] = KeyValue;
        name_time[1] = 0;
        
        if (timer[0] != 0)
        {
            init();
            
            // 在LCD上显示"Countdown time:"
            LCD_ShowString(1, 1, "Countdown time:");
            
            // 在LCD上显示设置的倒计时时间
            write_com(0x80 + 0x40 + 0x03);
            write_data(time[timer[0]]);
            delay(5);
            write_data(time[timer[1]]);
            delay(5);
            
            KeyValue = 0;
            break;
        }
    }
}

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值