本文介绍了 DFRobot Beetle RP2350结合VC02、AHT20实现的一个桌面小摆件实现步骤(未完成),通过OLED、VC02以及RP2350实现可对话交互的桌面语音对话摆件(虽然不知道有什么用)。
VC02模组
VC-02 是深圳市安信可科技有限公司开发的一款低成本纯离线语音识别模组。支持中、英文双语控制、单MIC接入、支持AEC回声消除、稳态降噪等功能,今天我们使用这款模组用来做离线语音识别,同时在未来可以加入家庭台灯、电器等家具的控制,实现自制的智能语音助手。

AHT20
HT20 是 DHT11 的全新升级产品,配置了专用的 ASIC 传感器芯片、高性能的半导体硅基电容式湿度传感器和一个标准的片上温度传感器,并使用了标准 I²C 数据输出信号格式。具有完全标定
数字输出,IIC 接口,优异的长期稳定性,响应迅速、抗干扰能力强,宽电压支持 2.2-5.5 VDC等特点。
准备工作
首先准备好DFROBOT RP2350开发板、拓展板(自己绘制的,稍后开源)、VC02模组、OLED屏幕的硬件,焊接完成之后如下图所示。
这里博主采用的是pico的SDK对RP2350进行开发,首先测试了AHT20是否能正确挂载出来,测试代码如下所示:
AHT源文件(用ESP32的代码改的,凑合用)
/**
* @file aht20.c
* @brief AHT20 Temperature and Humidity Sensor Driver Implementation for RP2350
*/
#include "aht20.h"
#define AHT20_DEVICE_ADDR 0x38
#define AHT20_READ_ADDR ((AHT20_DEVICE_ADDR << 1) | 1)
#define AHT20_WRITE_ADDR ((AHT20_DEVICE_ADDR << 1) | 0)
#define AHT20_CMD_MEASUREMENT 0xAC
#define AHT20_CMD_READ_STATUS 0x71
#define AHT20_CMD_INIT 0xBE
#define AHT20_CMD_RST 0xBA
#define AHT20_DELAY_MEASUREMENT 80
#define AHT20_DELAY_INIT 10
#define GET_BIT(byte, index) ((byte & (1 << index)) >> index)
// Debug日志打印宏,可根据需要打开或关闭
#define DEBUG_ENABLE 0
#if DEBUG_ENABLE
#define ESP_LOGD(tag, format, ...) printf("[D][%s] " format "\n", tag, ##__VA_ARGS__)
#define ESP_LOGI(tag, format, ...) printf("[I][%s] " format "\n", tag, ##__VA_ARGS__)
#else
#define ESP_LOGD(tag, format, ...)
#define ESP_LOGI(tag, format, ...)
#endif
// 定义ESP_OK常量以保持原代码风格一致
#define ESP_OK 0
//////////////////////////////////////////////// GLOBAL_VARIABLE ////////////////////////////////////////////////
uint8_t data[7] = {0};
uint8_t mode;
uint8_t cal;
//////////////////////////////////////////////// PRIVATE_DEFINITION ////////////////////////////////////////////////
/// @brief 发送初始化命令给设备
/// @return 操作是否成功
static int m_AHT20_command_init(void);
/// @brief 发送复位命令给设备
/// @return 操作是否成功
static int m_AHT20_command_reset(void);
/// @brief 读取设备状态
/// @return 操作是否成功
static int m_AHT20_command_read_status(void);
/// @brief 发送测量命令给设备
/// @return 操作是否成功
static int m_AHT20_command_measure(void);
/// @brief 解析设备状态
/// @param pAHT20_data 指向数据结构体的指针
/// @return 操作是否成功
static int m_AHT20_decode_status(AHT20_data_t *pAHT20_data);
/// @brief 从设备读取结果数据
/// @param pAHT20_data 指向数据结构体的指针
/// @param len 读取的字节数
/// @return 操作是否成功
static int m_AHT20_get_result(AHT20_data_t *pAHT20_data, size_t len);
//////////////////////////////////////////////// PRIVATE_DECLARATION ////////////////////////////////////////////////
/// @brief 发送初始化命令给设备
/// @return 操作是否成功
static int m_AHT20_command_init(void)
{
int ret = 1;
uint8_t cmd[3] = {AHT20_CMD_INIT, 0x08, 0x00};
int result = i2c_write_blocking(I2C_MASTER_PORT, AHT20_DEVICE_ADDR, cmd, 3, false);
if (result == 3) {
ESP_LOGD("m_AHT20_command_init", "completed");
ret = 0;
}
return ret;
}
/// @brief 发送复位命令给设备
/// @return 操作是否成功
static int m_AHT20_command_reset(void)
{
int ret = 1;
uint8_t cmd = AHT20_CMD_RST;
int result = i2c_write_blocking(I2C_MASTER_PORT, AHT20_DEVICE_ADDR, &cmd, 1, false);
if (result == 1) {
ESP_LOGD("m_AHT20_command_reset", "completed");
ret = 0;
}
return ret;
}
/// @brief 读取设备状态
/// @return 操作是否成功
static int m_AHT20_command_read_status(void)
{
int ret = 1;
uint8_t cmd = AHT20_CMD_READ_STATUS;
int result = i2c_write_blocking(I2C_MASTER_PORT, AHT20_DEVICE_ADDR, &cmd, 1, false);
if (result == 1) {
ESP_LOGD("m_AHT20_command_read_status", "completed");
ret = 0;
}
return ret;
}
/// @brief 发送测量命令给设备
/// @return 操作是否成功
static int m_AHT20_command_measure(void)
{
int ret = 1;
uint8_t cmd[3] = {AHT20_CMD_MEASUREMENT, 0x33, 0x00};
int result = i2c_write_blocking(I2C_MASTER_PORT, AHT20_DEVICE_ADDR, cmd, 3, false);
if (result == 3) {
ESP_LOGD("m_AHT20_command_measure", "completed");
ret = 0;
}
return ret;
}
/// @brief 解析设备状态
/// @param pAHT20_data 指向数据结构体的指针
/// @return 操作是否成功
static int m_AHT20_decode_status(AHT20_data_t *pAHT20_data)
{
int ret = 1;
// if bit[7] == 1, device is busy
if (GET_BIT(data[0], 7) == 1)
pAHT20_data->is_busy = 1;
else
pAHT20_data->is_busy = 0;
// if bit[3] == 1, device has been calibrated
if (GET_BIT(data[0], 3) == 1)
cal = 1;
else
cal = 0;
// if bit[6] == 1, device is under CMD mode
if (GET_BIT(data[0], 6) == 1)
mode = 2;
// if bit[5] == 1 and bit[6] == 0, device is under CYC mode
else if (GET_BIT(data[0], 6) == 0 || GET_BIT(data[0], 5) == 1)
mode = 1;
// if bit[5] == 0 and bit[6] == 0, device is under NOR mode
else
mode = 0;
ESP_LOGD("m_AHT20_decode_status", "AHT20 STATUS: BUSY=%d; CAL=%d; MODE=%d; BIN:%d%d%d%d%d%d%d%d; HEX:%x",
pAHT20_data->is_busy, cal, mode,
GET_BIT(data[0], 0), GET_BIT(data[0], 1), GET_BIT(data[0], 2), GET_BIT(data[0], 3),
GET_BIT(data[0], 4), GET_BIT(data[0], 5), GET_BIT(data[0], 6), GET_BIT(data[0], 7), data[0]);
ret = 0;
return ret;
}
/// @brief 从设备读取结果数据
/// @param pAHT20_data 指向数据结构体的指针
/// @param len 读取的字节数
/// @return 操作是否成功
static int m_AHT20_get_result(AHT20_data_t *pAHT20_data, size_t len)
{
int ret = 1;
// 读取len个字节的数据
int result = i2c_read_blocking(I2C_MASTER_PORT, AHT20_DEVICE_ADDR, data, len, false);
if (result == len) {
ESP_LOGD("m_AHT20_get_result", "completed");
ret = 0;
}
return ret;
}
//////////////////////////////////////////////// PUBLIC_DECLARATION ////////////////////////////////////////////////
/// @brief 初始化AHT20传感器,包括重置和校准
/// @param pAHT20_data 指向数据结构体的指针
/// @return 成功返回0,失败返回非0值
int AHT20_begin(AHT20_data_t *pAHT20_data)
{
sleep_ms(40); // 等待40毫秒让传感器稳定
m_AHT20_command_reset();
sleep_ms(40); // 等待重置完成
m_AHT20_command_read_status();
m_AHT20_get_result(pAHT20_data, 1);
m_AHT20_decode_status(pAHT20_data);
ESP_LOGD("AHT20", "begin: calibrated=%d", cal);
if(cal) {
return ESP_OK;
}
ESP_LOGD("AHT20", "begin: init");
m_AHT20_command_init();
sleep_ms(AHT20_DELAY_INIT);
while (!cal) {
sleep_ms(40);
m_AHT20_command_read_status();
m_AHT20_get_result(pAHT20_data, 1);
m_AHT20_decode_status(pAHT20_data);
ESP_LOGD("AHT20", "begin: calibrated=%d", cal);
}
return cal ? ESP_OK : -1;
}
/// @brief 测量温度和湿度
/// @param pAHT20_data 指向数据结构体的指针
/// @return 成功返回0,失败返回非0值
int AHT20_measure(AHT20_data_t *pAHT20_data)
{
int ret = 1;
uint32_t rh_raw, temp_raw = 0;
float rh, temp = 0;
m_AHT20_command_measure();
sleep_ms(AHT20_DELAY_MEASUREMENT);
m_AHT20_get_result(pAHT20_data, 7);
m_AHT20_decode_status(pAHT20_data);
// 如果传感器忙,则返回错误
if (pAHT20_data->is_busy == 1) {
ESP_LOGI("AHT20", "the device is busy");
return ret;
}
// 解析数据
rh_raw = (((uint32_t)data[1] << 16) | ((uint32_t)data[2] << 8) | (data[3])) >> 4;
temp_raw = ((uint32_t)(data[3] & 0x0F) << 16) | ((uint32_t)data[4] << 8) | (uint32_t)data[5];
// 转换为物理值
rh = (rh_raw * (0.0000953674316F));
temp = (temp_raw * (0.00019073F) - 50);
// 检查读数是否在合理范围内
if (rh > 100 || rh < 0 || temp > 120 || temp < -40) {
ESP_LOGD("AHT20", "the measurement is out of bounds %f, %f", rh, temp);
return ret;
}
// 保存结果
pAHT20_data->r_humidity = rh;
pAHT20_data->temperature = temp;
ESP_LOGD("AHT20", "Temperature: %f, Relative Humidity: %f", pAHT20_data->temperature, pAHT20_data->r_humidity);
ret = 0;
return ret;
}
AHT头文件
/**
* @file aht20.h
* @brief AHT20 Temperature and Humidity Sensor Driver Header for RP2350
*/
#pragma once
#include "hardware/i2c.h"
#include "pico/stdlib.h"
#include
#define I2C_MASTER_PORT i2c0 // 默认I2C接口,根据需要可修改为i2c1
/// @brief 存储传感器数据的结构体
typedef struct AHT20
{
float r_humidity; // 相对湿度(%)
float temperature; // 温度(°C)
uint8_t is_busy; // 传感器忙状态标志
} AHT20_data_t;
//////////////////////////////////////////////// PUBLIC_DEFINITION ////////////////////////////////////////////////
/// @brief 初始化AHT20传感器,包括重置和校准
/// @param pAHT20_data 指向数据结构体的指针
/// @return 成功返回0,失败返回非0值
int AHT20_begin(AHT20_data_t *pAHT20_data);
/// @brief 测量温度和湿度
/// @param pAHT20_data 指向数据结构体的指针
/// @return 成功返回0,失败返回非0值
int AHT20_measure(AHT20_data_t *pAHT20_data);
测试结果

可以正常和AHT20通信,硬件测试没问题!!!接下来就是简单的语音交互与OLED显示实现,未完待续……
评论