分享一个RX8025T时钟芯片的Arduino代码
背景
之前做那个点阵时钟使用的是DS3231
的时钟芯片,这个时钟芯片最大的有点就是高精度,缺点就是有点贵,现在淘宝一颗这样的芯片最便宜的都要十几块钱,大大的增加了我整个点阵时钟的成本造价,所以不得已采用了这个新的时钟芯片方案,就是RX8025T
,成本大概就是一块钱左右。
RX8025芯片介绍
1.内置高稳定度的32.768KHz 的 DTCXO (数字温度补偿晶体振荡器)
- 支持I2C总线的高速模式(400K)。
- 定时报警功能(可设定:天,日期,小时,分钟)
- 固定周期定时中断功能。
- 时间更新中断功能。
- 32.768KHz频率输出(具有使能OE功能)
- 闰年自动调整功能。(2000到2099)
- 宽范围接口电压:2.2V到5.5V
- 宽范围的时间保持电压: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
通讯协议,且Arduino
对I2C
的实现较为简单,所以代码也很容易看懂,这里更多的像是搬运别人的代码吧,首先是在网上看到有一段关于8025
的arduino
代码,然后又结合DS3231
的代码,由此缝合出来了这段我个人觉得还能用的RX8025T
代码。下面列出参考地址:
- DS3231库源码地址:https://github.com/NorthernWidget/DS3231
- RX8025参考代码地址:RX8025 library updated for IDE 1.0
- I2C通讯协议学习地址:RX-8025T使用说明概要
RX8025.h
#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
#include
#include
// 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
#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
#elif defined(ESP8266)
#include
#endif
// Changed the following to work on 1.0
//#include "WProgram.h"
#include
// 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();
}
主函数
#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