Skip to content

本文档提供九章 MCP 验证板各外设的示例代码与接线说明。所有示例基于 emMCP v1.0.1 框架,使用 emMCP_AddToolToToolList 添加工具、emMCP_RegistrationTools 一次性注册后,AI 可通过语音指令直接控制外设或读取传感器数据。

TIP

完整工程源码请参考 emMCP 仓库example/9Mod_MCPBoard/ 目录。


1. 继电器控制

接线

继电器端子说明
NO (常开)默认断开,高电平吸合
COM (公共)外接设备火线
GND / VCC板载已连接,无需额外接线

STM32 控制引脚:PB5(高电平触发)。

MCP 工具注册

c
// 工具回调 - 控制
static void emMCP_SetRelayHandler(void *arg)
{
    cJSON *param = (cJSON *)arg;
    cJSON *enable = cJSON_GetObjectItem(param, "enable");
    if (enable != NULL) {
        if (enable->valueint == 1) {
            HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_SET);
        } else {
            HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_RESET);
        }
        emMCP_ResponseValue(emMCP_CTRL_OK);
    } else {
        emMCP_ResponseValue(emMCP_CTRL_ERROR);
    }
}

// 工具回调 - 查询
static void emMCP_GetRelayHandler(void *arg)
{
    emMCP_ResponseValue(emMCP_CTRL_OK);
}

// 在 main() 中注册
emMCP_tool_t relay;
relay.name = "继电器";
relay.description = "用来控制继电器开关";
relay.inputSchema.properties[0].name = "enable";
relay.inputSchema.properties[0].description = "是否打开继电器,true表示打开,false表示关闭,查询时为null";
relay.inputSchema.properties[0].type = MCP_SERVER_TOOL_TYPE_BOOLEAN;
relay.setRequestHandler = emMCP_SetRelayHandler;
relay.checkRequestHandler = emMCP_GetRelayHandler;
emMCP_AddToolToToolList(&relay);
emMCP_RegistrationTools();

语音指令

「小安,打开继电器」 「小安,关闭继电器」


2. WS2812 灯条控制

接线

WS2812 灯条通过板载 4Pin 接口连接:

WS2812 接口说明
5V电源正极(板载 5V 输出)
GND电源地
DIN数据输入 — PA11
DOUT数据输出(级联下一颗)

支持 RGB 颜色控制和亮度调节。

MCP 工具注册

c
// 工具回调 - 控制
static void emMCP_SetWS2812Handler(void *arg)
{
    cJSON *param = (cJSON *)arg;

    cJSON *red = cJSON_GetObjectItem(param, "red");
    cJSON *green = cJSON_GetObjectItem(param, "green");
    cJSON *blue = cJSON_GetObjectItem(param, "blue");
    cJSON *brightness = cJSON_GetObjectItem(param, "brightness");

    uint8_t r = red ? red->valueint : 0;
    uint8_t g = green ? green->valueint : 0;
    uint8_t b = blue ? blue->valueint : 0;
    uint8_t bri = brightness ? brightness->valueint : 255;

    WS2812_SetColor(r, g, b, bri);
    emMCP_ResponseValue(emMCP_CTRL_OK);
}

// 工具回调 - 查询
static void emMCP_GetWS2812Handler(void *arg)
{
    emMCP_ResponseValue(emMCP_CTRL_OK);
}

// 在 main() 中注册
emMCP_tool_t ws2812;
ws2812.name = "WS2812灯条";
ws2812.description = "用来控制WS2812灯条的颜色和亮度";
ws2812.inputSchema.properties[0].name = "red";
ws2812.inputSchema.properties[0].description = "红色值,范围0-255,查询时为null";
ws2812.inputSchema.properties[0].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
ws2812.inputSchema.properties[1].name = "green";
ws2812.inputSchema.properties[1].description = "绿色值,范围0-255,查询时为null";
ws2812.inputSchema.properties[1].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
ws2812.inputSchema.properties[2].name = "blue";
ws2812.inputSchema.properties[2].description = "蓝色值,范围0-255,查询时为null";
ws2812.inputSchema.properties[2].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
ws2812.inputSchema.properties[3].name = "brightness";
ws2812.inputSchema.properties[3].description = "亮度值,范围0-255,查询时为null";
ws2812.inputSchema.properties[3].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
ws2812.setRequestHandler = emMCP_SetWS2812Handler;
ws2812.checkRequestHandler = emMCP_GetWS2812Handler;
emMCP_AddToolToToolList(&ws2812);
emMCP_RegistrationTools();

