51单片机+DS1302+MAX7219驱动8位共阴数码管显示时间

51单片机+DS1302+MAX7219驱动8位共阴数码管显示时间


  • 📺Proteus仿真
    在这里插入图片描述

🔖显示效果上的年和日顺序已经在代码中位置对调过来了,不在重新录制效果图了。

  • 🌿采用外部中断0,用来切换时间和日期显示。
  • 🌿采用定时器0,一秒钟更新一次时间。

主程序代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <reg52.h>
#include <intrins.h>
#include <string.h>
#include<DS1302.h>

typedef unsigned char u8;
typedef unsigned int u16;

sbit DIN = P2^0; //数据串出引脚
sbit CS = P2^1; //片选端
sbit CLK = P2^2; //移位时钟端
/\*\*\*外部中断和定时T0中断标志位\*\*\*\*/
u8 volatile State = 1;
u8 volatile flags = 1; //1秒定时标志

unsigned char Date_buff[3] = {0, 0,0};//数码管显示缓冲区,初值0xFF确保启动时都不亮
unsigned char Time_buff[3] = {0,0,0};
//显示的数字,数值为10的时候,显示“-”

/\*\*\*\*定时器T0初始化\*\*\*\*\*/
void TimeInit()
{
EA = 1; //打开中断总开关
EX0=1; //开外部中断0
IT0=1; //外部中断0边沿触发
ET0 = 1; //打开T0中断开关
TMOD = 0x01; //设置定时器工作在模式1
TH0=(65536-5000)/256; //高四位寄存器的值;//5000us=5ms
TL0=(65536-5000)%256; //低四位寄存器的值;
TR0 = 1; //允许定时器T0工作
}
void UpDate();
void DisTime();
void DisDate();
void delayms(unsigned int x)
{
unsigned char i;
while(x--)
{
for(i = 0; i < 120; i++);
}
}
//写数据函数
void write\_data(unsigned char addr,unsigned char dat)
{
unsigned char i;
CS = 0; // 先写地址,片选置低,串行数据加载到移位寄存器
for(i = 0; i < 8; i++) //
{
CLK = 0; //时钟上升沿数据移入内部移位寄存器
addr <<= 1; //待发送的地址,每次左移一次,高位在前发送,
DIN = CY; //数据移位后,如果有溢出,则可以从进位位CY中获得溢出的数据位
CLK = 1;
\_nop\_();
\_nop\_();
CLK = 0; //下降沿时数据从DOUT移出
}
for(i = 0; i < 8; i++)
{
CLK = 0; //
dat <<= 1; //发送数据
DIN = CY;
CLK = 1;
\_nop\_();
\_nop\_();
CLK = 0;
}
CS = 1; //CS上升沿,数据锁存
}
//初始化函数
void init\_max7221(void)
{
write\_data(0x09,0xff); //编码模式
write\_data(0x0a,0x07); //亮度控制
write\_data(0x0b,0x07); //扫描数码管的位数
write\_data(0x0c,0x01); //工作模式
}
void main(void)
{

unsigned char i;
TimeInit(); //定时器中断初始化
// Init\_DS1302();//将1302初始化,Proteus仿真时需要将初始注释掉,否则时间不会读取系统时间。
init\_max7221(); // 初始化
delayms(2);
for(i = 0; i < 8; i++)
{
write\_data(i+1,10); // 显示-位
}
delayms(1000);
while(1){
if(flags == 1) //判断1秒定时标志
{
UpDate();
flags = 0; //标志位清零
}
if(State)
DisTime();
else DisDate();
}
}
void UpDate(){
//unsigned char second,minute,hour,day,month,year; //分别储存苗、分、小时,日,月,年
unsigned char ReadValue; //储存从1302读取的数据
memset(Time_buff, 0, sizeof(Time_buff));
ReadValue = ReadSet1302(0x81); //从秒寄存器读数据
Time_buff[0]=((ReadValue&0x70)>>4)\*10 + (ReadValue&0x0F);//将读出数据转化

ReadValue = ReadSet1302(0x83); //从分寄存器读
Time_buff[1]=((ReadValue&0x70)>>4)\*10 + (ReadValue&0x0F); //将读出数据转化

ReadValue = ReadSet1302(0x85); //从时寄存器读
Time_buff[2]=((ReadValue&0x70)>>4)\*10 + (ReadValue&0x0F); //将读出数据转化

ReadValue = ReadSet1302(0x87); //从日寄存器读数据
Date_buff[2]=((ReadValue&0x70)>>4)\*10 + (ReadValue&0x0F); //将读出数据转化

ReadValue = ReadSet1302(0x89); //从月寄存器读
Date_buff[1]=((ReadValue&0x70)>>4)\*10 + (ReadValue&0x0F); //将读出数据转化

ReadValue = ReadSet1302(0x8d); //从年寄存器读
Date_buff[0]=((ReadValue&0x70)>>4)\*10 + (ReadValue&0x0F); //将读出数据转化
}
void DisTime(){

write\_data(1,Time_buff[2]/10); // 显示时高位
write\_data(2,Time_buff[2]%10); // 显示时低位
write\_data(3,10); // 显示-位
write\_data(4,Time_buff[1]/10); // 显示时高位
write\_data(5,Time_buff[1]%10); // 显示时低位
write\_data(6,10); // 显示-
write\_data(7,Time_buff[0]/10); // 显示时高位
write\_data(8,Time_buff[0]%10); // 显示时低位
}

void DisDate(){
write\_data(1,Date_buff[0]/10); // 显示年高位
write\_data(2,Date_buff[0]%10); // 显示年低位
write\_data(3,10); // 显示-位
write\_data(4,Date_buff[1]/10); // 显示月高位
write\_data(5,Date_buff[1]%10); // 显示月低位
write\_data(6,10); // 显示-
write\_data(7,Date_buff[2]/10); // 显示日高位
write\_data(8,Date_buff[2]%10); // 显示日低位

}
/\*\*\*\*中断服务函数\*\*\*\*\*/
void InterruptTimer0() interrupt 1
{
static volatile u8 cnt = 0; //用来记录中断次数,设置的中断定时为1ms,中断200次即一秒钟

TH0=(65536-5000)/256; //高四位寄存器的值;//5000us=5ms
TL0=(65536-5000)%256; //低四位寄存器的值;
cnt++; //中断次数计数值加1
if(cnt>=200) //中断次数达到200次即为1秒
{
cnt = 0; //清零,重新记录中断次数
flags = 1; //设置1秒定时标志位1
}
}
/\*\*\*\*中断服务函数\*\*\*\*\*/
void interint0() interrupt 0
{ //外部中断0处理
State = !State;
}


📚程序源码和仿真资源

1
2
3
链接:https://pan.baidu.com/s/1a3UNA7H8V\_XKsV9SQGGtAQ 
提取码:j0wk