使用80c51单片机与四位数码管实现按键暂停启动的秒级计时器。

前置知识

在实现秒级计时器前,必须要了解的一些知识。

按键的使用

按键(按钮)即Button是在单片机中非常常见的一种硬件,按键作为一种用户和单片机进行交互的工具十分重要。按键通常有两种状态:“按下”与“抬起”,正常状态是“抬起”的,按键被按下后电平发生改变。

按键按下再抬起后波形如下图

按键示波器波形

通过获取按键的状态来实现与用户进行交互

在本文将通过获取用户按下一次按键后来停止计时器,用户再次按下,则再次启动计时器。按下一次按键包括两个状态:“按下”与“抬起”,使用下方原理图的连接方式,则按键所连接的引脚电平将先在按下时升高,电流成凹形方波。

原理图部分

示波器电路+按键电路+四位数码管电路+80c51单片机

其中单片机使用的晶体振荡器频率为12MHz

原理图

代码部分

代码逻辑

计时部分

  1. 使用全局结构体存储数码管要显示的数据以及计时的时间
  2. 设置定时器,每过一秒更新计时,同时根据计时的时间设置数码管要显示的数据
  3. 在主函数的循环中显示该数据

按键部分

通过使用查询法来检测按键状态。

  1. 通过在主函数不断检测按键对应连接的并行口的电平来获取按键状态
  2. 在电平改变(按键状态改变)后设置标志位,开始对电平改变持续的时间计时
  3. 计时通过使用定时器维护的一个全局变量,该变量每次触发中断时自减1
  4. 若电平改变持续的时间大于设定的值且按键被“抬起”即电平恢复,则对控制定时器停止计时

完整代码

代码在Keil 5中编译通过(0-Error,0-Warning)

#include <reg51.h>
#include <math.h>

// 布尔类型
#define bool bit
#define true 1
#define false 0

#define T_MAX 4000
int CountMax = T_MAX;
int Count = T_MAX;

bool isUpdate = true;
sbit Button = P1 ^ 0;

struct DTs
{
    char DT1;
    char DT2;
    char DT3;
    char DT4;
};

struct TimeS
{
    char min;
    char sec;
};

struct DTs dts = {0x3F, 0x3F, 0x3F, 0x3F};
struct TimeS NowTime = {0, 0};

//初始化定时器
void InitTimer()
{
    TMOD = 0x02;
    TH0 = 0x06;
    TL0 = 0x06;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}

void Set_Dts(int dat)
{
    char i = 0, j = 1000;
    char Code_Table[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
    dts.DT1 = Code_Table[(dat % 10000) / 1000];
    dts.DT2 = Code_Table[(dat % 1000) / 100];
    dts.DT3 = Code_Table[(dat % 100) / 10];
    dts.DT4 = Code_Table[(dat % 10) / 1];
}

//更新数码管要显示的时间
void Update()
{
    ++NowTime.sec;
    if (NowTime.sec > 59)
    {
        ++NowTime.min;
        NowTime.sec = 0;
        if (NowTime.min > 59)
        {
            NowTime.min = 0;
        }
    }
    Set_Dts(NowTime.min * 100 + NowTime.sec);
}

void Timer_Interrupt() interrupt 1
{
    if (Count)
    {
        --Count;
        return;
    }
    Count = CountMax;
    if (isUpdate)
    {
        Update();
    }
}

void DT_Show()
{
    char i = 1;
    char *p = &dts.DT1;
    for (; i < 16; i *= 2, p++)
    {
        P0 = 0x00;
        P2 = ~i;
        P0 = *p;
    }
}

void main()
{
    //按键按下计时
    int t0 = 0;            //计时起始值
    bool BtnSig = true; //是否计时

    InitTimer();
    while (1)
    {
        DT_Show();
        //处理按键产生的信号
        if (BtnSig)
        {
            if (!Button)
            {
                t0 = Count;
                BtnSig = false;
            }
        }
        else
        {
            //按键按下未达到50ms
            if (abs(t0 - Count) < 200)
            {
                if (Button)
                {
                    //取消本次按键按下计时
                    BtnSig = true;
                }
            }
            //按键按下达到50ms
            else
            {
                if (!Button)
                {
                    //对是否更新时间的标志位取反
                    isUpdate = ~isUpdate;
                    //等待下一次按键按下计时
                    BtnSig = true;
                }
            }
        }
    }
}

结语

最难的地方是按键相关的代码,在实际的按键使用的情况下,按键要应该要有一定的容错率,要去处理“消抖”,而且检测按键按下持续时间对于提高按键容错非常重要,设置一个合理的检测阈值能很好的提高按键容错率。

Last modification:May 18th, 2020 at 11:01 am