Funpack4-3 基于MAX32655实现蓝牙读取米家温湿度计
该项目使用了MAX32655,实现了读取米家温湿度计的设计,它的主要功能为:通过蓝牙读取米家温湿度计,并显示在LCD屏幕上。
标签
Funpack活动
温湿度计
MAX32655
Funpack4-3
米家温湿度计
米家
枫雪天
更新2026-02-10
7

任务介绍

本项目实现了Funpack4-3活动板卡一的任务2,基于MAX32655FTHR开发板的蓝牙低功耗数据客户端应用,通过BLE的GATT服务连接并读取小米温湿度计2的数据,并将温度、湿度等信息实时显示在ST7735S彩色LCD屏幕上,同时支持按钮控制和数据交互功能。

硬件平台

本次使用Analog Devices MAX32655FTHR开发板,是一款面向物联网应用的高性能蓝牙低功耗开发平台。该开发板搭载了基于ARM Cortex-M4内核的MAX32655微控制器,具备丰富的外设资源,包括多个I2C接口、SPI接口、GPIO端口等,非常适合用于蓝牙低功耗应用的开发。开发板集成了蓝牙射频模块、调试接口、用户可编程按键与LED,便于快速搭建无线传感器网络系统。

在软件方面,本项目采用WSF(Wireless Software Framework)蓝牙协议栈作为底层运行环境。WSF以其模块化设计、高可靠性和良好的跨平台支持而著称,适用于资源受限的嵌入式设备。通过将蓝牙协议栈移植至MAX32655平台,实现了BLE客户端连接、GATT服务发现以及数据传输等功能。

主控设备:Analog Devices MAX32655FTHR开发板

  • 搭载MAX32655 MCU(ARM Cortex-M4F)
  • 集成蓝牙5.0低功耗射频模块
  • 板载2个用户可编程LED指示灯
  • 支持多连接蓝牙客户端应用

max32655引脚图.png

米家温湿度计2

ST7735S彩色OLED显示屏

任务分析与实现

本系统实现了基于WSF蓝牙协议栈的温湿度监测平台,主要功能包括:

  • 传感器数据采集
    • 小米温湿度计2数据读取:实时监测
    • 支持温度、湿度、电压等多参数获取
  • LCD显示控制
    • 显示刷新率:实时更新
    • 彩色图形界面渲染


方案框图:

本任务实现的核心是在 MAX32655FTHR 开发板上完成 WSF 蓝牙协议栈的成功调用,并在此基础上实现了对温湿度传感器数据的读取与彩色LCD屏幕的显示控制。接下来详细描述关键流程和核心要点。

一、使用前的准备

1. 硬件环境

  • 主控芯片:MAX32655(ARM Cortex-M4F 内核)
  • 开发板:MAX32655FTHR
  • 外设资源
    • SPI 接口用于驱动 ST7735S 彩色显示屏
    • GPIO 控制用户按键输入
    • UART 串口调试输出

2. 软件环境

  • 开发环境:VS Code + CodeFusion Studio 插件
  • 协议栈:WSF Bluetooth Stack
  • 编译工具链:GCC ARM Embedded (arm-none-eabi-gcc)


二、核心步骤

1. 应用程序框架创建

应用程序框架主要包括事件处理、连接管理、服务发现以及数据解析等部分。

a. 事件处理机制 (datc_main.c)

  • 定义蓝牙事件回调函数
  • 处理连接建立、断开事件
  • 实现服务发现与数据接收逻辑
static void datcDmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
uint16_t len;

len = DmSizeOfEvt(pDmEvt);

if ((pMsg = WsfMsgAlloc(len + pDmEvt->scanReport.len)) != NULL) {
memcpy(pMsg, pDmEvt, len);
if (pDmEvt->hdr.event == DM_SCAN_REPORT_IND) {
pMsg->scanReport.pData = (uint8_t *)((uint8_t *)pMsg + len);
memcpy(pMsg->scanReport.pData, pDmEvt->scanReport.pData, pDmEvt->scanReport.len);
}
WsfMsgSend(datcCb.handlerId, pMsg);
}
}

b. 数据接收处理 (datc_main.c)

  • 解析小米温湿度计数据包
  • 提取温度、湿度、电压信息
  • 调用显示更新函数
static void datcValueNtf(attEvt_t *pMsg)
{
if (pMsg->handle == pSecDatHdlList[pMsg->hdr.param - 1][SEC_DAT_HDL_IDX]) {
if (pMsg->valueLen >= 5) {
int16_t temp = (int16_t)(pMsg->pValue[0] | (pMsg->pValue[1] << 8));
uint16_t humidity = pMsg->pValue[2];
uint16_t voltage = (pMsg->pValue[3] | (pMsg->pValue[4] << 8));
float battery = ((float)(voltage - 2000) / (float)(3261 - 2000)) * 100.0f;

extern void update_display_values(int16_t temp, uint16_t humidity, uint16_t voltage, float battery);
update_display_values(temp, humidity, voltage, battery);
}
}
}

2. 蓝牙服务发现 (sdsc_main.c)

完成GATT服务和特征值发现:

