单元训练04:数码管的动态显示

蓝桥杯 小蜜蜂 单元训练04:数码管的动态显示

updated coding:

更新月份取值使用/10与%10。

#include "stc15F2k60S2.h"

#define COM(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1F | 0xc0; \
        P2 &= 0x1F;            \
    }
// 位选
#define SEG(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1F | 0xE0; \
        P2 &= 0x1F;            \
    }

typedef unsigned char uint8_t; // 自定义类型,最长255;
typedef unsigned short uint16_t;
// 自定义类型,注意后面500ms计数要计到500,如果是u8类型,最长只有255,所以要用到16位unsigned short
uint8_t BoolTimeOn;
uint8_t TimerCounter = 0;        // 时间计数
uint16_t TimerHalfOneSecond = 0; // 0.5s标识
uint8_t BoolHalfOneSecond;

uint8_t PortEnabled;  // 选中的位选端口
uint8_t NumDisplayed; // 要显示的数字

uint8_t segStatus; // 数码管状态机

uint8_t ShowMonth;
// 共阳
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

        0x88, // A,10
        0x83, // b,11
        0xc6, // C,12
        0xa1, // d,13
        0x86, // E,14
        0x8e, // F,15
        0xBF  // 符号“-”,这个要自己计算,按照h高位,a低位,g显示时为字符-。16为下标位置,要清楚,不清楚标上注释,方便调用
}; // 表不用记,官方提供资源包里面有。

code uint8_t ShowInfos[] = {2, 0, 1, 8, 16, 16, 0, 1}; // 自定义显示内容,本节训练显示2018--01,01可增加到12再循环到01

void Timer0_Init(void) // 500微秒us@12.000MHz , 0.5 ms
{
    AUXR |= 0x80; // 定时器时钟1T模式
    TMOD &= 0xF0; // 设置定时器模式
    TL0 = 0x90;   // 设置定时初始值
    TH0 = 0xE8;   // 设置定时初始值
    TF0 = 0;      // 清除TF0标志
    TR0 = 1;      // 定时器0开始计时
    ET0 = 1;      // 使能定时器0中断
    EA = 1;
}

void OneSegDisplay(uint8_t ShowNum, uint8_t ShowPort) // 仅显示某个位选上的某个数字
{
    SEG(Seg_Table[ShowNum]); // 数字通过数组下标直接调用
    COM(ShowPort);           // 开启位选端口
}
void InitSeg()
{
    NumDisplayed = 0;   // 显示数字从0开始
    PortEnabled = 0x01; // 位选端口从最左边开始
    ShowMonth = 1;
}

void InitTimer()
{
    TimerCounter = 0;       // 时间计数
    TimerHalfOneSecond = 0; // 0.5s标识
    BoolTimeOn = 0;
    BoolHalfOneSecond = 0;
}
void DynamicSeg()
{
    switch (segStatus)
    {
    case 0: // 2,第1个显示
        PortEnabled = 0x01;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 1;
        break;
    case 1:                 // 0,第2个显示
        PortEnabled = 0x02; // 换成 PortEnabled = PortEnabled << 1会出现重影,未解决。
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 2;
        break;
    case 2: // 1,第3个显示,
        PortEnabled = 0x04;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 3;
        break;
    case 3: // 8,第4个显示
        PortEnabled = 0x8;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 4;
        break;
    case 4: // -,第5个显示
        PortEnabled = 0x10;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 5;
        break;
    case 5: // -,第6个显示
        PortEnabled = 0x20;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 6;
        break;
    case 6: // 月份十位
        PortEnabled = 0x40;
        OneSegDisplay(ShowMonth / 10, PortEnabled); // 十位固定显示0
        segStatus = 7;
        break;
    case 7: // 月份个位
        PortEnabled = 0x80;
        OneSegDisplay(ShowMonth % 10, PortEnabled); // 个位显示
        segStatus = 8;
        break;
    case 8:
        if (BoolHalfOneSecond) // 如果达到设定的增长间隔时间,这里用第2个定时器Timer1也可以实现。
        {
            ShowMonth++;
            BoolHalfOneSecond = 0;
        }

        if (ShowMonth == 13) // 如果1-12已经循环显示完,重新循环
        {
            ShowMonth = 1;
        }
        segStatus = 0; // 回到状态0
        break;

    default:
        segStatus = 0;
        PortEnabled = 0x01;
        ShowMonth = 1;
        break;
    }
}
void main()
{
    InitSeg();
    InitTimer();

    Timer0_Init();
    while (1)
    {
        if (BoolTimeOn)
            DynamicSeg();
        BoolTimeOn = 0;
    }
}

void Timer0_Isr(void) interrupt 1
{
    TimerCounter++;
    if (TimerCounter == 2) // 500us间隔,1ms或2ms闪烁比较大,
    {
        BoolTimeOn = 1;
        TimerCounter = 0;

        TimerHalfOneSecond++;
        if (TimerHalfOneSecond == 500) // 500ms
        {
            BoolHalfOneSecond = 1;
            TimerHalfOneSecond = 0;
        }
    }
}

the 1st  coding:

#include "stc15F2k60S2.h"

#define COM(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1F | 0xc0; \
        P2 &= 0x1F;            \
    }
