- 打卡等级:常住居民I
- 打卡总天数:66
- 最近打卡:2025-08-01 07:20:48
已绑定手机
注册会员
- 积分
- 98
|
发表于 2025-7-7 17:06:19
|
显示全部楼层
学习感悟之实战:第九集 数码管
学习了本集,购买配件做了一个时钟,几块钱的成本:一块TM1637显示模块、一块STC8G1K08A核心板、2个按钮开关,在面包板连接测试没问题。
#include <STC8G.H>
#include <intrins.h>
// 定义TM1637引脚
sbit TM1637_CLK = P5^4;
sbit TM1637_DIO = P5^5;
// 定义按键引脚
sbit KEY_UP = P3^2; // 调分钟加
sbit KEY_DOWN = P3^3; // 调小时加
// 数码管显示缓冲区
unsigned char DisplayBuffer[4] = {0, 0, 0, 0};
// 时间变量
unsigned char hour = 12;
unsigned char minute = 0;
unsigned char second = 0;
bit blink_state = 0;
// 数码管编码表 (共阳数码管)
// 位定义: DP-G-F-E-D-C-B-A
const unsigned char SegmentCode[] = {
0x3F, // 0 (00111111)
0x06, // 1 (00000110)
0x5B, // 2 (01011011)
0x4F, // 3 (01001111)
0x66, // 4 (01100110)
0x6D, // 5 (01101101)
0x7D, // 6 (01111101)
0x07, // 7 (00000111)
0x7F, // 8 (01111111)
0x6F // 9 (01101111)
};
// 精确延时函数
void DelayUs(unsigned char t)
{
while(t--);
}
// TM1637起始信号
void TM1637_Start()
{
TM1637_CLK = 1;
TM1637_DIO = 1;
DelayUs(2);
TM1637_DIO = 0;
DelayUs(2);
TM1637_CLK = 0;
DelayUs(2);
}
// TM1637停止信号
void TM1637_Stop()
{
TM1637_CLK = 0;
TM1637_DIO = 0;
DelayUs(2);
TM1637_CLK = 1;
DelayUs(2);
TM1637_DIO = 1;
DelayUs(2);
}
// TM1637写一个字节
bit TM1637_WriteByte(unsigned char data_val)
{
unsigned char i;
bit ack;
for(i = 0; i < 8; i++)
{
TM1637_CLK = 0;
DelayUs(2);
TM1637_DIO = (data_val & 0x01) ? 1 : 0;
data_val >>= 1;
DelayUs(2);
TM1637_CLK = 1;
DelayUs(2);
}
TM1637_CLK = 0;
TM1637_DIO = 1;
DelayUs(2);
TM1637_CLK = 1;
DelayUs(2);
ack = TM1637_DIO;
TM1637_CLK = 0;
DelayUs(2);
return ack;
}
// 设置显示数据
void TM1637_SetDisplay()
{
unsigned char i;
TM1637_Start();
TM1637_WriteByte(0x40); // 数据命令: 固定地址, 普通模式
TM1637_Stop();
TM1637_Start();
TM1637_WriteByte(0xC0); // 地址命令: 从地址0开始
for(i = 0; i < 4; i++)
{
TM1637_WriteByte(DisplayBuffer);
}
TM1637_Stop();
TM1637_Start();
TM1637_WriteByte(0x88); // 显示控制: 开显示, 0x8F亮度最大,0x88最小
TM1637_Stop();
}
// 更新显示缓冲区
void UpdateDisplayBuffer()
{
DisplayBuffer[0] = SegmentCode[hour / 10]; // 小时十位
DisplayBuffer[1] = SegmentCode[hour % 10]; // 小时个位
DisplayBuffer[2] = SegmentCode[minute / 10]; // 分钟十位
DisplayBuffer[3] = SegmentCode[minute % 10]; // 分钟个位
// 添加冒号(秒闪烁)
if(blink_state)
{
DisplayBuffer[1] |= 0x80; // 设置小数点(冒号)
}
else
{
DisplayBuffer[1] &= 0x7F; // 清除小数点(冒号)
}
}
// 初始化定时器0
void Timer0_Init()
{
AUXR &= 0x7F; // 定时器时钟12T模式
TMOD &= 0xF0; // 设置定时器模式
TMOD |= 0x01; // 16位定时器模式
TH0 = 0xFC; // 设置定时初值(1ms)
TL0 = 0x66;
TR0 = 1; // 启动定时器0
ET0 = 1; // 允许定时器0中断
EA = 1; // 开总中断
}
//// 延时函数
//void DelayMs(unsigned int ms)
//{
// unsigned int i, j;
// for(i = 0; i < ms; i++)
// for(j = 0; j < 1000; j++);
//}
// 按键扫描函数(改进版)
void KeyScan() {
static unsigned char key_up_cnt = 0;
static unsigned char key_down_cnt = 0;
static unsigned char key_both_cnt = 0;
static bit key_up_pressed = 0;
static bit key_down_pressed = 0;
static bit key_both_pressed = 0;
// 检测同时按下
if(KEY_UP == 0 && KEY_DOWN == 0) {
key_both_cnt++;
if(key_both_cnt > 5 && !key_both_pressed) {
key_both_pressed = 1;
if(++hour >= 24) hour = 0;
UpdateDisplayBuffer();
TM1637_SetDisplay();
}
} else {
key_both_cnt = 0;
key_both_pressed = 0;
}
// 检测单独按下P3.2(分钟增加)
if(KEY_UP == 0 && KEY_DOWN == 1) {
key_up_cnt++;
if(key_up_cnt > 5 && !key_up_pressed) {
key_up_pressed = 1;
if(++minute >= 60) minute = 0;
second = 0; //同时复位秒
UpdateDisplayBuffer();
TM1637_SetDisplay();
}
} else {
key_up_cnt = 0;
key_up_pressed = 0;
}
// 检测单独按下P3.3(分钟减少)
if(KEY_DOWN == 0 && KEY_UP == 1) {
key_down_cnt++;
if(key_down_cnt > 5 && !key_down_pressed) {
key_down_pressed = 1;
if(--minute >= 60) minute = 59;
second = 0; //同时复位秒
UpdateDisplayBuffer();
TM1637_SetDisplay();
}
} else {
key_down_cnt = 0;
key_down_pressed = 0;
}
}
// 主函数
void main()
{
// 初始化IO口
P3M0 &= ~(0x0C); // P3.2和P3.3设置为准双向口
P3M1 &= ~(0x0C);
P5M0 &= ~(0x30); // P5.4和P5.5设置为准双向口
P5M1 &= ~(0x30);
// 启用内部上拉电阻
P3 |= 0x0C; // P3.2和P3.3上拉
// 初始化定时器
Timer0_Init();
// 初始化显示
UpdateDisplayBuffer();
TM1637_SetDisplay();
while(1)
{
KeyScan();
}
}
// 定时器0中断服务函数
void Timer0_ISR() interrupt 1
{
static unsigned int count = 0;
TH0 = 0xFC; // 重新加载初值(1ms)
TL0 = 0x66;
count++;
if(count >= 1004) // 1秒(加或减1会使每天影响86.4秒)
{
count = 0;
second++;
blink_state = ~blink_state; // 闪烁状态切换
if(second >= 60)
{
second = 0;
minute++;
if(minute >= 60)
{
minute = 0;
hour++;
if(hour >= 24)
{
hour = 0;
}
}
}
// 更新显示
UpdateDisplayBuffer();
TM1637_SetDisplay();
}
}
|
|