Proteus仿真AT89C51单片机八位抢答器及源文件分享

在网上没能容易地直接找到仿真文件,所以我把这个上传,希望对各位有所帮助。

倒是有不少好心人给出了图文教学和源代码,对他们表示感谢。我也是用这位老哥的代码和电路稍作了修改,感谢分享。

简要介绍图中各按钮的作用:

  • 起初 led 数码管是熄灭的,按下 P2.1 的按钮会将它们点亮,开始抢答。

  • 抢答开始后 P2 口按钮失效。按下 P1 口按钮后将在右侧数码管显示对应的选手号码,这时计时将暂停,按下 P2.0 按钮表示回答正确,3 秒左右后数码管熄灭,准备下一轮抢答;按下 P2.1 按钮继续这轮抢答·。

  • 时间耗尽时,暂停 3 秒左右,之后计时器熄灭,准备下一轮抢答。

  • 代码:

    #include <reg51.h>
    #define RAT 30 // 抢答时间 rush to answer time
    
    sbit DIN = P3 ^ 0; // 与MAX7219的接口引脚定义
    sbit LOAD = P3 ^ 1;
    sbit CLK = P3 ^ 2;
    sbit key0 = P1 ^ 0; // 定义8路抢答器按键
    sbit key1 = P1 ^ 1;
    sbit key2 = P1 ^ 2;
    sbit key3 = P1 ^ 3;
    sbit key4 = P1 ^ 4;
    sbit key5 = P1 ^ 5;
    sbit key6 = P1 ^ 6;
    sbit key7 = P1 ^ 7;
    
    sbit speaker = P0 ^ 0;
    sbit keyClear = P2 ^ 0;                                                    // 主持人的“清除/设置时间”按键
    sbit begin = P2 ^ 1;                                                        // 主持人开始按键
    sbit sounder = P3 ^ 7;                                                      // 蜂鸣器相连的引脚
    unsigned char second = RAT;                                                 // 秒表计数值
    unsigned char counter = 0;                                                  // counter 每计100,minite加1
    unsigned char people = 0;                                                   // 抢答结果
    unsigned char numAdd[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // MAX7219的读写地址
    unsigned char numDat[] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89};
    
    unsigned char keyScan() { // 键盘扫描函数
    
        unsigned char keyValue, temp;
        keyValue = 0;
        P1 = 0xff; // P1口的8个引脚设置为输入
        temp = P1;
        if (~(P1 & temp)) { // 如P1口的引脚电平发生变化,有键按下
            switch (temp)
            {
            case 0xfe: // 如P1.0口的引脚电平为低,则S1键按下
                keyValue = 1;
                break;
            case 0xfd: // 如P1.1口的引脚电平为低,则S2键按下
                keyValue = 2;
                break;
            case 0xfb: // 如P1.2口的引脚电平为低,则S3键按下
                keyValue = 3;
                break;
            case 0xf7: // 如P1.3口的引脚电平为低,则S4键按下
                keyValue = 4;
                break;
            case 0xef: // 如P1.4口的引脚电平为低,则S5键按下
                keyValue = 5;
                break;
            case 0xdf: // 如P1.5口的引脚电平为低,则S6键按下
                keyValue = 6;
                break;
            case 0xbf: // 如P1.6口的引脚电平为低,则S7键按下
                keyValue = 7;
                break;
            case 0x7f:
                keyValue = 8; // 如P1.7口的引脚电平为低,则S8键按下
                break;
            default:
                keyValue = 0;
                break;
            }
        }
        return keyValue; // 返回键号
    }
    
    void secondIniter() {
        second = RAT;
    }
    
    void max7219Send(unsigned char add, unsigned char dat) { // 向MAX7219写命令函数
        unsigned char ADS, i, j;
        LOAD = 0;
        i = 0;
        while (i < 16) {
            if (i < 8) {
                ADS = add;
            } else {
                ADS = dat;
            }
            for (j = 8; j >= 1; j--) {
                DIN = ADS & 0x80;
                ADS <<= 1;
                CLK = 1;
                CLK = 0;
            }
            i += 8;
        }
        LOAD = 1;
    }
    
    void max7219Init() { // MAX7219初始化函数
        max7219Send(0x0c, 0x01);
        max7219Send(0x0b, 0x07);
        max7219Send(0x0a, 0xf5);
        max7219Send(0x09, 0xff);
    }
    void max7219Shutdown() { // MAX7219关闭函数
        max7219Send(0x0C, 0x00); // 发送关闭命令给MAX7219
    }
    void timeDisplay(unsigned char x) { // 时间显示函数
        unsigned char i, j;
        i = x / 10;
        j = x % 10;
        max7219Send(numAdd[1], numDat[j]);
        max7219Send(numAdd[0], numDat[i]);
    }
    
    void scareDisplay(unsigned char x) { // 显示抢答结果函数
        unsigned char i, j;
        i = x / 10;
        j = x % 10;
        max7219Send(numAdd[3], numDat[j]);
        max7219Send(numAdd[2], numDat[i]);
    }
    void delayMs(unsigned int ms) { // 延时函数
        unsigned int i, j;       // 定义两个循环变量
        for (i = 0; i < ms; i++) // 外层循环控制毫秒数
            for (j = 0; j < 112; j++)
                ; // 内层循环控制微秒数,具体值要根据晶振频率和编译器优化程度调整
    }
    void mkNoi(char modle) { // 开始和结束时播放
        int i;
        for (i = 0; i < 400 / modle; i++) { 
            speaker = ~speaker;
            delayMs(modle);
        }
    }
    void bingo() { // 答对了要播放这个
        int i, j;
        for (i = 4; i > 0; i--) {
            for (j = 0; j < 200 / i; j++) {
                speaker = ~speaker;
                delayMs(i);
            }
        }
    }
    void holderScan() { // 函数功能:设置抢答时间为0~60s
        timeDisplay(second); // 时间显示
        scareDisplay(people);
        if (~keyClear) { // 如果回答正确,开始下一轮抢答
            while (~keyClear)
                ;
            bingo();
            secondIniter();       // 抢答器重置
            delayMs(3000);
            timeDisplay(second); // 显示重置后的时间
            people = 0;
            
            scareDisplay(people); // 显示重置后的抢答区
            
            max7219Shutdown();
        }
    }
    
    void timerInit() { // 定时器T0初始化
        EA = 1;
        ET0 = 1;
        TMOD = 0x01; // 定时器T0方式0定时
        TH0 = 0xd8;  // 装入定时初值,10ms中断一次
        TL0 = 0xef;
    }
    
    void main() { // 主函数
        while (1) {
            do{
                holderScan();
            } while (begin); // 若未按下“开始”键,则循环
            while (~begin)
                ; // 若按下“开始”键,则往下执行
            mkNoi(1);
            max7219Init(); // MAX7219初始化
            timerInit();   // 定时器T0中断初始化
            TR0 = 1;        // 启动定时器T0
            do {
                timeDisplay(second);  // 显示时间
                scareDisplay(people); // 显示抢答结果
                people = keyScan();
            } while ((!people) && (second)); // 运行直到抢答结束或者时间结束
            TR0 = 0;
    
            if (!second) { // 回合结束
                timeDisplay(second);
                mkNoi(2);
                delayMs(3000);
                secondIniter();
                max7219Shutdown();
            }
        }
    }
    
    void timer0() interrupt 1 { // 定时器T0中断函数
        if (counter < 100) {
            counter++;
            if (counter == 50) {
                sounder = 0; // 蜂鸣器发出声响
            }
        } else {
            sounder = 1;
            counter = 0;
            second--;
        }
        TH0 = 0xd8; // 重新装载定时初值
        TL0 = 0xef;
        TR0 = 1; // 启动T0
    }

    下载链接:

    度盘: https://pan.baidu.com/s/1YU4sybDi_oqA3SSCCIHoGw?pwd=jmvg 提取码: jmvg 复制这段内容后打开百度网盘手机App,操作更方便哦

    https://cloud.lilywhite.cc/s/7RrSA

    希望自己没有损失的情况下,能有更多人随手分享^^

    物联沃分享整理
    物联沃-IOTWORD物联网 » Proteus仿真AT89C51单片机八位抢答器及源文件分享

    发表评论