// 位选
#define SEG(x)                 \
    {                          \
        P0 = x;                \
        P2 = P2 & 0x1F | 0xE0; \
        P2 &= 0x1F;            \
    }

typedef unsigned char uint8_t; // 自定义类型,最长255;
typedef unsigned short uint16_t;
// 自定义类型,注意后面500ms计数要计到500,如果是u8类型,最长只有255,所以要用到16位unsigned short
uint8_t BoolTimeOn;
uint8_t TimerCounter = 0;        // 时间计数
uint16_t TimerHalfOneSecond = 0; // 0.5s标识
uint8_t BoolHalfOneSecond;

uint8_t PortEnabled;  // 选中的位选端口
uint8_t NumDisplayed; // 要显示的数字

uint8_t segStatus; // 数码管状态机

uint8_t ShowMonth;
// 共阳
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

        0x88, // A,10
        0x83, // b,11
        0xc6, // C,12
        0xa1, // d,13
        0x86, // E,14
        0x8e, // F,15
        0xBF  // 符号“-”,这个要自己计算,按照h高位,a低位,g显示时为字符-。16为下标位置,要清楚,不清楚标上注释,方便调用
}; // 表不用记,官方提供资源包里面有。

code uint8_t ShowInfos[] = {2, 0, 1, 8, 16, 16, 0, 1}; // 自定义显示内容,本节训练显示2018--01,01可增加到12再循环到01

void Timer0_Init(void) // 500微秒us@12.000MHz , 0.5 ms
{
    AUXR |= 0x80; // 定时器时钟1T模式
    TMOD &= 0xF0; // 设置定时器模式
    TL0 = 0x90;   // 设置定时初始值
    TH0 = 0xE8;   // 设置定时初始值
    TF0 = 0;      // 清除TF0标志
    TR0 = 1;      // 定时器0开始计时
    ET0 = 1;      // 使能定时器0中断
    EA = 1;
}

void OneSegDisplay(uint8_t ShowNum, uint8_t ShowPort) // 仅显示某个位选上的某个数字
{
    SEG(Seg_Table[ShowNum]); // 数字通过数组下标直接调用
    COM(ShowPort);           // 开启位选端口
}
void InitSeg()
{
    NumDisplayed = 0;   // 显示数字从0开始
    PortEnabled = 0x01; // 位选端口从最左边开始
    ShowMonth = 1;
}

void InitTimer()
{
    TimerCounter = 0;       // 时间计数
    TimerHalfOneSecond = 0; // 0.5s标识
    BoolTimeOn = 0;
    BoolHalfOneSecond = 0;
}
void DynamicSeg()
{
    switch (segStatus)
    {
    case 0: // 2,第1个显示
        PortEnabled = 0x01;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 1;
        break;
    case 1:                 // 0,第2个显示
        PortEnabled = 0x02; // 换成 PortEnabled = PortEnabled << 1会出现重影,未解决。
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 2;
        break;
    case 2: // 1,第3个显示,
        PortEnabled = 0x04;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 3;
        break;
    case 3: // 8,第4个显示
        PortEnabled = 0x8;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 4;
        break;
    case 4: // -,第5个显示
        PortEnabled = 0x10;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 5;
        break;
    case 5: // -,第6个显示
        PortEnabled = 0x20;
        OneSegDisplay(ShowInfos[segStatus], PortEnabled);
        segStatus = 6;
        break;
    case 6: // 月份十位
        PortEnabled = 0x40;
        if (ShowMonth < 10)
            OneSegDisplay(0, PortEnabled); // 十位固定显示0
        else
            OneSegDisplay(1, PortEnabled); // 十位固定显示1
        segStatus = 7;
        break;
    case 7: // 月份个位
        PortEnabled = 0x80;
        if (ShowMonth < 10)
        {
            OneSegDisplay(ShowMonth, PortEnabled); // 个位显示
        }
        else
            OneSegDisplay(ShowMonth - 10, PortEnabled); // 个位显示
        segStatus = 8;
        break;
    case 8:
        if (BoolHalfOneSecond) // 如果达到设定的增长间隔时间,这里用第2个定时器Timer1也可以实现。
        {
            ShowMonth++;
            BoolHalfOneSecond = 0;
        }

        if (ShowMonth == 13) // 如果1-12已经循环显示完,重新循环
        {
            ShowMonth = 1;
        }
        segStatus = 0; // 回到状态0
        break;

    default:
        segStatus = 0;
        PortEnabled = 0x01;
        ShowMonth = 1;
        break;
    }
}
void main()
{
    InitSeg();
    InitTimer();

    Timer0_Init();
    while (1)
    {
        if (BoolTimeOn)
            DynamicSeg();
        BoolTimeOn = 0;
    }
}

void Timer0_Isr(void) interrupt 1
{
    TimerCounter++;
    if (TimerCounter == 2) // 500us间隔,1ms或2ms闪烁比较大,
    {
        BoolTimeOn = 1;
        TimerCounter = 0;

        TimerHalfOneSecond++;
        if (TimerHalfOneSecond == 500) // 500ms
        {
            BoolHalfOneSecond = 1;
            TimerHalfOneSecond = 0;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zfdc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值