[ESP8266/ESP32]FireBeetle 蓝牙温湿度记录仪 精华

1085浏览
查看: 1085|回复: 2

[ESP8266/ESP32] FireBeetle 蓝牙温湿度记录仪

[复制链接]
本帖最后由 zoologist 于 2021-8-28 10:23 编辑

对于Aduino玩家来说,记录大量数据最常见的手段是配合 SD卡模块将数据记录到SD卡中,有些特别情况下,Arduino可以支持通过SPI来直接支持 SD卡。但是实际使用中存在着严重的兼容性问题,另外读取数据也并不方便。这次介绍直接使用U盘来存储获得的小米蓝牙温湿度计取得的数据。
这次的项目使用 DFRobot FireBeetle 来完成。首先为了实现U盘的读写,选择国产的 CH376 芯片。CH376是南京沁恒出品的U盘和SD卡文件管理控制芯片,CH376是文件管理控制芯片,用于单片机系统读写U盘或者SD卡中的文件。
CH376支持USB设备方式和USB主机方式,并且内置了USB通讯协议的基本固件,内置了处理Mass-Storage海量存储设备的专用通讯协议的固件,内置了SD卡的通讯接口固件,内置了FAT16FAT32以及FAT12文件系统的管理固件,支持常用的USB存储设备(包括U/USB 硬盘/USB 闪存盘/USB 读卡器)和SD卡(包括标准容量SD卡和高容量HC-SD卡以及协议兼容的MMC卡和TF 卡)。
CH376支持三种通讯接口:8位并口、SPI接口或者异步串口,单片机/DSP/MCU/MPU等控制器可以通过上述任何一种通讯接口控制CH376芯片,存取U 盘或者SD 卡中的文件或者与计算机通讯。
此外,这一系列还有 CH375 (比CH376少了SPI 接口),CH378USBFull Speed)。为了实现目标,首先制作一个 FireBeetle CH376 Shield 为了方便手工焊接,选择了SOP-28封装的CH376S,电路设计如下,芯片和FireBeetle 使用串口连接,这样虽然速度无法和SPI接口相比,但是我们数据量不大完全够用:
xiaom1.png
从图中可以看到,外围元件主要是12M的晶振和一些电容,从外还有一个工作指示灯,当芯片有读写动作时,会熄灭。

xiaom2.png

xiaom3.png
成品照片如下:
xiaom4.png
接下来是要找到驱动 CH376的方法,在Github上找到djuseeqCh376msc项目【参考1】。测试发现,这个项目能够在 Arduino Uno 上正常工作,但是在ESP32上会遇到奇怪不稳定的问题。最终在逻辑分析仪的帮助下确定出现问题是在切换频率之后。这个CH376上电之后根据硬件Strapping结果有一个默认的波特率,这次设计的Shield默认使用 9600,之后通过串口命令通知CH376使用指定的波特率进行通讯。前面提到的Ch376msc库在切换之后会使用 FireBeetle立刻使用新的波特率进行通讯,此时在ESP32串口缓冲中仍然会有尚未通过串口发送出去的数据,切换之后的命令实际上并没有正确的传输给 CH376。用具体的例子来说明:
FireBeetle 串口发送 57 AB 02 03 CC命令通知CH376即将切换为115200 波特率。代码中在执行完发送最后2个数据之后,这两个数据只是加入到串口发送缓冲中,执行完之后FireBeetle马上进行了波特率切换,串口随之发送动作,串口缓冲区仍然存在的数据将会用新的波特率发送,此时CH376还没有按照新的波特率开始响应,因此将会收到错误的数据。

_comPortHW->write(uint8_t(0x03));
_comPortHW->write(uint8_t(0xCC));

解决方法也很简单:在切换波特率之间加入足够大的延时,保证串口发送缓冲以切换之前的波特率发送完成。
为了更好的记录数据,增加了一个 RTC 模块,起初使用的是 DS1307模块,但是测试下来发现这个模块有奇怪的问题(1.模块实际上是为可充电电池设计的,如果使用非充电电池可能有**烧毁的风险2.特别注意电池型号,市面常见的纽扣电池会比原装的可充电电池薄一些,使用时会有接触的问题3.解决上面三个问题之后,仍然有经常丢失时间的问题)。最终选择的是 DS3231 模块,搭配 FireBeetle 测试良好。
最终还设计了一个底板,左上角是为了让整体能在充电宝供电的情况下正常工作电路(很多充电宝如果电流低于200ma会自动切断供电)。FireBeetle上还有一个按钮,这是为了当我们需要让其停止工作时,通知FireBeetle将缓冲中的数据写入U盘(U盘也是一种 FLASH 介质,每次写入时需要先擦除,因此有寿命上的考虑,所以采用先将收集到的数据存储在RAM中,收集到足够的数据后一次性写入文件中)。

