分享一个RX8025T时钟芯片的Arduino代码

背景

之前做那个点阵时钟使用的是DS3231的时钟芯片,这个时钟芯片最大的有点就是高精度,缺点就是有点贵,现在淘宝一颗这样的芯片最便宜的都要十几块钱,大大的增加了我整个点阵时钟的成本造价,所以不得已采用了这个新的时钟芯片方案,就是RX8025T,成本大概就是一块钱左右。

RX8025芯片介绍

1.内置高稳定度的32.768KHz 的 DTCXO (数字温度补偿晶体振荡器)
2. 支持I2C总线的高速模式(400K)。
3. 定时报警功能(可设定:天,日期,小时,分钟)
4. 固定周期定时中断功能。
5. 时间更新中断功能。
6. 32.768KHz频率输出(具有使能OE功能)
7. 闰年自动调整功能。(2000到2099)
8. 宽范围接口电压:2.2V到5.5V
9. 宽范围的时间保持电压:1.8V到5.5V10.低电流功耗:0.8uA/3V (Typ.)

相关文档

更多的介绍看下面的文档,如果文档失效的话,请百度搜索关键字RX-8025T使用说明概要

RX-8025T使用说明概要

电路&PCB设计

其实很早就想搞这个RX8025T的时钟芯片了,但是无奈淘宝上没有现成的模块,所以就只能自己搞一个了,然后就百度各种原理图,发现大家的原理图就都不太一样,所以就综合各种原理图搞一个大概的原理图出来,然后画一个简单的PCB板出来搞一搞,所以原理图这块仅供学习和参考,如果有大佬有更好的方案欢迎在评论区指出。

立创开源地址

RX8025T模块(附Arduino代码)

RX8025T电路原理图

PCB-3D预览图

成品图

Arduino代码

目前由于我还只擅长Arduino平台的代码处理,所以就只贴出来Arduino的代码,后续如果有其他平台的代码,一定也会在这里列举出来。由于RX8025T主要采用的是I2C通讯协议,且ArduinoI2C的实现较为简单,所以代码也很容易看懂,这里更多的像是搬运别人的代码吧,首先是在网上看到有一段关于8025arduino代码,然后又结合DS3231的代码,由此缝合出来了这段我个人觉得还能用的RX8025T代码。下面列出参考地址:

RX8025.h

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
#ifndef RX8025_h
#define RX8025_h

#define RX8025_SEC 0x0
#define RX8025_MIN 0x1
#define RX8025_HR 0x2
#define RX8025_WEEK 0x3
#define RX8025_DATE 0x4
#define RX8025_MTH 0x5
#define RX8025_YR 0x6
#define RX8025_Doffset 0x7
#define RX8025_AW_MIN 0x8
#define RX8025_AW_HR 0x9
#define RX8025_AW_WEEK 0xa
#define RX8025_AD_MIN 0xb
#define RX8025_AD_HR 0xc
#define RX8025_CTL1 0xd
#define RX8025_CTL2 0xE

#include <Arduino.h>
#include <Wire.h>
#include <time.h>
// DateTime (get everything at once) from JeeLabs / Adafruit
// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime
{
public:
DateTime(uint32_t t = 0);
DateTime(uint16_t year, uint8_t month, uint8_t day,
uint8_t hour = 0, uint8_t min = 0, uint8_t sec = 0);
DateTime(const char *date, const char *time);
uint16_t year() const
{
return 2000 + yOff;
}
uint8_t month() const
{
return m;
}
uint8_t day() const
{
return d;
}
uint8_t hour() const
{
return hh;
}
uint8_t minute() const
{
return mm;
}
uint8_t second() const
{
return ss;
}
uint8_t dayOfTheWeek() const;

// 32-bit times as seconds since 1/1/2000
long secondstime() const;
// 32-bit times as seconds since 1/1/1970
// THE ABOVE COMMENT IS CORRECT FOR LOCAL TIME; TO USE THIS COMMAND TO
// OBTAIN TRUE UNIX TIME SINCE EPOCH, YOU MUST CALL THIS COMMAND AFTER
// SETTING YOUR CLOCK TO UTC
uint32_t unixtime(void) const;

protected:
uint8_t yOff, m, d, hh, mm, ss;
};

//判断年份是否是闰年
bool isleapYear(const uint8_t);

