【Proteus仿真】Arduino UNO+DS1302+74HC595联级+8位数码管时钟+串口设置时间

【Proteus仿真】Arduino UNO+DS1302+74HC595联级+8位数码管时钟+串口设置时间


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

仿真前准备工作

  • 需要使用到虚拟串口工具,设置一对虚拟串口,用于Proteus软件仿真时的串口和另外一个串口助手之间的数据通讯。
    在这里插入图片描述
  • Proteus仿真设置:串口号需要和虚拟串口软件里面设置的相对应,波特率与代码设置的一致
    在这里插入图片描述

程序代码

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
#include <DS1302.h>

DS1302 rtc(2, 3, 4); //对应DS1302的RST,DAT,CLK
unsigned char smgduan[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; //共阳段码表
//{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示0~F的值共阴

/\*\*\*\*74HC595\*\*\*/
const byte DS = 11; //data
const byte ST = 12; //latch
const byte SH = 10; //clock
char weiMa[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; //选择1-8哪位数码管段
char duanZhi[8] = {0, 0, 0xBF, 0, 0, 0xBF, 0, 0};
//{0,0,0x40,0,0,0x40,0,0};//共阴
const long interval = 1000;//设置延时时间间隔
unsigned long previousMillis = 0;
static unsigned char i =0;
//u16 miao, fen, shi;
//秒、分、时高位低位
u8 miao_L, miao_H, fen_L, fen_H, shi_L, shi_H;
String input_string; // 声明变量 input\_string ,用于存储串口输入的数据

// 获取串口数据函数
void GetSerialStuff(String& input_string) {
String temp_string = ""; // 声明变量 temp\_string,用于临时存储串口输入的数据
while(Serial.available()) { // 当串口有数据时,循环执行
temp_string += (char)Serial.read(); // 把读取的串口数据,逐个组合到inStr变量里
delay(2);
}
input_string = temp_string; // 把引用指针的变量赋值为 tempStr
}

void initRTCTime(void)//初始化RTC时钟
{
rtc.writeProtect(false); //关闭写保护
rtc.halt(false); //清除时钟停止标志
Time t(2021, 9, 26, 21, 50, 50, 7); //新建初始时间对象 通过串口设定,这里的时间随便填写,最后参数位星期数据,周日为1,周一为2以此类推
rtc.time(t);//向DS1302设置时间数据
}

void readtime() {
Time tim = rtc.time(); //从DS1302获取时间数据
shi_L = (tim.hr) % 10;
shi_H = (tim.hr) / 10;
fen_L = (tim.min) % 10;
fen_H = (tim.min) / 10;
miao_L = (tim.sec) % 10;
miao_H = (tim.sec) / 10;
}

void display()
{ //先发送8位位码,后发送8位段码
//8位数码管需要发送8次
//保存段值/
i%=8;
duanZhi[7] = smgduan[miao_L];
duanZhi[6] = smgduan[miao_H];
duanZhi[3] = smgduan[fen_H];
duanZhi[4] = smgduan[fen_L];
duanZhi[1] = smgduan[shi_L];
duanZhi[0] = smgduan[shi_H];
digitalWrite(ST, LOW);
shiftOut(DS, SH, MSBFIRST, weiMa[i]);送位码
shiftOut(DS, SH, MSBFIRST, duanZhi[i]);//送段码
i++;
delayMicroseconds(2);
digitalWrite(ST, HIGH);//ST\_CP
delay(2);
}

void setup() {
Serial.begin(9600);

//新模块上电需要设置一次当前时间,
//下载完成后需屏蔽此函数再次下载,否则每次上电都会初始化时间数据
initRTCTime();
pinMode(ST, OUTPUT);//ST\_CP
pinMode(DS, OUTPUT);//DS
pinMode(SH, OUTPUT);//SH\_CP
digitalWrite(DS, LOW);
readtime();
}

void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
Time tim = rtc.time(); //从DS1302获取时间数据

miao_L = (tim.sec) % 10;
miao_H = (tim.sec) / 10;

fen_L = (tim.min) % 10;
fen_H = (tim.min) / 10;

shi_L = (tim.hr) % 10;
shi_H = (tim.hr) / 10;
}
display();
GetSerialStuff(input_string); // 获取串口的数据
if(input_string != "") { // 如果 串口不为空,则
//2022-06-02 20:08:37
// Serial.println(input\_string);
Serial.println("receve data");
unsigned int to_year = input_string.substring(0, 4).toInt(); // 从字符串中截取 年 的数据并转换成int数据类型
Serial.println(to_year, DEC);
unsigned int to_month = input_string.substring(5, 7).toInt(); // 从字符串中截取 月 的数据并转换成int数据类型
Serial.println(to_month, DEC);
unsigned int to_day = input_string.substring(8, 10).toInt(); // 从字符串中截取 日 的数据并转换成int数据类型
Serial.println(to_day, DEC);
unsigned int to_hours = input_string.substring(11, 13).toInt(); // 从字符串中截取 时 的数据并转换成int数据类型
Serial.println(to_hours, DEC);
unsigned int to_minute = input_string.substring(14, 16).toInt(); // 从字符串中截取 分 的数据并转换成int数据类型
Serial.println(to_minute, DEC);
unsigned int to_second = input_string.substring(17, 19).toInt(); // 从字符串中截取 秒 的数据并转换成int数据类型
Serial.println(to_second, DEC);
unsigned int to_week = input_string.substring(20, 21).toInt();// 从字符串中截取 星期 的数据并转换成int数据类型
Serial.println(to_week, DEC);
rtc.writeProtect(false); //关闭写保护
rtc.halt(false); //清除时钟停止标志
// 重新设定DS1302模块的时间
Time t(to_year, to_month , to_day, to_hours, to_minute, to_second,to_week); //新建时间对象 最后参数位星期数据,周日为1,周一为2以此类推
rtc.time(t);//向DS1302设置时间数据
delay(100);
}
}

  • 编译信息
