分享一个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
通讯协议,且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 <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/2000long 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 UTCuint32_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 <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 1970ss = 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 2000return 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