void SecDatSvcDiscover(dmConnId_t connId, uint16_t *pHdlList)
{
AppDiscFindService(connId, ATT_128_UUID_LEN, (uint8_t *)SecDatSvcUuid, SEC_HDL_LIST_LEN,
(attcDiscChar_t **)secDatDiscCharList, pHdlList);
}

3. 设备驱动适配

a. SPI驱动 (main.c)

  • 使用SPI接口实现显示屏通信
  • 配置SPI时序参数以匹配ST7735S要求
static int spi_tx(uint8_t *data, unsigned int len)
{
mxc_spi_req_t req;

req.spi = MXC_SPI1;
req.txData = data;
req.rxData = NULL;
req.txLen = len;
req.rxLen = 0;
req.ssIdx = 0;
req.ssDeassert = 1;
req.txCnt = 0;
req.rxCnt = 0;
req.completeCB = NULL;

return MXC_SPI_MasterTransaction(&req);
}

b. 显示驱动 (st7735s.c)

  • 封装显示控制器初始化序列
  • 实现像素绘制和区域刷新功能
  • 集成LVGL图形库支持

4. 图形界面集成

使用LVGL图形库提供用户界面:

static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
int32_t x, x1, x2;
int32_t y, y1, y2;
uint8_t *lineptr;
unsigned int len;

x1 = area->x1;
x2 = area->x2;
y1 = area->y1;
y2 = area->y2;

for (y = y1; y <= y2; y++) {
st7735s_xyloc(y, x1);
len = 0;
lineptr = linebuf;
for (x = x1; x <= x2; x++) {
*lineptr++ = color_p->ch.blue << 3;
*lineptr++ = color_p->ch.green << 2;
*lineptr++ = color_p->ch.red << 3;
len += 3;
color_p++;
}
st7735s_write_pixels(linebuf, len);
}

lv_disp_flush_ready(disp_drv);
}

代码详解

整体软件流程图:


一、硬件初始化与传感器配置

系统启动后首先完成外设初始化序列,关键流程如下:

  • 配置GPIO引脚为输入/输出模式,确保按键与LED正常工作
  • 初始化SPI接口,设置合适速率,用于驱动ST7735S显示屏
  • 启动蓝牙协议栈并开始扫描周边设备
int main(void)
{
// 初始化LVGL和显示
MX_DISPLAY_Init();

// 创建简单UI界面
lv_obj_t *screen = lv_scr_act();
lv_obj_set_style_bg_color(screen, lv_color_black(), 0);

// 温湿度标签(四行显示)
temp_hum_label = lv_label_create(screen);
lv_obj_set_style_text_font(temp_hum_label, &lv_font_unscii_8, 0);
lv_obj_set_style_text_color(temp_hum_label, lv_color_white(), 0);
lv_label_set_text(temp_hum_label, "Temp:\n--\n\nHumi:\n--");
lv_obj_align(temp_hum_label, LV_ALIGN_CENTER, 0, 0);

// 其他初始化...
mainWsfInit();
StackInitDatc();
DatcStart();

WsfOsEnterMainLoop();
}


二、蓝牙数据处理任务

static void datcValueNtf(attEvt_t *pMsg)
{
if (pMsg->handle == pSecDatHdlList[pMsg->hdr.param - 1][SEC_DAT_HDL_IDX]) {
APP_TRACE_INFO0(">> 来自小米温湿度传感器的通知 <<<");

/* 解析小米温湿度传感器数据 */
if (pMsg->valueLen >= 5) {
int16_t temp = (int16_t)(pMsg->pValue[0] | (pMsg->pValue[1] << 8));
uint16_t humidity = pMsg->pValue[2];
uint16_t voltage = (pMsg->pValue[3] | (pMsg->pValue[4] << 8));
float battery = ((float)(voltage - 2000) / (float)(3261 - 2000)) * 100.0f;

if (battery > 100.0f) battery = 100.0f;
if (battery < 0.0f) battery = 0.0f;

APP_TRACE_INFO3("温度: %d.%02d'C, 湿度: %d%%",
temp/100, abs(temp%100), humidity);
APP_TRACE_INFO2("电压: %d mV, 电量: %.2f%%", voltage, (double)battery);

// 更新显示屏标签内容
extern void update_display_values(int16_t temp, uint16_t humidity, uint16_t voltage, float battery);
update_display_values(temp, humidity, voltage, battery);
}
}
}

效果展示

遇到的问题与解决办法

问题:小米温湿度计2的蓝牙连接不稳定,时常断开。

解法:原因是电量不足,更换新电池后问题消失。

活动感想

通过本项目实践,我第一次接触WSF框架,经过学习最终掌握了WSF蓝牙协议栈在嵌入式平台上的应用方法,学习到了蓝牙低功耗在Cortex-M4架构上的连接管理、服务发现机制及数据传输规范。在这一过程中,MAX32655开发板完善的文档支持极大提升了开发效率。活动中还发现本板卡还支持Zephyr系统,接下来准备用它来进一步学习Zephyr,更加丰富我的技能树。

感谢硬禾科技和得捷电子联合举办的Funpack活动,祝硬禾的活动越办越好!

附件下载
MAX32655读取米家温湿度计-源代码.zip
团队介绍
个人
团队成员
枫雪天
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号