语音指令

「小安,把灯条调成红色」 「小安,灯条亮度调到 50%」 「小安,关闭灯条」


3. SHT30 温湿度读取

接线

SHT30 温湿度传感器与 PD 诱骗共享 GPIO 位操作模拟的 I²C 总线(PB6(SDA) / PB7(SCL)),通过设备地址区分:

设备I²C 地址
SHT30 温湿度0x44
CH224K PD 诱骗0x48

OLED 使用 SPI 接口(独立片选),板载 GT20L61S 中文字库芯片。

MCP 工具注册

c
// 工具回调 - 控制(温湿度为只读传感器,无需控制逻辑)
static void emMCP_SetSHT30Handler(void *arg)
{
    emMCP_ResponseValue(emMCP_CTRL_ERROR);
}

// 工具回调 - 查询
static void emMCP_GetSHT30Handler(void *arg)
{
    float temp = 0, humi = 0;
    SHT30_ReadData(&temp, &humi);

    cJSON *result = cJSON_CreateObject();
    cJSON_AddNumberToObject(result, "temperature", temp);
    cJSON_AddNumberToObject(result, "humidity", humi);
    cJSON_AddStringToObject(result, "unit_temp", "°C");
    cJSON_AddStringToObject(result, "unit_humi", "%");
    char *json_str = cJSON_PrintUnformatted(result);
    emMCP_ResponseValue(json_str);
    cJSON_Delete(result);
    cJSON_free(json_str);
}

// 在 main() 中注册
emMCP_tool_t sht30;
sht30.name = "温湿度传感器";
sht30.description = "用来获取环境温度和湿度数据";
sht30.inputSchema.properties[0].name = "temperature";
sht30.inputSchema.properties[0].description = "当前温度值,单位°C,控制时为null";
sht30.inputSchema.properties[0].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
sht30.inputSchema.properties[1].name = "humidity";
sht30.inputSchema.properties[1].description = "当前湿度值,单位%,控制时为null";
sht30.inputSchema.properties[1].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
sht30.setRequestHandler = emMCP_SetSHT30Handler;
sht30.checkRequestHandler = emMCP_GetSHT30Handler;
emMCP_AddToolToToolList(&sht30);
emMCP_RegistrationTools();

语音指令

「小安,查一下现在的温湿度」 「小安,当前温度是多少?」



4. PD 诱骗供电控制

接线

PD 诱骗使用 CH224K 芯片,通过 I²C 配置输出电压档位。使用 Type-C 接口连接 PD 充电器。

⚠️ 高压警告: PD 诱骗输出最高 20V/3A (60W)。接线前请确认外接负载的额定电压,切勿短路。请勿在通电状态下插拔高压负载端。初次使用建议从 5V 开始测试。

PD 诱骗STM32 引脚
SDAPB6
SCLPB7
I²C 地址0x48

MCP 工具注册

c
// 工具回调 - 控制
static void emMCP_SetPDHandler(void *arg)
{
    cJSON *param = (cJSON *)arg;
    cJSON *voltage = cJSON_GetObjectItem(param, "voltage");

    if (voltage) {
        CH224K_SetVoltage(voltage->valueint);
        emMCP_ResponseValue(emMCP_CTRL_OK);
    } else {
        emMCP_ResponseValue(emMCP_CTRL_ERROR);
    }
}

