目标
将深度传感器采集的数据附上RTC时间并存入SD卡中,工作状态为离线,依靠电池供电
一、主要硬件
Arduino uno R3,SD card model(TF卡SPI接口),Time model-DS3231, DEPTH-MS5837(ELEC-DS1-3050), Calculation board-(IIC to TTL), micro-SD-XC(64G), ie...
二、通信协议及接线
2.1 连接硬件
下面将各个模块按照对应的通信协议,用杜邦线接入Arduino uno R3,下面的数字即为引脚号。
SD card model
cs : 10
SCK: 13
MOSI: 11
MISO: 12
协议:SPI
Time model-DS3231
SCL : A5
SDA : A4
协议:IIC协议
DEPTH-MS5837 + Calculation board
RED :8
WHITE :9
BLACK : 5
YELLOW: GND
协议:IIC to TTL
2.2 硬件全部连接后的图片
三、测试代码
#include <Adafruit_BusIO_Register.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_I2CRegister.h>
#include <Adafruit_SPIDevice.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <SPI.h>
#include <SoftwareSerial.h>
//#include <SdFat.h>
//深度传感器的接线引脚
SoftwareSerial depthSerial(8, 9); // RX: digital pin 0, TX: digital pin 1
//SdFat sd;//sd卡格式转换
RTC_DS3231 rtc;
unsigned long previousMillis = 0;
const unsigned long interval = 1; // 1毫秒
const int chipSelectPin = 10;
File dataFile;//定义写入sd卡的数据文件名
int DelayTime = 2600;//读取深度传感器每个字符串的时间
char buffer[16];//将时间格式化为字符串
void setup() {
Serial.begin(115200);
Wire.begin();
rtc.begin();
depthSerial.begin(115200); // 初始化深度传感器解算板的串口通信,波特率为115200
// 获取电脑时间,以校准rtc模块时间
DateTime pcTime = DateTime(__DATE__, __TIME__);
// 将RTC时间设置为电脑时间
rtc.adjust(pcTime);
// 初始化SD卡
if (!SD.begin(10)) {
Serial.println("SD卡初始化失败");
return;
}
else{
Serial.println("SD卡初始化成功");
}
// 打开文件以写入数据
dataFile = SD.open("datatest.txt", FILE_WRITE);
if (!dataFile) {
Serial.println("无法打开文件");
return;
}
else{
Serial.println("文件打开成功");
}
// 向解算板发送密度
char sendData = '!F998\r\n';
depthSerial.write(sendData);
// 向解算板发送算法,修改成ms5837算法
char sendData_1 = '!A30';
depthSerial.write(sendData_1);
//写入深度修正值
char sendData_2 = '!D-00.33\r\n';
depthSerial.write(sendData_2);
//写入温度修正值
char sendData_3 = '!T19.20\r\n';
depthSerial.write(sendData_3);
delay(1000);
}
void loop() {
DateTime now = rtc.now();
unsigned long currentMillis = millis();
//读取深度数据
char data = depthSerial.read(); // 逐个读取可用数据
if (data != 'D') {
dataFile.write(data); // 在串口监视器上写入深度数据
Serial.print(data); // 在串口监视器上显示深度数据
//dataFile.flush();
delayMicroseconds(DelayTime);
}
if (data == 'D'){
dataFile.println();
Serial.println();
// 每毫秒更新一次时间显示
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
sprintf(buffer,"%02d-%02d %02d:%02d:%02d.%03d",now.month(),now.day(),now.hour(), now.minute(), now.second(), currentMillis % 1000);
//将rtc时间数据写入文件
dataFile.print(buffer);
dataFile.print(" ");
//显示获取到的rtc时间
Serial.print(buffer);
Serial.print(" ");
Serial.print(data);
// 在sd卡中写入'D'
dataFile.print(" ");
dataFile.print(data);
dataFile.flush();
}
}
}
四、遇到的问题及解决方案
4.1 DS3231模块校准时间和实际真实时间存在一个Gap time的问题
由于与电脑离线状态下,各设备的采样频率、波特率,离线状态无法进行通信的情况下,写入sd卡写入速度等均有差异,则测量的实验数据必须要带有时间戳,用于处理不同传感器或设备采集到的数据。这里便考虑将数据附上RTC时间,便于统一不同设备所测量得到的数据。
由于arduino获取电脑时间后,编译时已经获取到电脑时间,并将它存储到PCtime变量中,但是由于IDE编译并将代码上传到arduino板子上会存在一个时间差,此时arduino再给DS3231模块校准时,PCtime变量中的时间与真实时间存在一个gap time,这个gap time是稳定在7s500ms附近(具体gap time的大小跟电脑硬件和板子芯片有关,需要自己测试)。这也就是为什么RTC模块无法做到实时校准的原因。
So, real time = now.date() + gap time;
其中:now.date()是从RTC模块获取的时间,具体获取时间的函数模块与传感器及板子自身的库有关。
4.2 深度传感器存在的问题及解决方案
由于深度传感器本身是IIC通信协议,加上一块解算板,可将IIC协议转为TTL协议,并完成解算过程,TTL协议便接入arduino的数字串口,用串口模拟进行发送与接收数据(即TX,RX引脚),直接引用arduino库函数获取解算板的数据,会出现大量乱码以及无法获取数据的情况。
而深度传感器解算板发送给arduino的数据是按单个字符形式发送,而不是完成过解算后以字符串的形式发送完整的深度和温度数据,故在主函数体中是不断接收单个字符的。否则出现如下图情况:
由于厂家一般无法提供解算板的发送速度,而且将数据写入sd卡也需要时间,两者之间如何平衡,那么就需要计算解算板解算完成后发送字符的时间间隔,以及sd卡写入数据耗费的时间,计算两者的时间才能保证arduino不会读取到“空字符(即乱码)“。此外,sd卡由于硬件写入速度及TF模块本身的限制,具体调整多少时间才能保证不断接收到解算板的数据而不是”空“,这和你的硬
件设备有很大关系,需要自己计算并调试,但计算并调试的方法便是如此。在串口监视器中,最后测试并获取得到的数据如下图所示:
4.3 sd卡模块存在的问题
在无法通过IDE的串口监视器实时查看数据的情况下,即离线情况下,那么我们需要将数据写入sd卡保存便于之后分析,一般为 time + data,但有时存在引用SD.h 或者sdFat.h,无法完成SD card initial,自然也就无法打开文件并写入数据了。
原因:SD.h 或者sdFat.h库虽然是用于写入数据用的,但它们只支持Fat 16 或 Fat 32 格式,但是由于SD卡容量一般超过32G,一般的格式均是exfat格式,SD.h or sdFat.h 是不能向其写入数据的。ps:具体的sd card的格式读者自己查阅资料。
解决方案:最便捷的办法就是将sd卡格式化,一般磁盘不支持exfat转fat32,但是在win窗口下,输入format E: fs:fat32,即完成了格式化,其中E代表的sd卡的盘符;
但是这种办法对于大容量sd卡速度太慢,也可以使用一些分区助手格式化,快捷简单,推荐使用第二种办法,第一种方案速度实在太慢了!
4.4 SD卡损坏
由于测试过程中频繁的插拔sd卡,有时忘记弹出导致sd卡损坏,可使用win的命令直接修复
五、最后完成初步调试
最后完成调试,在离线状态下,将带RTC的深度数据写入SD卡中,如下图所示
其中有部分乱码是解算板发送数据存在延迟而导致,后续可以将数据存储格式改为D:xx T:XX, 以消除存入的乱码,或者直接解算深度传感器数据并且将数据以二进制写入sd卡,提高速度,避免解算板或Arduino的缓冲区数据溢出。
此外,还需要注意调整串口的波特率保持一致。
六、反思与改进
可以加入WIFI模块,从NTR获取并校准时间模块,此外,数据解算及存储可以改为二进制,提高读取和写入速度,可以提高样频率。并且可以换为STM32或树莓派。