class RX8025
{
private:
unsigned char RX8025_Control[2];
/**
* 获取寄存器数据
* @return byte
*/
byte getData(byte regaddr);

/**
* @brief 将十进制编码的二进制数转换为普通十进制数
*
* @param val
* @return byte
*/
byte decToBcd(byte val);

/**
* 将二进制编码的十进制数转换为普通十进制数
* @param val
* @return byte
*/
byte bcdToDec(byte val);

public:
RX8025(); // costruttore
/**
* 初始化
*/
void RX8025_init(void);

/**
* 向时钟芯片设置时间
* @param s 秒钟
* @param m 分钟
* @param h 时钟
* @param d 天
* @param mh 月
* @param y 年
*/
void setRtcTime(uint8_t s, uint8_t m, uint8_t h, uint8_t d, uint8_t mh, uint8_t y);

/**
* 获取秒钟
*/
byte getSecond();
/**
* 获取分钟数
* @return byte
*/
byte getMinute();
/**
* 获取小时数
* @return byte
*/
byte getHour();
/**
* 获取星期数
* @return byte
*/
byte getDoW();
/**
* 获取日期
* @return byte
*/
byte getDate();
/**
* 获取月份
* @return byte
*/
byte getMonth();
/**
* 获取年份
* @return byte
*/
byte getYear();

/**
* 获取时间戳
* @return long
*/
long getUnixtime();
};

#endif

RX8025.cpp

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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

#include "RX8025.h"
// These included for the DateTime class inclusion; will try to find a way to
// not need them in the future...
#if defined(__AVR__)
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#endif
// Changed the following to work on 1.0
//#include "WProgram.h"
#include <Arduino.h>

// 8025I2C地址
#define RX8025_address 0x32
// 日期起始时间(这里为啥要减掉八个小时,因为用的日期所在时区和国内时区相差8小时,所以需要减掉八小时的时区时间)
#define SECONDS_FROM_1970_TO_2000 946684800 - (8 * 60 * 60)
//
static const uint8_t daysInMonth[] PROGMEM = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/**
自2000/01/01起的天数,2001年有效。。2099
*/
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d)
{
if (y >= 2000)
y -= 2000;
uint16_t days = d;
for (uint8_t i = 1; i < m; ++i)
days += pgm_read_byte(daysInMonth + i - 1);
if (m > 2 && isleapYear(y))
++days;
return days + 365 * y + (y + 3) / 4 - 1;
}

static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s)
{
return ((days * 24L + h) * 60 + m) * 60 + s;
}

DateTime::DateTime(uint32_t t)
{
t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970

ss = t % 60;
t /= 60;
mm = t % 60;
t /= 60;
hh = t % 24;
uint16_t days = t / 24;
uint8_t leap;
for (yOff = 0;; ++yOff)
{
leap = isleapYear(yOff);
if (days < 365 + leap)
break;
days -= 365 + leap;
}
for (m = 1;; ++m)
{
uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
if (leap && m == 2)
++daysPerMonth;
if (days < daysPerMonth)
break;
days -= daysPerMonth;
}
d = days + 1;
}

DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
{
if (year >= 2000)
{
year -= 2000;
}
yOff = year;
m = month;
d = day;
hh = hour;
mm = min;
ss = sec;
}

// supported formats are date "Mmm dd yyyy" and time "hh:mm:ss" (same as __DATE__ and __TIME__)
DateTime::DateTime(const char *date, const char *time)
{
static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static char buff[4] = {'0', '0', '0', '0'};
int y;
sscanf(date, "%s %c %d", buff, &d, &y);
yOff = y >= 2000 ? y - 2000 : y;
m = (strstr(month_names, buff) - month_names) / 3 + 1;
sscanf(time, "%c:%c:%c", &hh, &mm, &ss);
}

// UNIX time: IS CORRECT ONLY WHEN SET TO UTC!!!
uint32_t DateTime::unixtime(void) const
{
uint32_t t;
uint16_t days = date2days(yOff, m, d);
t = time2long(days, hh, mm, ss);
t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000
return t;
}

// Slightly modified from JeeLabs / Ladyada
// Get all date/time at once to avoid rollover (e.g., minute/second don't match)
static uint8_t bcd2bin(uint8_t val)
{
return val - 6 * (val >> 4);
}
// Commented to avoid compiler warnings, but keeping in case we want this
// eventually
static uint8_t bin2bcd(uint8_t val) { return val + 6 * (val / 10); }

/**
判断是否是闰年
*/
bool isleapYear(const uint8_t y)
{
//检查是否可以被4整除
if (y & 3)
{
return false;
}
// 仅在第一次失败时检查其他
return (y % 100 || y % 400 == 0);
}

RX8025::RX8025() // costruttore
{
RX8025_Control[0] = 0x20;
RX8025_Control[1] = 0x00;
}

/**
* 向时钟芯片设置时间
* @param s 秒钟
* @param m 分钟
* @param h 时钟
* @param d 天
* @param mh 月
* @param y 年
*/
void RX8025::setRtcTime(uint8_t s, uint8_t m, uint8_t h, uint8_t d, uint8_t mh, uint8_t y)
{
// 使用指定的地址开始向I2C从设备进行传输。
Wire.beginTransmission(RX8025_address);
Wire.write((byte)0x00);
Wire.write(decToBcd(s));
Wire.write(decToBcd(m));
Wire.write(decToBcd(h));
Wire.write(0x1);
Wire.write(decToBcd(d));
Wire.write(decToBcd(mh));
Wire.write(decToBcd(y));
// 停止与从机的数据传输
Wire.endTransmission();
}

