冲刺单片机设计与开发:数码管驱动实战练习与提升指南 4.3.5版
4.3.5练习提升
1、固定使用2位数码管显示60s倒计时,高位数码管熄灭。
2、数码管最高位显示固定字符U,固定使用2位数码管显示60s倒计时,高位数码管熄灭。倒计时结束5s后,重新开始 倒计时。计时过程中指示灯L1点亮,L2熄灭,计时结束后L1熄灭,L2以0.1s为间隔切换亮灭状态。其余指示灯均处于 熄灭状态。
/*
* @Description:
* @Author: fdzhang
* @Email: zfdc@qq.com
* @Date: 2024-08-19 07:55:08
* @LastEditTime: 2024-08-19 11:45:44
* @LastEditors: fdzhang
*/
#include "stc15f2k60s2.h"
#include "intrins.h"
typedef unsigned char uint8_t;
uint8_t Led2Info = 0xFD; // led 2 on
uint8_t ledInfo;
uint8_t basicTimerCounter = 0; // 基础 计时计数
uint8_t Sec1TimerCounter = 0; // 1s计数
uint8_t sec5GapTimerCounter = 0; // 间隔5s计数,实际达到6s
uint8_t boolCounterDot1s = 0; // 达到0.1s
uint8_t boolCounter1s = 0; // 达到1s
uint8_t boolCounter5sGap = 0; // 达到5s
uint8_t secStatus = 0;
uint8_t countDownStatus = 0;
#define lightLED(x) \
{ \
P2 = P2 & 0x1f | 0x80; \
P0 = x; \
P2 &= 0x1f; \
}
#define lightSEG(x) \
{ \
P0 = x; \
P2 = P2 & 0x1f | 0xe0; \
P2 &= 0x1f; \
}
#define lightCOM(x) \
{ \
P0 = x; \
P2 = P2 & 0x1f | 0xc0; \
P2 &= 0x1f; \
}
// 定义控制蜂鸣器
#define Buzz(x) \
{ \
P0 = x; \
P2 = P2 & 0x1F | 0xA0; \
P2 &= 0x1F; \
}
#define L1 0xFE // 定义LED 1
#define L2 0xFD
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, // A10
0x83, // b11
0xc6, // C12
0xa1, // d13
0x86, // E14
0x8e, // F15
0xc1, // 符号 U,16
0xff // all off,17
};
void Timer0_Init(void) // 5毫秒@12.000MHz
{
AUXR |= 0x80; // 定时器时钟1T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0xA0; // 设置定时初始值
TH0 = 0x15; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 使能定时器0中断
EA = 1;
}
void Delay1ms() //@12.000MHz
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j)
;
} while (--i);
}
void lightL1() // 点亮L1
{
lightLED(L1);
}
uint8_t blinkStatus;
void blinkL2() // L2闪烁
{
ledInfo = Led2Info;
switch (blinkStatus)
{
case 0:
if (boolCounterDot1s) // 1秒翻转
{
lightLED(ledInfo);
blinkStatus = 1;
boolCounterDot1s = 0;
}
break;
case 1:
if (boolCounterDot1s)
{
ledInfo ^= ~Led2Info;
lightLED(ledInfo);
blinkStatus = 0;
boolCounterDot1s = 0;
}
break;
default:
blinkStatus = 0;
break;
}
}
void showU() // 显示字符U
{
lightCOM(0x01);
lightSEG(Seg_Table[16]);
Delay1ms();
Delay1ms();
}
void showSec10(uint8_t sec10) // 秒10位显示
{
lightCOM(0x40);
lightSEG(Seg_Table[sec10]);
Delay1ms();
}
void showSec1(uint8_t sec1) // 秒个位显示
{
lightCOM(0x80);
lightSEG(Seg_Table[sec1]);
Delay1ms();
}
void showSeconds(uint8_t seconds)
{
switch (secStatus)
{
case 0:
showU();
lightL1();
secStatus = 1;
break;
case 1:
showSec10(seconds / 10);
secStatus = 2;
break;
case 2:
showSec1(seconds % 10);
secStatus = 0;
break;
default:
secStatus = 0;
break;
}
}
void secCountDown(uint8_t seconds)
{
switch (countDownStatus)
{
case 0: // 60s倒计时
while (1)
{
showSeconds(seconds);
if (boolCounter1s)
{
seconds--;
boolCounter1s = 0;
if (seconds == -1)
break;
}
}
countDownStatus = 1;
boolCounter5sGap = 0;
break;
case 1:
if (!boolCounter5sGap) // 间隔5s,L2以0.1s切换亮灭
{
showU();
blinkL2();
}
else
{
countDownStatus = 0;
}
break;
}
}
void main()
{
Timer0_Init();
lightLED(0xff);
while (1)
{
secCountDown(60);
}
}
void Timer0_Isr(void) interrupt 1
{
// 5毫秒@12.000MHz,0.1s,100ms,计20次
if (basicTimerCounter++ == 20)
{
basicTimerCounter = 0;
boolCounterDot1s = 1; // 0.1s
// 5毫秒@12.000MHz,1s,1000ms,计200次
// 0.1秒@12.000MHz,1s,10*0.1s,计10次
if (Sec1TimerCounter++ == 10) // 1s
{
Sec1TimerCounter = 0;
boolCounter1s = 1;
if (sec5GapTimerCounter++ == 6) // 计到6秒,间隔5s
{
sec5GapTimerCounter = 0;
boolCounter5sGap = 1;
}
}
}
}
作者:zfdc