1
2
3
4
5
6
7
8
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-gcc" -w -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o "d:\\arduino\\MyHexDir/ds1302.ino.elf" "d:\\arduino\\MyHexDir\\sketch\\ds1302.ino.cpp.o" "d:\\arduino\\MyHexDir\\libraries\\ds1302\\DS1302.cpp.o" "d:\\arduino\\MyHexDir/core\\core.a" "-Ld:\\arduino\\MyHexDir" -lm
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "d:\\arduino\\MyHexDir/ds1302.ino.elf" "d:\\arduino\\MyHexDir/ds1302.ino.eep"
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-objcopy" -O ihex -R .eeprom "d:\\arduino\\MyHexDir/ds1302.ino.elf" "d:\\arduino\\MyHexDir/ds1302.ino.hex"
使用库 ds1302 在文件夹: C:\Program Files (x86)\Arduino\libraries\ds1302 (legacy)
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7/bin/avr-size" -A "d:\\arduino\\MyHexDir/ds1302.ino.elf"
项目使用了 6278 字节,占用了 (19%) 程序存储空间。最大为 32256 字节。
全局变量使用了256字节,(12%)的动态内存,余留1792字节局部变量。最大为2048字节。

程序代码和仿真资源以及库

在我的Arduino IDE里面编译显示使用库 ds1302 在文件夹: C:\Program Files (x86)\Arduino\libraries\ds1302 (legacy),该库是一个旧版本的 (legacy),我不敢保证每个人所安装的库是否会有差异,所以附上我编译时的自带库,仿真时请调用ds1302.ino.with_bootloader.standard.hex

  • 本实验基于Proteus8.9平台
1
2
3
链接:https://pan.baidu.com/s/1jd5hEThBXcc6EMFUDodALw 
提取码:zde2


人生中最大的痛苦: 你知道什么是对的 但却永远做出错误的选择 知道和做到这道巨大的鸿沟, 你永远无法跨越