/**
* 获取寄存器里面的数据
* @param regaddr
* @return byte
*/
byte RX8025::getData(byte regaddr)
{
// 使用指定的地址开始向I2C从设备进行传输。
Wire.beginTransmission(RX8025_address);
Wire.write(regaddr);
// 停止与从机的数据传输
Wire.endTransmission();
// 由主设备用来向从设备请求字节。
Wire.requestFrom(RX8025_address, 1);
// 读取数据
return Wire.read();
}

/**
* @brief 初始化函数
*
*/
void RX8025::RX8025_init(void)
{
// Wire初始化
Wire.begin();
// 使用指定的地址开始向I2C从设备进行传输。
Wire.beginTransmission(RX8025_address);
Wire.write(0xe0);
for (unsigned char i = 0; i < 2; i++)
{
Wire.write(RX8025_Control[i]);
}
// 使用指定的地址开始向I2C从设备进行传输。
Wire.endTransmission();
}

/**
* @brief 将十进制编码的二进制数转换为普通十进制数
*
* @param val
* @return byte
*/
byte RX8025::decToBcd(byte val)
{
// 将十进制编码的二进制数转换为普通十进制数
return ((val / 10 * 16) + (val % 10));
}

/**
* 将二进制编码的十进制数转换为普通十进制数
*
* @param val
* @return byte
*/
byte RX8025::bcdToDec(byte val)
{
// 将二进制编码的十进制数转换为普通十进制数
return ((val / 16 * 10) + (val % 16));
}

/**
* 获取秒钟
*/
byte RX8025::getSecond()
{
byte buff = getData(RX8025_SEC);
return bcdToDec(buff & 0x7f);
}

/**
* 获取分钟数
* @return byte
*/
byte RX8025::getMinute()
{
byte buff = getData(RX8025_MIN);
return bcdToDec(buff & 0x7f);
}

/**
* 获取小时数
* @return byte
*/
byte RX8025::getHour()
{
byte buff = getData(RX8025_HR);
return bcdToDec(buff & 0x3f);
}

/**
* 获取星期数
* @return byte
*/
byte RX8025::getDoW()
{
byte buff = getData(RX8025_WEEK);
return bcdToDec(buff & 0x07);
}

/**
* 获取日期
* @return byte
*/
byte RX8025::getDate()
{
byte buff = getData(RX8025_DATE);
return bcdToDec(buff & 0x3f);
}

/**
* 获取月份
* @return byte
*/
byte RX8025::getMonth()
{
byte buff = getData(RX8025_MTH);
return bcdToDec(buff & 0x1f);
}

/**
* 获取年份
* @return byte
*/
byte RX8025::getYear()
{
byte buff = getData(RX8025_YR);
return bcdToDec(buff & 0xff);
}

long RX8025::getUnixtime()
{
// 使用指定的地址开始向I2C从设备进行传输。
Wire.beginTransmission(RX8025_address);
Wire.write(0x00);
// 停止与从机的数据传输
Wire.endTransmission();
// 由主设备用来向从设备请求字节。
Wire.requestFrom(RX8025_address, 7);
// 读取数据
uint16_t ss = bcdToDec(Wire.read() & 0x7F);
uint16_t mm = bcdToDec(Wire.read() & 0x7f);
uint16_t hh = bcdToDec(Wire.read() & 0x3f);
Wire.read();
uint16_t d = bcdToDec(Wire.read() & 0x3f);
uint16_t m = bcdToDec(Wire.read() & 0x1f);
uint16_t y = bcdToDec(Wire.read() & 0xff) + 2000;
return DateTime(y, m, d, hh, mm, ss).unixtime();
}

主函数

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
#include "Arduino.h"
#include "RX8025.h"

RX8025 rtc;
DateTime datetime;

void setup(void)
{
Serial.begin(9600);
Serial.println("on the setup");
rtc.RX8025_init();
rtc.setRtcTime(0, 24, 21, 4, 4, 22);
}

void loop(void)
{
Serial.print(rtc.getYear());
Serial.print("年");
Serial.print(rtc.getMonth());
Serial.print("月");
Serial.print(rtc.getDate());
Serial.print("日");
Serial.print(rtc.getHour());
Serial.print(":");
Serial.print(rtc.getMinute());
Serial.print(":");
Serial.println(rtc.getSecond());
delay(1000);
Serial.println(rtc.getUnixtime());
}

参考文章

I2C详解

太极创客 - Arduino – Wire 库

RX-8025T使用说明概要

RX8025 library updated for IDE 1.0