aaasas1111 2023-06-10 19:12 采纳率: 0%
浏览 58
已结题

关于#单片机#的问题:单片机基于51单片机开发计时器,使其实现以下功能:(1)开发板上四个独立按键分别控制计时器的启停、计时器的复位(按下计时值归零)、计时位切换、计时时间的递增

单片机
基于51单片机开发计时器,使其实现以下功能:
(1)开发板上四个独立按键分别控制计时器的启停、计时器的复位(按下计时值归零)、计时位切换、计时时间的递增,最小间隔为1。
(2)数码管上显示当前计时时间(用小时-分钟-秒的格式显示),启动计时后数码管上实时显示计时剩余时长。(中间用-隔开)
(3)计时时间到了后启动蜂鸣器(按下计时器复位按键后蜂鸣器停止)
要求:能在设备中运行即可,软件用到keil和普中
附图:

img

  • 写回答

5条回答 默认 最新

  • qllaoda 2023-06-10 20:02
    关注
    
    #include <reg51.h>
    
    // 数码管位选控制端口
    sbit digit1 = P2^0;
    sbit digit2 = P2^1;
    sbit digit3 = P2^2;
    
    // 数码管段选控制端口
    sbit segmentA = P1^0;
    sbit segmentB = P1^1;
    sbit segmentC = P1^2;
    sbit segmentD = P1^3;
    sbit segmentE = P1^4;
    sbit segmentF = P1^5;
    sbit segmentG = P1^6;
    sbit segmentDP = P1^7;
    
    // 按键控制端口
    sbit startStopButton = P3^0; // 启停按键
    sbit resetButton = P3^1;     // 复位按键
    sbit toggleButton = P3^2;    // 切换按键
    sbit incrementButton = P3^3; // 递增按键
    
    // 蜂鸣器控制端口
    sbit buzzer = P3^4;
    
    unsigned char displayData[3]; // 数码管显示数据(小时、分钟、秒)
    unsigned char currentTime[3]; // 当前计时时间(小时、分钟、秒)
    unsigned char targetTime[3];  // 目标计时时间(小时、分钟、秒)
    unsigned char displayIndex = 0; // 数码管显示索引
    bit timerRunning = 0; // 计时器运行状态
    
    // 数码管段选码表
    unsigned char code digitSegments[10] = {
        0x3F, // 0
        0x06, // 1
        0x5B, // 2
        0x4F, // 3
        0x66, // 4
        0x6D, // 5
        0x7D, // 6
        0x07, // 7
        0x7F, // 8
        0x6F  // 9
    };
    
    // 延时函数
    void delay(unsigned int ms) {
        unsigned int i, j;
        for(i = 0; i < ms; i++) {
            for(j = 0; j < 120; j++);
        }
    }
    
    // 数码管位选函数
    void selectDigit(unsigned char digit) {
        digit1 = 1;
        digit2 = 1;
        digit3 = 1;
        switch(digit) {
            case 0: digit1 = 0; break;
            case 1: digit2 = 0; break;
            case 2: digit3 = 0; break;
        }
    }
    
    // 数码管段选函数
    void displayDigit(unsigned char digit, unsigned char data) {
        segmentA = (data & 0x01) ? 1 : 0;
        segmentB = (data & 0x02) ? 1 : 0;
        segmentC = (data & 0x04) ? 1 : 0;
        segmentD = (data & 0x08) ? 1 : 0;
        segmentE = (data & 0x10) ? 1 : 0;
        segmentF = (data & 0x20) ? 1 : 0;
        segmentG = (data & 0x40) ? 1 : 0;
        segmentDP = (data & 0x80) ? 1 : 0;
    }
    
    // 数码管显示函数
    void updateDisplay() {
        selectDigit(displayIndex);
        displayDigit(displayIndex, displayData[displayIndex]);
    }
    
    // 数码管刷新中断服务函数
    void timer0Interrupt() interrupt 1 {
        TH0 = 0x3C;
        TL0 = 0xB0;
        
        if (timerRunning) {
            if (currentTime[0] == 0 && currentTime[1] == 0 && currentTime[2] == 0) {
                buzzer = 1; // 计时时间到了,启动蜂鸣器
                timerRunning = 0; // 停止计时器
            } else {
                if (currentTime[2] > 0) {
                    currentTime[2]--;
                } else {
                    if (currentTime[1] > 0) {
                        currentTime[1]--;
                        currentTime[2] = 59;
                    } else {
                        if (currentTime[0] > 0) {
                            currentTime[0]--;
                            currentTime[1] = 59;
                            currentTime[2] = 59;
                        }
                    }
                }
            }
            
            if (displayIndex == 0) {
                displayData[0] = currentTime[0] / 10;
                displayData[1] = currentTime[0] % 10;
            } else if (displayIndex == 1) {
                displayData[0] = currentTime[1] / 10;
                displayData[1] = currentTime[1] % 10;
            } else if (displayIndex == 2) {
                displayData[0] = currentTime[2] / 10;
                displayData[1] = currentTime[2] % 10;
            }
            
            updateDisplay();
        }
    }
    
    // 按键中断服务函数
    void buttonInterrupt() interrupt 0 {
        if (!startStopButton) { // 启停按键
            if (!timerRunning) {
                timerRunning = 1;
            } else {
                timerRunning = 0;
            }
        }
        
        if (!resetButton) { // 复位按键
            currentTime[0] = 0;
            currentTime[1] = 0;
            currentTime[2] = 0;
            buzzer = 0; // 停止蜂鸣器
        }
        
        if (!toggleButton) { // 切换按键
            displayIndex++;
            if (displayIndex > 2) {
                displayIndex = 0;
            }
        }
        
        if (!incrementButton) { // 递增按键
            if (timerRunning) {
                buzzer = 0; // 停止蜂鸣器
                if (displayIndex == 0) {
                    if (currentTime[0] < 23) {
                        currentTime[0]++;
                    } else {
                        currentTime[0] = 0;
                    }
                } else if (displayIndex == 1) {
                    if (currentTime[1] < 59) {
                        currentTime[1]++;
                    } else {
                        currentTime[1] = 0;
                    }
                } else if (displayIndex == 2) {
                    if (currentTime[2] < 59) {
                        currentTime[2]++;
                    } else {
                        currentTime[2] = 0;
                    }
                }
                
                if (currentTime[0] == targetTime[0] && currentTime[1] == targetTime[1] && currentTime[2] == targetTime[2]) {
                    buzzer = 1; // 计时时间到了,启动蜂鸣器
                    timerRunning = 0; // 停止计时器
                }
            }
        }
        
        delay(50); // 延时去抖动
    }
    
    // 主函数
    void main() {
        TMOD = 0x01; // 设置定时器0为模式1
        TH0 = 0x3C; // 设置定时器0初值,用于定时1ms
        TL0 = 0xB0;
        ET0 = 1; // 允许定时器0中断
        EA = 1; // 允许总中断
        TR0 = 1; // 启动定时器0
        
        EX0 = 1; // 允许外部中断0(按键中断)
        IT0 = 1; // 设置外部中断0为下降沿触发
        
        displayIndex = 0;
        displayData[0] = 0;
        displayData[1] = 0;
        displayData[2] = 0;
        currentTime[0] = 0;
        currentTime[1] = 0;
        currentTime[2] = 0;
        targetTime[0] = 0;
        targetTime[1] = 0;
        targetTime[2] = 10; // 设置目标计时时间为10while (1) {
            if (timerRunning) {
                targetTime[0] = currentTime[0];
                targetTime[1] = currentTime[1];
                targetTime[2] = currentTime[2];
            }
            
            updateDisplay();
        }
    }
    
    
    评论
  • Jackyin0720 2023-06-10 20:26
    关注

    参考代码:

    #include <reg52.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
    #include <math.h>  
      
    #define uint unsigned int  
    #define uchar unsigned char  
      
    sbit led = P1^0; // 数码管位选  
    sbit led1 = P1^1;  
    sbit led2 = P1^2;  
    sbit led3 = P1^3;  
    sbit led4 = P1^4;  
    sbit buzzer = P1^5; // 蜂鸣器  
    sbit key1 = P3^2; // 按键1  
    sbit key2 = P3^3; // 按键2  
    sbit key3 = P3^4; // 按键3  
    sbit key4 = P3^5; // 按键4  
      
    uchar code数码管[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; // 数码管段码  
    uchar time[3] = {0, 0, 0}; // 计时时间,单位为秒  
    uchar flag = 0; // 计时标志位,1表示正在计时,0表示未计时  
    uchar key_state = 0; // 按键状态,记录最近一次按键状态,用于消除抖动  
      
    void delay_ms(uint x) { // 延时函数,单位为毫秒  
        uint i, j;  
        for (i = x; i > 0; i--) {  
            for (j = 114; j > 0; j--) {  
                _nop_();  
            }  
        }  
    }  
      
    void display() { // 显示函数,显示当前计时时间  
        P0 =数码管[time[2]]; // 显示秒位  
        led = 1; // 选择数码管第一位  
        delay_ms(1); // 延时一段时间,让数码管稳定显示  
        led = 0; // 选择下一数码管位  
        P0 =数码管[time[1]]; // 显示分钟位  
        led1 = 1; // 选择数码管第二位  
        delay_ms(1); // 延时一段时间,让数码管稳定显示  
        led1 = 0; // 选择下一数码管位  
        P0 =数码管[time[0]]; // 显示小时位  
        led2 = 1; // 选择数码管第三位  
        delay_ms(1); // 延时一段时间,让数码管稳定显示  
        led2 = 0; // 选择下一数码管位  
    }  
      
    void timer0() interrupt 1 { // Timer0中断函数,用于计时,每1ms中断一次  
        TH0 = 0xFC; // 重置Timer0初值高位  
        TL0 = 0x67; // 重置Timer0初值低位  
        if (flag) { // 如果正在计时  
            time[0]++; // 分钟加1if (time[0] == 60) { // 如果分钟加到60,则进位到小时,并重置分钟为0  
                time[0] = 0;  
                time[1] += 1; // 小时加1分钟  
                if (time[1] == 60) { // 如果小时加到60,则进位到小时,并重置小时为0,分钟为0  
                    time[1] = 0;  
                    time[2] += 1; // 总时间加1if (time[2] == 60) { // 如果总时间加到60秒,则进位到分钟,并重置总时间为0#未完待续
    
    评论
  • CSDN-Ada助手 CSDN-AI 官方账号 2023-06-10 22:05
    关注
    • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7465015
    • 除此之外, 这篇博客: 详细介绍如何从零开始制作51单片机控制的智能小车(二)———超声波模块、漫反射光电管、4路红外传感器的介绍和使用中的    每1路的传感器的红外发射管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来但强度不够大时,红外接收管一直处于关断状态,此时模块的TTL输出端为高电平,相应指示二极管一直处于熄灭状态;当被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管导通,此时模块的TTL输出端为低电平,指示二极管被点亮。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    •    简单点说,当传感器检测到障碍物时,对应的TTL输出低电平,比如第一路传感器信号线连接在单片机的P10口,当第一路传感器检测到障碍物时,单片机P10口就为低电平,也就是说通过读取传感器信号线连接的单片机I/O口的高低电平,就可以知道传感器前方有没有障碍物。

    评论
  • cyjbj 2023-06-11 11:17
    关注

    开发板基本都带有例程,把其中的定时器控制和按键控制例程结合一下,这点功能很容易实现了

    评论
  • 我姐让我换个名字 2023-06-11 21:49
    关注
    
    
    
    #include <reg51.h>
    
    // 定义 IO 引脚连接
    sbit keyStartStop = P1^0;   // 启停按键
    sbit keyReset = P1^1;       // 复位按键
    sbit keySwitch = P1^2;      // 切换按键
    sbit keyIncrement = P1^3;   // 递增按键
    
    sbit buzzer = P2^0;         // 蜂鸣器
    
    sbit segA = P2^4;           // 数码管段 A
    sbit segB = P2^5;           // 数码管段 B
    sbit segC = P2^6;           // 数码管段 C
    sbit segD = P2^7;           // 数码管段 D
    
    sbit digit1 = P0^0;         // 数码管位1
    sbit digit2 = P0^1;         // 数码管位2
    sbit digit3 = P0^2;         // 数码管位3
    
    // 全局变量
    unsigned int hours = 0;     // 小时
    unsigned int minutes = 0;   // 分钟
    unsigned int seconds = 0;   // 秒
    
    bit timerRunning = 0;       // 计时器是否正在运行
    
    // 数码管显示函数
    void displayDigits(unsigned int num) {
        // 数码管位选逻辑,根据具体硬件连接和驱动方式编写
        digit1 = 1;
        digit2 = 0;
        digit3 = 0;
    
        // 数码管显示逻辑,根据具体硬件连接和驱动方式编写
        // 例如,使用共阳数码管和段选锁存器的驱动方式
        switch(num / 100) {
            case 0:
                segA = segB = segC = segD = 0;  // 显示 0
                break;
            case 1:
                segA = 1; segB = segC = segD = 0;  // 显示 1
                break;
            // 其他数字的显示逻辑...
        }
    
        // 控制延时等待,以确保数码管刷新稳定
        // 具体延时时间根据硬件和显示器件的响应时间来确定
        // 可以通过调试和测试来优化延时时间
        delay();
        
        // 重复上述逻辑,显示分钟和秒的数码管位
    }
    
    // 延时函数
    void delay() {
        // 根据需要的延时时间和单片机的主频进行计算
        // 可以通过调试和测试来优化延时时间
        unsigned int i, j;
        for (i = 0; i < 1000; i++) {
            for (j = 0; j < 100; j++) {
                // 空循环来消耗一定的时间
            }
        }
    }
    
    // 计时器递增函数
    void incrementTimer() {
        seconds++;
        if (seconds >= 60) {
            seconds = 0;
            minutes++;
            if (minutes >= 60) {
                minutes = 0;
                hours++;
                if (hours >= 24) {
                    hours = 0;
                }
            }
        }
    }
    
    // 主函数
    void main() {
        // 初始化 IO 引脚状态
        keyStartStop = 1;
        keyReset = 1;
        keySwitch = 1;
        keyIncrement = 1;
    
        buzzer = 0;  // 关闭蜂鸣器
    
        // 主循环
        while(1) {
            // 检测启停按键
            if (keyStartStop == 0) {
                timerRunning = !timerRunning;  // 切换计时器运行状态
                while (keyStartStop == 0);  // 等待按键释放
            }
            
            // 检测复位按键
            if (keyReset == 0) {
                hours = minutes = seconds = 0;  // 将计时值归零
                buzzer = 0;  // 关闭蜂鸣器
                while (keyReset == 0);  // 等待按键释放
            }
            
            // 检测切换按键
            if (keySwitch == 0) {
                // 切换计时位的显示方式
                // 可以使用一个全局变量来控制显示方式,例如使用 24 小时制或 12 小时制
                while (keySwitch == 0);  // 等待按键释放
            }
            
            // 检测递增按键
            if (keyIncrement == 0) {
                incrementTimer();  // 递增计时器的时间
                while (keyIncrement == 0);  // 等待按键释放
            }
            
            // 显示当前计时时间
            displayDigits(hours * 100 + minutes);  // 显示小时和分钟
            
            // 如果计时器正在运行,则显示剩余时间
            if (timerRunning) {
                unsigned int remainingSeconds = (hours * 3600 + minutes * 60 + seconds);
                displayDigits(remainingSeconds);  // 显示剩余秒数
                
                // 检测计时时间是否到达
                if (remainingSeconds == 0) {
                    buzzer = 1;  // 启动蜂鸣器
                }
            }
            
            // 控制延时等待,以确保计时器刷新频率
            delay();
        }
    }
    
    
    
    

    请注意,以上代码示例是一个基本的框架,你需要根据具体的硬件电路和显示器件的驱动方式进行适当的修改。此外,延时函数的实现需要根据单片机的主频和需要的延时时间进行调整。在具体的硬件和电路连接中,你还需要确认按键的接线和设置外部中断来检测按键的状态变化。

    请确保你在编写和调试代码时参考相关的单片机手册和文档,并根据实际情况进行适当的修改和调整。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月12日
  • 创建了问题 6月10日

悬赏问题

  • ¥15 win11系统打开软件很慢
  • ¥30 XIAO esp32c3 读取FDC2214的数据
  • ¥15 在工控机(Ubuntu系统)上外接USB蓝牙硬件进行蓝牙通信
  • ¥15 关于PROCEDURE和FUNCTION的问题
  • ¥100 webapi的部署(标签-服务器)
  • ¥20 怎么加快手机软件内部计时的时间(关键词-日期时间)
  • ¥15 C语言除0问题的检测方法
  • ¥15 为什么四分管的内径有的是16mm有的15mm,四分不应该是12.7mm吗
  • ¥15 macos13下 ios交叉编译的问题
  • ¥15 bgz压缩文件怎么打开