// 工具回调 - 查询
static void emMCP_GetPDHandler(void *arg)
{
    emMCP_ResponseValue(emMCP_CTRL_OK);
}

// 在 main() 中注册
emMCP_tool_t pd;
pd.name = "PD诱骗供电";
pd.description = "用来设置PD诱骗输出电压";
pd.inputSchema.properties[0].name = "voltage";
pd.inputSchema.properties[0].description = "目标电压,可选: 5/9/12/15/20,查询时为null";
pd.inputSchema.properties[0].type = MCP_SERVER_TOOL_TYPE_NUMBLE;
pd.setRequestHandler = emMCP_SetPDHandler;
pd.checkRequestHandler = emMCP_GetPDHandler;
emMCP_AddToolToToolList(&pd);
emMCP_RegistrationTools();

语音指令

「小安,设置 PD 输出 12V」 「小安,PD 升压到 20V」


5. OLED 显示控制

接线

0.96 寸 OLED(SSD1306,128×64)使用 SPI1 接口,板载 GT20L61S 中文字库芯片:

OLED 引脚STM32 引脚说明
OLED_DCPA1数据/命令选择
OLED_CS1PA4OLED 片选
CS2PB0GT20L61S 字库片选
SCLKPA5 (SPI1_SCK)SPI 时钟
MISOPA6 (SPI1_MISO)SPI 数据输入(字库读)
MOSIPA7 (SPI1_MOSI)SPI 数据输出

MCP 工具注册

c
// 工具回调 - 控制
static void emMCP_SetOLEDHandler(void *arg)
{
    cJSON *param = (cJSON *)arg;
    cJSON *text = cJSON_GetObjectItem(param, "text");

    if (text) {
        OLED_Clear();
        OLED_ShowString(0, 0, text->valuestring);
        OLED_Refresh();
        emMCP_ResponseValue(emMCP_CTRL_OK);
    } else {
        emMCP_ResponseValue(emMCP_CTRL_ERROR);
    }
}

// 工具回调 - 查询
static void emMCP_GetOLEDHandler(void *arg)
{
    emMCP_ResponseValue(emMCP_CTRL_OK);
}

// 在 main() 中注册
emMCP_tool_t oled;
oled.name = "OLED屏幕";
oled.description = "用来在OLED屏幕上显示文字";
oled.inputSchema.properties[0].name = "text";
oled.inputSchema.properties[0].description = "要显示的文字内容,查询时为null";
oled.inputSchema.properties[0].type = MCP_SERVER_TOOL_TYPE_STRING;
oled.setRequestHandler = emMCP_SetOLEDHandler;
oled.checkRequestHandler = emMCP_GetOLEDHandler;
emMCP_AddToolToToolList(&oled);
emMCP_RegistrationTools();

语音指令

「小安,OLED 显示「你好」」 「小安,在屏幕上显示当前温度」


6. 综合示例:注册所有外设

c
void RegisterAllTools(void)
{
    // LED
    emMCP_AddToolToToolList(&led);
    // 继电器
    emMCP_AddToolToToolList(&relay);
    // WS2812 灯条
    emMCP_AddToolToToolList(&ws2812);
    // 温湿度
    emMCP_AddToolToToolList(&sht30);
    // PD 诱骗
    emMCP_AddToolToToolList(&pd);
    // OLED 显示
    emMCP_AddToolToToolList(&oled);

    // 一次性注册所有工具到小安AI
    emMCP_RegistrationTools();
}

将所有工具注册后,只需调用一次 emMCP_RegistrationTools() 即可向 AI 平台同步所有工具定义。

验证方法

  1. 编译检查:确保工程编译无报错
  2. 串口日志:烧录后连接调试串口(USART1, 1500000),对模组说"你好小安",应看到 [DEBUG] emMCP_EventCallback: event:8 等日志输出
  3. 工具同步:串口日志中出现 tool_list 发送成功即表示工具已注册到 AI 平台
  4. 功能测试:对小安说出示例对应的语音指令,观察外设响应

更多资料

Released under the MIT License.