Arduino处理并存储带RTC时间的传感器数据遇到的问题

目标


将深度传感器采集的数据附上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或树莓派。

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值