蓝桥杯 小蜜蜂   单元训练10:定时器实现秒表功能-数组方式

单元训练10:定时器实现秒表功能-数组方式-LMLPHP

/*
 * @Description:
 * @Author: fdzhang
 * @Email: zfdc@qq.com
 * @Date: 2024-08-15 21:58:53
 * @LastEditTime: 2024-08-16 19:07:27
 * @LastEditors: fdzhang
 */

#include "stc15f2k60s2.h"

#define LED(x)                 \
    {                          \
        P2 = P2 & 0x1f | 0x80; \
        P0 = x;                \
        P2 &= 0x1f;            \
    }
// y7c 111,0xE0
#define SEG(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1f | 0xE0; \
        P2 &= 0x1f;            \
    }
// y6c 110,0xC0
#define COM(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1f | 0xC0; \
        P2 &= 0x1f;            \
    }

typedef unsigned char uint8_t;

uint8_t *setStopWatch(uint8_t min10, uint8_t min1, uint8_t sec10, uint8_t sec1, uint8_t ms10, uint8_t ms1)
{
    uint8_t *stopWatchTimer[6];
    *stopWatchTimer[0] = min10;
    *stopWatchTimer[1] = min1;
    *stopWatchTimer[2] = sec10;
    *stopWatchTimer[3] = sec1;
    *stopWatchTimer[4] = ms10;
    *stopWatchTimer[5] = ms1;
    return stopWatchTimer;
}

uint8_t com1 = 0x01; // 定义数码管的8个口
uint8_t com2 = 0x02;
uint8_t com3 = 0x04;
uint8_t com4 = 0x08;
uint8_t com5 = 0x10;
uint8_t com6 = 0x20;
uint8_t com7 = 0x40;
uint8_t com8 = 0x80;

sbit s4 = P3 ^ 3; // 定义按键
sbit s5 = P3 ^ 2;

code unsigned char Seg_Table[] =
    {
        0xc0, // 0
        0xf9, // 1
        0xa4, // 2
        0xb0, // 3
        0x99, // 4
        0x92, // 5
        0x82, // 6
        0xf8, // 7
        0x80, // 8
        0x90, // 9
        0xBF  // 符号"-"
};

uint8_t timerCounter = 0;
uint8_t counter50ms = 0;
uint8_t counter1s = 0;
uint8_t counter1min = 0;
uint8_t counter1h = 0;

void Timer0_Init(void) // 5毫秒@12MHz
{
    AUXR |= 0x80; // 定时器时钟1T模式
    TMOD &= 0xF0; // 设置定时器模式
    TL0 = 0xA0;   // 设置定时初始值
    TH0 = 0x15;   // 设置定时初始值
    TF0 = 0;      // 清除TF0标志
    // TR0 = 1;      // 定时器0开始计时 //因为题目要求可以暂停,所以一开始不要打开
    ET0 = 1; // 使能定时器0中断
    EA = 1;
}
// 使用STC - ISP中的延时计算器生成,
// 不想再使用定时器1生成时间间隔了,有些麻烦。
// 注意,延时500us会有重影
void Delay1ms() //@12.000MHz 使用STC-ISP中的延时计算器生成
{
    unsigned char i, j;
    i = 2;
    j = 239;
    do
    {
        while (--j)
            ;
    } while (--i);
}

void oneSegShow(uint8_t comX, uint8_t showNum) // 单数码管显示
{
    COM(comX);
    SEG(Seg_Table[showNum]);
}
void min10Seg1(uint8_t min10) // 1管显示分10位
{
    oneSegShow(com1, min10);
}
void min1Seg2(uint8_t min1) // 2管显示分个位
{
    oneSegShow(com2, min1);
}
void dashSeg3() // 3管显示符号-
{
    oneSegShow(com3, 10);
}
void sec10Seg4(uint8_t sec10) // 4管显示秒10位
{
    oneSegShow(com4, sec10);
}
void sec1Seg5(uint8_t sec1) // 5管显示秒个位
{
    oneSegShow(com5, sec1);
}
void dashSeg6() // 6管显示符号-
{
    oneSegShow(com6, 10);
}
void ms10Seg7(uint8_t ms10) // 7管显示毫秒10位
{
    oneSegShow(com7, ms10);
}
void ms1Seg8(uint8_t ms1) // 8管显示毫秒个位
{
    oneSegShow(com8, ms1);
}

