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

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

img


#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();
    }
}

参考代码:

#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#未完待续
  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7465015
  • 除此之外, 这篇博客: 详细介绍如何从零开始制作51单片机控制的智能小车(二)———超声波模块、漫反射光电管、4路红外传感器的介绍和使用中的    每1路的传感器的红外发射管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来但强度不够大时,红外接收管一直处于关断状态,此时模块的TTL输出端为高电平,相应指示二极管一直处于熄灭状态;当被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管导通,此时模块的TTL输出端为低电平,指示二极管被点亮。 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  •    简单点说,当传感器检测到障碍物时,对应的TTL输出低电平,比如第一路传感器信号线连接在单片机的P10口,当第一路传感器检测到障碍物时,单片机P10口就为低电平,也就是说通过读取传感器信号线连接的单片机I/O口的高低电平,就可以知道传感器前方有没有障碍物。

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




#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();
    }
}


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

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