37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手试试多做实验,不管成功与否,都会记录下来——小小的进步或是搞不掂的问题,希望能够抛砖引玉。
** 【Arduino】189种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百四十五:DS3231 高精度时钟模块 IIC/I2C接口 实时计时传感器**
实验模块接线示意图
【Arduino】189种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百四十五:DS3231 高精度时钟模块 IIC/I2C接口 实时计时传感器
项目之八:通过 I2C 通信 接收用户输入的时间数据并更新时钟
实验开源代码
/*
【Arduino】189种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验二百四十五:DS3231 高精度时钟模块 IIC/I2C接口 实时计时传感器
项目之八:通过 I2C 通信 接收用户输入的时间数据并更新时钟
*/
#include <DS3231.h> // 引入 DS3231 RTC 库
#include <Wire.h> // 引入 I2C 通信库
// **创建 DS3231 RTC 对象**
DS3231 myRTC;
// **定义时间变量**
byte year, month, date, dow; // 年、月、日、星期
byte hour, minute, second; // 时、分、秒
bool century = false; // 用于跨世纪判断
bool h12Flag; // 12 小时制标志
bool pmFlag; // PM 标志(仅用于 12 小时制)
/*****************************************************************************************************
* **初始化**
* - 开启串口和 I2C 通信
* - 解释程序的使用方法
*****************************************************************************************************/
void setup() {
Serial.begin(57600); // **初始化串口,波特率 57600**
Wire.begin(); // **启动 I2C 通信**
// **等待 4 秒,确保 RTC 启动稳定**
delay(4000);
// **向用户解释时间格式**
Serial.println("时间格式:YYMMDDwhhmmssx");
Serial.println("其中:");
Serial.println(" YY = 年(如 20 表示 2020 年)");
Serial.println(" MM = 月(如 04 表示 4 月)");
Serial.println(" DD = 日期(如 09 表示 9 号)");
Serial.println(" w = 星期(1-7,1=星期天,5=星期四)");
Serial.println(" hh = 24 小时制小时数(如 09 表示上午 9 点,21 表示晚上 9 点)");
Serial.println(" mm = 分钟(如 02)");
Serial.println(" ss = 秒(如 42)");
Serial.println("例如输入:2004095090242x");
Serial.println("-----------------------------------------------------------------------------");
Serial.println("请在串口输入时间,并以 'x' 结尾以设置 DS3231 的时间:");
}
/*****************************************************************************************************
* **主循环**
* - 监听串口输入的时间校正数据
* - 根据输入设置 DS3231 的时钟
* - 在 5 秒内回显 DS3231 时间
*****************************************************************************************************/
void loop() {
// **如果串口收到输入数据,则进行时间校正**
if (Serial.available()) {
inputDateFromSerial(); // 读取串口数据并解析时间
myRTC.setClockMode(false); // **设置 24 小时模式**
// **将输入的时间写入 DS3231**
myRTC.setYear(year);
myRTC.setMonth(month);
myRTC.setDate(date);
myRTC.setDoW(dow);
myRTC.setHour(hour);
myRTC.setMinute(minute);
myRTC.setSecond(second);
// **连续 5 秒,每秒打印 DS3231 当前时间**
for (uint8_t i = 0; i < 5; i++) {
delay(1000);
Serial.print(myRTC.getYear(), DEC);
Serial.print("-");
Serial.print(myRTC.getMonth(century), DEC);
Serial.print("-");
Serial.print(myRTC.getDate(), DEC);
Serial.print(" ");
Serial.print(myRTC.getHour(h12Flag, pmFlag), DEC); // 24 小时制
Serial.print(":");
Serial.print(myRTC.getMinute(), DEC);
Serial.print(":");
Serial.println(myRTC.getSecond(), DEC);
}
// **提示用户输入新时间**
Serial.println("请在串口输入新的时间,并以 'x' 结尾以设置 DS3231:");
}
delay(1000); // 每秒刷新一次
}
/*****************************************************************************************************
* **inputDateFromSerial**
* - 读取用户串口输入的时间数据
* - 解析并存储到全局变量
*****************************************************************************************************/
void inputDateFromSerial() {
// **检查串口数据是否完整(结束字符为 'x')**
boolean isStrComplete = false;
char inputChar;
byte temp1, temp2;
char inputStr[20]; // 存储输入的时间字符串
uint8_t currentPos = 0;
while (!isStrComplete) {
if (Serial.available()) {
inputChar = Serial.read();
inputStr[currentPos] = inputChar;
currentPos += 1;
// **检查输入是否以 'x' 结尾**
if (inputChar == 'x') {
isStrComplete = true;
}
}
}
Serial.println(inputStr); // **打印用户输入的数据**
// **查找字符串中的 'x' 位置**
int posX = -1;
for (uint8_t i = 0; i < 20; i++) {
if (inputStr[i] == 'x') {
posX = i;
break;
}
}
// **ASCII 码 '0' 的值(用于转换字符为数字)**
uint8_t zeroAscii = '0';
// **解析年**
temp1 = (byte)inputStr[posX - 13] - zeroAscii;
temp2 = (byte)inputStr[posX - 12] - zeroAscii;
year = temp1 * 10 + temp2;
// **解析月**
temp1 = (byte)inputStr[posX - 11] - zeroAscii;
temp2 = (byte)inputStr[posX - 10] - zeroAscii;
month = temp1 * 10 + temp2;
// **解析日期**
temp1 = (byte)inputStr[posX - 9] - zeroAscii;
temp2 = (byte)inputStr[posX - 8] - zeroAscii;
date = temp1 * 10 + temp2;
// **解析星期**
dow = (byte)inputStr[posX - 7] - zeroAscii;
// **解析小时**
temp1 = (byte)inputStr[posX - 6] - zeroAscii;
temp2 = (byte)inputStr[posX - 5] - zeroAscii;
hour = temp1 * 10 + temp2;
// **解析分钟**
temp1 = (byte)inputStr[posX - 4] - zeroAscii;
temp2 = (byte)inputStr[posX - 3] - zeroAscii;
minute = temp1 * 10 + temp2;
// **解析秒**
temp1 = (byte)inputStr[posX - 2] - zeroAscii;
temp2 = (byte)inputStr[posX - 1] - zeroAscii;
second = temp1 * 10 + temp2;
}
代码简单解读
这段代码使用 DS3231 RTC(实时时钟)模块 通过 I2C 通信 接收用户输入的时间数据,并更新 DS3231 的时钟,核心逻辑如下:
-
初始化 RTC
✅ DS3231 myRTC; → 创建 DS3231 RTC 对象
✅ Wire.begin(); → 启动 I2C 通信
✅ Serial.begin(57600); → 初始化串口,波特率 57600 -
解释时间格式
✅ Serial.println() → 向用户展示输入格式(YYMMDDwhhmmssx)
✅ 示例输入 → “2004095090242x” 代表 2020 年 4 月 9 日星期四 09:02:42 -
监听串口输入并解析时间
✅ inputDateFromSerial(); → 读取串口输入数据并转换为 RTC 兼容格式
✅ 解析年、月、日、星期、时、分、秒
✅ myRTC.setClockMode(false); → 设置为 24 小时制
✅ myRTC.setYear(year); → 设置年份
✅ myRTC.setMonth(month); → 设置月份
✅ myRTC.setDate(date); → 设置日期
✅ myRTC.setDoW(dow); → 设置星期
✅ myRTC.setHour(hour); → 设置小时
✅ myRTC.setMinute(minute); → 设置分钟
✅ myRTC.setSecond(second); → 设置秒 -
每 5 秒回显当前时间
✅ 每秒打印 DS3231 当前时间,以确保时间正确 -
采集间隔
✅ delay(1000); → 每秒监听串口输入,等待新时间数据
这段代码让 用户通过串口输入时间,并更新 DS3231 的时钟。
实验串口返回情况