uint8_t arrayStatus;                         // 状态机显示方式
void segsAllShowFSM(uint8_t *stopWatchTimer) // Finite state machine
{
    switch (arrayStatus)
    {
    case 0:
        min10Seg1(stopWatchTimer[0]);
        Delay1ms();
        arrayStatus = 1;
        break;
    case 1:
        min1Seg2(stopWatchTimer[1]);
        Delay1ms();
        arrayStatus = 2;
        break;
    case 2:
        dashSeg3();
        Delay1ms();
        arrayStatus = 3;
        break;
    case 3:
        sec10Seg4(stopWatchTimer[3]);
        Delay1ms();
        arrayStatus = 4;
        break;
    case 4:
        sec1Seg5(stopWatchTimer[4]);
        Delay1ms();
        arrayStatus = 5;
        break;
    case 5:
        dashSeg6();
        Delay1ms();
        arrayStatus = 6;
        break;
    case 6:
        ms10Seg7(stopWatchTimer[5]);
        Delay1ms();
        arrayStatus = 7;
        break;
    case 7:
        ms1Seg8(stopWatchTimer[6]);
        Delay1ms();
        arrayStatus = 0;
        break;

    default:
        arrayStatus = 0;
        break;
    }
}

uint8_t s4Status;
uint8_t falling;
uint8_t counterOnOff = 0;

uint8_t keyStatus;
uint8_t keyValue;

void readKey()
{
    switch (keyStatus)
    {
    case 0:
        if ((s4 == 0) | (s5 == 0))
        {
            keyStatus = 1;
            falling = 1;
            keyStatus = 1;
        }
        break;
    case 1:
        if (s5 == 0)
        {
            keyValue = 5;
        }
        else if (s4 == 0)
        {
            keyValue = 4;
        }
        if (falling)
        {
            counterOnOff = ~counterOnOff;
        }
        if ((s4 == 0) | (s5 == 0)) // 如果长按锁定在当前状态
        {
            falling = 0;
            keyStatus = 1;
        }
        else
            keyStatus = 2;
        break;
    case 2:
        if ((s4 == 1) && (s5 == 1))
            keyStatus = 0;
    default:
        keyStatus = 0;
        break;
    }
}
void keyScan()
{
    uint8_t *arrayTimer;
    uint8_t ms10;
    uint8_t ms1;
    uint8_t sec10;
    uint8_t sec1;
    uint8_t min10;
    uint8_t min1;
    readKey();

    if (keyValue == 5)
    {

        timerCounter = 0; // 清零
        counter50ms = 0;
        counter1s = 0;
        counter1min = 0;
        counter1h = 0;

        ms10 = counter50ms / 10;
        ms1 = counter50ms % 10;
        sec10 = counter1s / 10;
        sec1 = counter1s % 10;
        min10 = counter1min / 10;
        min1 = counter1min % 10;

        arrayTimer = setStopWatch(min10, min1, sec10, sec1, ms10, ms1);
        segsAllShowFSM(arrayTimer);
    }
    else if (keyValue == 4)
    {
        ms10 = counter50ms / 10;
        ms1 = counter50ms % 10;
        sec10 = counter1s / 10;
        sec1 = counter1s % 10;
        min10 = counter1min / 10;
        min1 = counter1min % 10;

        arrayTimer = setStopWatch(min10, min1, sec10, sec1, ms10, ms1);
        segsAllShowFSM(arrayTimer);

        if (counterOnOff)
        {
            TR0 = 1; // open timer启动恢复
        }
        else
        {
            TR0 = 0; // pause timer//暂停
        }
    }
}
void main()
{
    LED(0xff); // 关闭LED
    COM(0xFF); // 关闭数码管

    // SEG(Seg_Table[0]);

    Timer0_Init();

    while (1)
    {
        keyScan();
    }
}

void Timer0_Isr(void) interrupt 1
{
    if (++timerCounter == 10) // 5毫秒为基本单位,50ms为一个计时单元
    {
        timerCounter = 0;
        if (++counter50ms == 20) // 1s
        {
            counter50ms = 0;       // 数码管显示的毫秒的数值
            if (++counter1s == 60) // 1min
            {
                counter1s = 0;           // 数码管显示的秒的数值
                if (++counter1min == 60) // 1h
                {
                    counter1min = 0; // 数码管显示的分的数值
                }
            }
        }
    }
}
08-17 05:15