蓝桥杯 小蜜蜂 单元训练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;
}
}
}