xiaom5.png
PCB 如下:

xiaom6.png
xiaom7.png

成品:

xiaom8.png
关键代码如下:

1.     1.,U盘读写模块 CH376 相关代码
  1. // CH376 对象,使用  115200 波特率
  2. Ch376msc flashDrive(Serial2, 115200);
  3.   flashDrive.init();
  4. // 检查当前是否有 U盘插入
  5.   if (flashDrive.checkIntMessage()) {
  6.     if (flashDrive.getDeviceStatus()) {
  7.       Serial.println(F("Flash drive attached!"));
  8.     } else {
  9.       Serial.println(F("Flash drive detached!"));
  10.     }
  11.   }
  12.   // 检查U盘是否可以工作(要求必须是 FAT 分区)
  13.   while (flashDrive.driveReady() != true) {
  14.     Serial.println("Attach flash drive first!");
  15.     Serial.print(flashDrive.pingDevice());
  16.     delay(500);
  17.   }
  18. // 设定存储数据的文件名称,特别注意:文件名不能是小写,这里使用从日期生成的纯数字组成文件名
  19.   flashDrive.setFileName(Filename);
  20.   flashDrive.openFile();
  21.   flashDrive.writeFile(header, strlen(header));
  22.   flashDrive.closeFile();
复制代码

2.      2.DS3231 相关代码
  1. // 声明 DS3231 对象
  2. RTC_DS3231 RTC;
  3.     初始化时有一个检查的动作,如果时间不正确那么重新进行设定
  4.   // 检查 RTC 状态,如果有掉电发生就说明
  5.   if (RTC.lostPower()) {
  6.     Serial.println("RTC lost power, let's set the time!");
  7.     // 使用当前的编译时间重新设定 RTC
  8.     RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));
  9.     // 下面是直接设定时间的例子
  10.     // January 21, 2014 at 3am you would call:
  11. // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
复制代码
之后,通过 RTC.now()可以取得 DS3231 的时间

3.     小米温湿度传感器是下面这个东西,非常省电,一节7号电池可以使用一年(我亲自测试)。除了显示之外,它还会使用 BLE 广播的方式对外发送蓝牙信号。FireBeetle可以监听蓝牙广播,收到之后做进一步处理。具体代码在classMyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {}  中。
xiaom9.png
同一个函数中,下面的代码将数据收取下来后先保存在 RAM 中的Recorder结构体数组中:

  1. Data[RecorderCounter].tm = RTC.now();
  2.               Data[RecorderCounter].humidity = current_humidity;
  3.               Data[RecorderCounter].temperature = current_temperature;
  4. // 存储收到的温湿度数据
  5. struct Recorder {
  6.   char      Address[18]; // 地址
  7.   DateTime  tm;          // 发生的时间
  8.   float     humidity;    // 湿度数据
  9.   float     temperature; // 温度数据
  10. };
复制代码

当收集到足够数据或者发现有按键按下后,就开始写入U盘上的文件进行保存。
4.     定义了一个按键,在下面这个函数中处理按键中断。上电后第一次按下,进入函数后检查距离上一次按键的时间,只有超过3秒才会响应按键,这样避免了按键抖动和误触发。StopMark记录按键的历史状态,0表示没有触发过,记录会正常进行;1表示触发过,当前是停止向U盘写入数据的状态;此外,如果当前 StopMark==1,再次按下就会触发重启命令,重新开始记录数据。
  1. void IRAM_ATTR StopFunction() {
  2.   if (millis() - StopElsp > 3000) {
  3.     Serial.println("Pressed\n");
  4.     if (StopMark == 0) {
  5.       StopMark = 1;
  6.     } else {
  7.       esp_restart();
  8.     }
  9.     StopElsp = millis();
  10.   }
  11. }
复制代码

工作的照片:

a.jpg

参考:



xiaom5.png
xiaom6.png

zoologist  初级技匠
 楼主|

发表于 2021-8-28 10:26:44

源代码   HumitRecorder.zip (3.8 KB, 下载次数: 27)
回复

使用道具 举报

刁雷  初级技匠

发表于 2021-10-27 11:32:14

膜拜大神
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail