传感器驱动(ds1307/ds3231)(ahtx0_th)

This commit is contained in:
sc committed 2025-12-28 15:24:20 +08:00
1 parent 201d203888
commit 7a3b64472d
3 files changed
+1272 -1054

No files matched your search

+218
View File
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2025, Your Name
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-12-27 Developer First version for AHT20 on RT-Thread
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define DBG_TAG "sensor.aht20"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
/* AHT20 I2C 地址 */
#define AHT20_I2C_ADDR 0x38
/* 使用的 I2C 总线设备名 */
#define AHT20_I2C_BUS_NAME "i2c2" // 根据你的板子修改,如 "i2c2"
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
/**
* 向 AHT20 发送命令
*/
static rt_err_t aht20_send_cmd(rt_uint8_t cmd, const rt_uint8_t *data, rt_size_t len)
{
rt_uint8_t buf[3] = {cmd};
if (len > 0)
{
rt_memcpy(&buf[1], data, len);
}
struct rt_i2c_msg msgs[1] = {
{
.addr = AHT20_I2C_ADDR,
.flags = RT_I2C_WR,
.buf = buf,
.len = 1 + len,
}
};
if (rt_i2c_transfer(i2c_bus, msgs, 1) != 1)
{
LOG_E("I2C send command 0x%02X failed.", cmd);
return -RT_ERROR;
}
return RT_EOK;
}
/**
* 从 AHT20 读取数据
*/
static rt_err_t aht20_read_data(rt_uint8_t *buf, rt_size_t len)
{
struct rt_i2c_msg msgs[1] = {
{
.addr = AHT20_I2C_ADDR,
.flags = RT_I2C_RD,
.buf = buf,
.len = len,
}
};
if (rt_i2c_transfer(i2c_bus, msgs, 1) != 1)
{
LOG_E("I2C read data failed.");
return -RT_ERROR;
}
return RT_EOK;
}
/**
* 初始化 AHT20
*/
static rt_err_t aht20_init_sensor(void)
{
rt_uint8_t status = 0;
rt_uint8_t cmd_data[2] = {0x08, 0x00};
/* 发送初始化命令 */
if (aht20_send_cmd(0xBE, cmd_data, 2) != RT_EOK)
{
LOG_E("Failed to send init command.");
return -RT_ERROR;
}
rt_thread_mdelay(20); // 等待初始化完成
/* 读取状态字节(可选) */
if (aht20_read_data(&status, 1) == RT_EOK)
{
LOG_D("AHT20 status: 0x%02X", status);
}
return RT_EOK;
}
/**
* 触发一次温湿度测量
*/
static rt_err_t aht20_trigger_measure(void)
{
rt_uint8_t cmd[2] = {0x33, 0x00};
return aht20_send_cmd(0xAC, cmd, 2);
}
/**
* 读取原始温湿度数据(6 字节)
*/
static rt_err_t aht20_fetch_raw(rt_uint8_t raw[6])
{
return aht20_read_data(raw, 6);
}
/**
* 解析原始数据为温度(0.1°C)和湿度(0.1%RH)
*/
static void aht20_parse_data(const rt_uint8_t raw[6], rt_int32_t *temp, rt_int32_t *humi)
{
rt_uint32_t humi_raw = ((rt_uint32_t)raw[1] << 12) | ((rt_uint32_t)raw[2] << 4) | (raw[3] >> 4);
rt_uint32_t temp_raw = ((rt_uint32_t)raw[3] & 0x0F) << 16 | ((rt_uint32_t)raw[4] << 8) | raw[5];
*humi = (rt_int32_t)((humi_raw * 1000) / (1 << 20)); // 转换为 0.1%RH
*temp = (rt_int32_t)((temp_raw * 2000) / (1 << 20) - 500); // 转换为 0.1°C(公式:T = (raw / 2^20) * 200 - 50)
}
/**
* AHT20 读取线程
*/
static void aht20_thread_entry(void *parameter)
{
rt_uint8_t raw_data[6];
rt_int32_t temperature, humidity;
while (1)
{
if (aht20_trigger_measure() != RT_EOK)
{
LOG_E("Trigger measurement failed.");
rt_thread_mdelay(2000);
continue;
}
rt_thread_mdelay(80); // AHT20 典型转换时间 75ms
if (aht20_fetch_raw(raw_data) != RT_EOK)
{
LOG_E("Fetch raw data failed.");
rt_thread_mdelay(2000);
continue;
}
/* 检查忙标志(bit7 of raw_data[0] 应为 0)*/
if (raw_data[0] & 0x80)
{
LOG_W("AHT20 is busy, retrying...");
rt_thread_mdelay(100);
continue;
}
aht20_parse_data(raw_data, &temperature, &humidity);
LOG_I("Temp: %d.%dC, Humidity: %d.%dRH",
temperature / 10, temperature % 10,
humidity / 10, humidity % 10);
rt_thread_mdelay(5000); // 每 2 秒读取一次
}
}
/**
* AHT20 驱动初始化函数
*/
static int rt_hw_aht20_init(void)
{
i2c_bus = rt_i2c_bus_device_find(AHT20_I2C_BUS_NAME);
if (i2c_bus == RT_NULL)
{
LOG_E("Failed to find I2C bus: %s", AHT20_I2C_BUS_NAME);
return -RT_ENOSYS;
}
LOG_I("Found I2C bus: %s", AHT20_I2C_BUS_NAME);
if (aht20_init_sensor() != RT_EOK)
{
LOG_E("AHT20 sensor initialization failed!");
return -RT_ERROR;
}
LOG_I("AHT20 initialized successfully.");
/* 创建读取线程 */
rt_thread_t tid = rt_thread_create("ahtX0",
aht20_thread_entry,
RT_NULL,
512,
RT_THREAD_PRIORITY_MAX - 2,
10);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
LOG_E("Failed to create AHT20 thread.");
return -RT_ERROR;
}
return RT_EOK;
}
/* 自动初始化 */
INIT_APP_EXPORT(rt_hw_aht20_init);
+274
View File
@@ -0,0 +1,274 @@
/**
* @file drv_rtc_ds1307.c
* @brief DS1307 RTC driver for RT-Thread
* @author jiache (wanghuan3037@fiberhome.com)
* @version 1.1
* @date 2025-12-13
*
* Notes:
* - DS1307 requires 5V for reliable operation (not just 3.3V or backup battery).
* - Ensure I2C pull-up resistors are present.
*
* Kconfig usage (add to board/Kconfig):
* config BRD_RTC_DS1307
* bool "Enable rtc ds1307"
* default n
* if BRD_RTC_DS1307
* config DS1307_IIC_BUS
* string "Select I2C bus"
* default "i2c2"
* config BRD_RTC_DS1307_DEBUG
* bool "Enable DS1307 debug log"
* default n
* endif
*/
#include "board.h"
#include <rtdevice.h>
#include <rtthread.h>
#include <sys/time.h>
#include <drivers/rtc.h>
#define DBG_TAG "DS1307"
#ifdef BRD_RTC_DS1307_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
/* DS1307 I2C 7-bit address */
#define DS1307_ADDR 0x68
/* Driver structure */
typedef struct drv_rtc_ds1307
{
struct rt_i2c_bus_device *i2c_bus;
char *iic_name;
struct tm datetime;
struct timeval tick;
rt_thread_t thd_soft_update_sec;
} drv_rtc_ds1307_t;
/* Default I2C bus name from Kconfig or hardcoded */
#ifndef DS1307_IIC_BUS
#define DS1307_IIC_BUS "i2c2"
#endif
static drv_rtc_ds1307_t ds1307 = {
.iic_name = DS1307_IIC_BUS,
};
/* Write multiple registers starting at reg */
static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, const rt_uint8_t *data, rt_size_t len)
{
rt_uint8_t buf[16];
if (len + 1 > sizeof(buf)) return -RT_EINVAL;
buf[0] = reg;
rt_memcpy(&buf[1], data, len);
struct rt_i2c_msg msg;
msg.addr = DS1307_ADDR;
msg.flags = RT_I2C_WR;
msg.buf = buf;
msg.len = len + 1;
return (rt_i2c_transfer(bus, &msg, 1) == 1) ? RT_EOK : -RT_ERROR;
}
/* Read multiple registers starting at reg */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
{
struct rt_i2c_msg msgs[2];
msgs[0].addr = DS1307_ADDR;
msgs[0].flags = RT_I2C_WR;
msgs[0].buf = &reg;
msgs[0].len = 1;
msgs[1].addr = DS1307_ADDR;
msgs[1].flags = RT_I2C_RD;
msgs[1].buf = buf;
msgs[1].len = len;
return (rt_i2c_transfer(bus, msgs, 2) == 2) ? RT_EOK : -RT_ERROR;
}
/* Read current time from DS1307 */
static void ds1307_read_time(void)
{
uint8_t buff[7];
RT_ASSERT(ds1307.i2c_bus);
if (read_regs(ds1307.i2c_bus, 0x00, 7, buff) != RT_EOK)
{
LOG_E("Failed to read DS1307 registers");
return;
}
// BCD to decimal
ds1307.datetime.tm_sec = (buff[0] & 0x7F); // mask CH bit
ds1307.datetime.tm_sec = (ds1307.datetime.tm_sec >> 4) * 10 + (ds1307.datetime.tm_sec & 0x0F);
ds1307.datetime.tm_min = (buff[1] >> 4) * 10 + (buff[1] & 0x0F);
ds1307.datetime.tm_hour = (buff[2] >> 4) * 10 + (buff[2] & 0x0F);
ds1307.datetime.tm_wday = (buff[3] & 0x07) - 1; // DS1307: 1=Sun → tm_wday: 0=Sun
ds1307.datetime.tm_mday = (buff[4] >> 4) * 10 + (buff[4] & 0x0F);
ds1307.datetime.tm_mon = (buff[5] >> 4) * 10 + (buff[5] & 0x0F) - 1; // 0-based
ds1307.datetime.tm_year = (buff[6] >> 4) * 10 + (buff[6] & 0x0F) + 100; // years since 1900
// Optional: update tick if libc is available
#ifdef RT_USING_LIBC
ds1307.tick.tv_sec = mktime(&ds1307.datetime);
ds1307.tick.tv_usec = 0;
#endif
LOG_I("RTC: %d-%02d-%02d %02d:%02d:%02d",
ds1307.datetime.tm_year + 1900,
ds1307.datetime.tm_mon + 1,
ds1307.datetime.tm_mday,
ds1307.datetime.tm_hour,
ds1307.datetime.tm_min,
ds1307.datetime.tm_sec);
if(ds1307.datetime.tm_year<199)//
{
/* 设置日期为年月号 */
set_date(ds1307.datetime.tm_year + 1900, ds1307.datetime.tm_mon + 1, ds1307.datetime.tm_mday);
/* 设置时间为点分秒 */
set_time(ds1307.datetime.tm_hour, ds1307.datetime.tm_min, ds1307.datetime.tm_sec);
}
}
/* Software thread to maintain local time estimation */
static void auto_update_current_datatime(void *parameter)
{
uint32_t count = 0;
while (1)
{
rt_thread_delay(RT_TICK_PER_SECOND);
// Sync with hardware every 10 minutes
if (++count >= 3600) // 600 seconds
{
ds1307_read_time();
count = 0;
}
}
}
/* Directly write struct tm to DS1307 (no time_t dependency) */
static rt_err_t ds1307_write_tm(struct tm *tm)
{
uint8_t buff[7];
// Seconds (bit7 = CH must be 0 to enable oscillator)
buff[0] = ((tm->tm_sec / 10) << 4) | (tm->tm_sec % 10);
// Minutes
buff[1] = ((tm->tm_min / 10) << 4) | (tm->tm_min % 10);
// Hours (24-hour mode, bit6=0)
buff[2] = ((tm->tm_hour / 10) << 4) | (tm->tm_hour % 10);
// Day of week: DS1307 uses 1=Sun, 2=Mon ... 7=Sat
// tm_wday: 0=Sun, 1=Mon ... 6=Sat → so +1
buff[3] = tm->tm_wday + 1;
// Date
buff[4] = ((tm->tm_mday / 10) << 4) | (tm->tm_mday % 10);
// Month
int month = tm->tm_mon + 1; // convert to 1-based
buff[5] = ((month / 10) << 4) | (month % 10);
// Year (last two digits only)
int year = tm->tm_year + 1900; // full year
buff[6] = (((year % 100) / 10) << 4) | (year % 10);
rt_err_t err = write_reg(ds1307.i2c_bus, 0x00, buff, 7);
if (err == RT_EOK)
{
ds1307.datetime = *tm;
#ifdef RT_USING_LIBC
ds1307.tick.tv_sec = mktime(tm);
ds1307.tick.tv_usec = 0;
#endif
}
return err;
}
/* Initialization and registration */
static int rt_hw_ds1307_rtc_init(void)
{
ds1307.i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(ds1307.iic_name);
if (!ds1307.i2c_bus)
{
LOG_E("I2C bus '%s' not found", ds1307.iic_name);
return -RT_ERROR;
}
ds1307_read_time();
ds1307.thd_soft_update_sec = rt_thread_create("ds1307",auto_update_current_datatime,RT_NULL,256, 20, 5);
if (ds1307.thd_soft_update_sec)
{
rt_thread_startup(ds1307.thd_soft_update_sec);
}
LOG_I("DS1307 RTC initialized successfully on %s", ds1307.iic_name);
return RT_EOK;
}
INIT_APP_EXPORT(rt_hw_ds1307_rtc_init);
/* MSH Commands */
#include <stdlib.h>
int date_drv_set(int argc, char *argv[])
{
if (argc != 7)
{
rt_kprintf("Usage: ds1307_set_time YYYY MM DD HH MM SS\n");
rt_kprintf("Example: ds1307_set_time 2025 12 25 10 30 00\n");
return -1;
}
struct tm tm_time = {0};
tm_time.tm_year = atoi(argv[1]) - 1900;
tm_time.tm_mon = atoi(argv[2]) - 1;
tm_time.tm_mday = atoi(argv[3]);
tm_time.tm_hour = atoi(argv[4]);
tm_time.tm_min = atoi(argv[5]);
tm_time.tm_sec = atoi(argv[6]);
// Basic validation
if (tm_time.tm_year < 100 || tm_time.tm_year > 200 ||
tm_time.tm_mon < 0 || tm_time.tm_mon > 11 ||
tm_time.tm_mday < 1 || tm_time.tm_mday > 31 ||
tm_time.tm_hour < 0 || tm_time.tm_hour > 23 ||
tm_time.tm_min < 0 || tm_time.tm_min > 59 ||
tm_time.tm_sec < 0 || tm_time.tm_sec > 59)
{
rt_kprintf("Error: Invalid date/time range!\n");
return -1;
}
rt_err_t err = ds1307_write_tm(&tm_time);
if (err != RT_EOK)
{
rt_kprintf("Error: Failed to write DS1307!\n");
return -1;
}
rt_kprintf("Success: DS1307 time set.\n");
return 0;
}
MSH_CMD_EXPORT(date_drv_set, Set DS1307 RTC time: YYYY MM DD HH MM SS);
void date_drv(void)
{
ds1307_read_time();
}
MSH_CMD_EXPORT(date_drv, Read DS1307 RTC time);
/* BRD_RTC_DS1307 */