From d554b5b296a49a4f85376f56c04b349dd1e12581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=B2=BB=E4=B8=9E?= <16113360+chen-zhichengzzz@user.noreply.gitee.com> Date: Sun, 23 Aug 2026 16:44:30 +0000 Subject: [PATCH] =?UTF-8?q?Day5=EF=BC=9A=E6=8F=90=E4=BA=A4AHT10=E9=87=87?= =?UTF-8?q?=E9=9B=86=E4=B8=8EData.txt=E5=AD=98=E5=82=A8=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 陈治丞 <16113360+chen-zhichengzzz@user.noreply.gitee.com> --- .../README.md" | 69 +++++++++++ .../aht10_data_logger.c" | 117 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 "2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/README.md" create mode 100644 "2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/aht10_data_logger.c" diff --git "a/2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/README.md" "b/2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/README.md" new file mode 100644 index 0000000..6015a4e --- /dev/null +++ "b/2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/README.md" @@ -0,0 +1,69 @@ +# 【DAY5】AHT10 采集、文件系统与云端命令框架 + +- 姓名:陈治丞 +- 组别:第 1 组 +- 开发板:STM32F407 星火一号 + +## 一、任务与边界 + +本作业设计 AHT10 温湿度采集、文件追加保存和云端命令控制 LED 的程序框架。源码为 `aht10_data_logger.c`。本提交不包含未实际采集的截图、温湿度数值或云端上报结果;所有运行数据应在完成硬件配置和实际测试后补充。 + +## 二、AHT10 温湿度采集 + +AHT10 通过 I2C 总线工作,默认地址为 `0x38`。程序在 `aht10_read()` 中发送触发测量命令 `AC 33 00`,等待转换完成后读取 6 字节原始数据,并按 AHT10 数据手册换算温度和湿度。 + +连接时需要确认: + +| AHT10 引脚 | 开发板 I2C 引脚 | +| --- | --- | +| VCC | 3.3 V | +| GND | GND | +| SDA | 所选 I2C 总线 SDA | +| SCL | 所选 I2C 总线 SCL | + +代码默认总线名为 `i2c1`;如果实际 BSP 注册的总线名称不同,需要修改 `AHT10_I2C_BUS`。 + +## 三、文件系统启动与 Data.txt + +要把数据保存到 Flash,需要先启用 FAL 和 DFS,并创建、格式化后挂载一个分区。挂载成功后,程序使用 POSIX `open()`、`write()` 和 `close()` 将数据追加写入: + +```text +/Data.txt +Temp: XX.XX; Humi: XX.XX; Count: N +``` + +`day5_collect` 每执行一次就读取一次 AHT10 并追加一行。计数值应由实际项目保存或在读取文件后统计;本框架保留了数据格式和追加逻辑,实际运行时可扩展为持久化计数。 + +## 四、云端命令与 LED + +`day5_handle_cloud_command()` 是云端接收回调的统一入口。网络组件(如 MQTT 或 HTTP 客户端)收到字符串后,只需要调用此函数: + +```text +led:on +led:off +led:toggle +``` + +函数会控制星火一号 PF12 的 LED_R。`day5_led on/off/toggle` 是对应的本地 MSH 测试命令,便于先验证命令处理逻辑,再接入云端回调。 + +## 五、需要启用的组件 + +当前基础工程只启用了 PIN 和 FinSH;使用完整功能前需要在 RT-Thread Studio 的 `menuconfig` 中启用: + +1. `RT_USING_I2C` 和对应 STM32 I2C 驱动; +2. AHT10 所使用 I2C 总线; +3. `RT_USING_DFS`、相应文件系统和 FAL/Flash 分区; +4. 云端通信所需网络、AT 客户端、MQTT 或 WebClient 组件。 + +未启用 I2C 或 DFS 时,`day5_collect` 会明确提示缺少配置,不会生成虚构的传感器数据。 + +## 六、MSH 使用方法 + +```text +msh >day5_led on +msh >day5_led toggle +msh >day5_collect +msh >cat Data.txt +``` + +在文件系统正确挂载、AHT10 正确接线后,`cat Data.txt` 应显示逐次追加的温湿度记录。每一条记录都必须来自实际采样。 diff --git "a/2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/aht10_data_logger.c" "b/2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/aht10_data_logger.c" new file mode 100644 index 0000000..0fae407 --- /dev/null +++ "b/2026/\347\254\2541\347\273\204/\351\231\210\346\262\273\344\270\236/\347\254\254\344\272\224\345\244\251\344\275\234\344\270\232/aht10_data_logger.c" @@ -0,0 +1,117 @@ +/* Day5: AHT10 acquisition, Data.txt logging, and a cloud-command entry. + * Enable RT_USING_I2C and RT_USING_DFS before using the logger command. */ +#include +#include +#include + +#define DAY5_LED_PIN GET_PIN(F, 12) +#define DAY5_FILE_PATH "/Data.txt" + +static rt_uint8_t day5_led_on; + +static void day5_set_led(rt_bool_t on) +{ + day5_led_on = on ? 1 : 0; + /* RT-Spark LED_R is active low. */ + rt_pin_write(DAY5_LED_PIN, day5_led_on ? PIN_LOW : PIN_HIGH); +} + +/* This function is the only entry required by an MQTT/HTTP receive callback. */ +int day5_handle_cloud_command(const char *command) +{ + if (command == RT_NULL) return -RT_EINVAL; + if (!rt_strcmp(command, "led:on")) day5_set_led(RT_TRUE); + else if (!rt_strcmp(command, "led:off")) day5_set_led(RT_FALSE); + else if (!rt_strcmp(command, "led:toggle")) day5_set_led(!day5_led_on); + else return -RT_EINVAL; + rt_kprintf("day5 cloud command accepted: %s\n", command); + return RT_EOK; +} + +#if defined(RT_USING_I2C) && defined(RT_USING_DFS) +#include +#include + +static rt_uint32_t day5_sample_count; + +#define AHT10_I2C_BUS "i2c1" +#define AHT10_ADDRESS 0x38 + +static rt_err_t aht10_read(float *temperature, float *humidity) +{ + struct rt_i2c_bus_device *bus; + struct rt_i2c_msg msgs[2]; + rt_uint8_t trigger[3] = {0xac, 0x33, 0x00}; + rt_uint8_t data[6]; + rt_uint32_t raw_h, raw_t; + + if (temperature == RT_NULL || humidity == RT_NULL) return -RT_EINVAL; + bus = (struct rt_i2c_bus_device *)rt_device_find(AHT10_I2C_BUS); + if (bus == RT_NULL) return -RT_ENOSYS; + + msgs[0].addr = AHT10_ADDRESS; msgs[0].flags = RT_I2C_WR; msgs[0].buf = trigger; msgs[0].len = sizeof(trigger); + if (rt_i2c_transfer(bus, msgs, 1) != 1) return -RT_ERROR; + rt_thread_mdelay(80); + msgs[1].addr = AHT10_ADDRESS; msgs[1].flags = RT_I2C_RD; msgs[1].buf = data; msgs[1].len = sizeof(data); + if (rt_i2c_transfer(bus, &msgs[1], 1) != 1 || (data[0] & 0x80)) return -RT_ERROR; + + raw_h = ((rt_uint32_t)data[1] << 12) | ((rt_uint32_t)data[2] << 4) | (data[3] >> 4); + raw_t = ((rt_uint32_t)(data[3] & 0x0f) << 16) | ((rt_uint32_t)data[4] << 8) | data[5]; + *humidity = raw_h * 100.0f / 1048576.0f; + *temperature = raw_t * 200.0f / 1048576.0f - 50.0f; + return RT_EOK; +} + +static int day5_collect(int argc, char **argv) +{ + float temperature, humidity; + int fd; + char line[80]; + int length; + + RT_UNUSED(argc); RT_UNUSED(argv); + if (aht10_read(&temperature, &humidity) != RT_EOK) + { + rt_kprintf("AHT10 read failed: check %s and wiring\n", AHT10_I2C_BUS); + return -RT_ERROR; + } + fd = open(DAY5_FILE_PATH, O_WRONLY | O_CREAT | O_APPEND, 0); + if (fd < 0) { rt_kprintf("open %s failed: mount DFS first\n", DAY5_FILE_PATH); return -RT_ERROR; } + day5_sample_count++; + length = rt_snprintf(line, sizeof(line), "Temp: %.2f; Humi: %.2f; Count: %lu\n", + temperature, humidity, (unsigned long)day5_sample_count); + if (write(fd, line, length) != length) { close(fd); return -RT_ERROR; } + close(fd); + rt_kprintf("%s", line); + return RT_EOK; +} +MSH_CMD_EXPORT(day5_collect, read AHT10 and append to /Data.txt); +#else +static int day5_collect(int argc, char **argv) +{ + RT_UNUSED(argc); RT_UNUSED(argv); + rt_kprintf("day5_collect needs RT_USING_I2C and RT_USING_DFS. Enable AHT10, DFS/FAL, then rebuild.\n"); + return -RT_ENOSYS; +} +MSH_CMD_EXPORT(day5_collect, configuration required: I2C and DFS); +#endif + +static int day5_led(int argc, char **argv) +{ + RT_UNUSED(argc); + if (argc != 2) { rt_kprintf("usage: day5_led [on|off|toggle]\n"); return -RT_EINVAL; } + if (!rt_strcmp(argv[1], "on")) return day5_handle_cloud_command("led:on"); + if (!rt_strcmp(argv[1], "off")) return day5_handle_cloud_command("led:off"); + if (!rt_strcmp(argv[1], "toggle")) return day5_handle_cloud_command("led:toggle"); + return -RT_EINVAL; +} +MSH_CMD_EXPORT(day5_led, test cloud command handler: on/off/toggle); + +static int day5_init(void) +{ + rt_pin_mode(DAY5_LED_PIN, PIN_MODE_OUTPUT); + day5_set_led(RT_FALSE); + rt_kprintf("Day5 ready: use day5_collect and day5_led\n"); + return RT_EOK; +} +INIT_APP_EXPORT(day5_init); -- Gitee