本文是一篇实战教程,旨在引导你通过自定义 MCP(Model Context Protocol)工具,结合语音指令控制硬件设备。我们将以 CSK6 大模型开发套件 为例,展示如何通过语音触发串口通信,最终实现控灯。
你将学习到如何配置 MCP 工具、编写串口控制逻辑,并实现语音到硬件的无缝控制。
实操之前,请确保已根据文档《环境搭建》 和《获取大模型套件SDK》搭建开发环境。
如果您不想重新编译代码而希望直接体验本固件,可点击下载进行烧录:
mcp_tool_led_control_3.1.6.bin
下载后直接覆盖 SDK 的 apps/LLM_pic 文件夹
下载后,可以通过命令
git apply .\mcp_tool_led_control_3.1.6.diff应用更改
SDK根目录(duomotai_ap)\.sdk\csk\boards\arm\csk6_duomotai_devkit\csk6_duomotai_devkit.dts是本开发板的设备树文件,在该文件中定义了这个版型的硬件设备节点信息,在aliases节点中我们可以看到 RGB LED 的节点信息,我们以控制 RGB LED 显示绿色为例,节点名称为 led_rgb_green。
aliases {
sw0 = &user_button_0;
csk6-exmcu = &csk6_ch32v003;
led-rgb-red = &led_rgb_red;
led-rgb-green = &led_rgb_green;
led-rgb-blue = &led_rgb_blue;
lcd-pwm-ctl = &lcd_pwm_ctl;
camera-ir-led = &camera_ir_led;
led0 = &led_rgb_green;
};

新增文件:LLM_pic\src\app_led.c,然后增加对 led 的控制为例:
#include <errno.h>
#include <string.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app_led, LOG_LEVEL_INF);
// 将 LED_G_NODE 定义为绿色 rgb led 设备节点
#define LED_G_NODE DT_ALIAS(led_rgb_green)
// 通过设备节点创建一个 GPIO 控制结构 led_g
static const struct gpio_dt_spec led_g = GPIO_DT_SPEC_GET(LED_G_NODE, gpios);
static bool led_inited;
void app_led_init(void)
{
led_inited = false;
if (!gpio_is_ready_dt(&led_g)) {
LOG_ERR("LED GPIO not ready");
return;
}
if (gpio_pin_configure_dt(&led_g, GPIO_OUTPUT_ACTIVE) < 0) {
LOG_ERR("LED config failed");
return;
}
led_inited = true;
}
int app_led_control(const char *command)
{
int ret = 0;
if (!command) {
return -EINVAL;
}
if (!led_inited) {
app_led_init();
if (!led_inited) {
return -ENODEV;
}
}
if (!strcmp(command, "1")) { // 打开 LED
ret = gpio_pin_set_dt(&led_g, 1);
} else if (!strcmp(command, "0")) { // 关闭 LED
ret = gpio_pin_set_dt(&led_g, 0);
} else {
return -EINVAL;
}
if (ret < 0) {
LOG_ERR("LED control failed, command=%s ret=%d", command, ret);
}
return ret;
}
RGB LED 以及 GPIO 接口的使用方法可以文档《(外部扩展)GPIO》或 SDK 中的示例
{SDK}\.sdk\csk\samples\driver\exmcu_gpio_led。
新增文件:LLM_pic\src\app_led.h,然后暴露对 led 的控制函数:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void app_led_init(void);
int app_led_control(const char *command);
#ifdef __cplusplus
}
#endif
修改文件duomotai_ap/apps/LLM_pic/CMakeLists.txt 增加语句:src/app_led.c

修改文件duomotai_ap/apps/LLM_pic/main.c 增加语句:
extern void app_led_init(void);
app_led_init();
在 duomotai_ap/apps/LLM_pic/app_mcp/tools 文件夹下添加文件 led_control.c
修改 aduomotai_ap/apps/LLM_pic/app_mcp/CMakeLists.txt 添加语句${CMAKE_CURRENT_SOURCE_DIR}/tools/led_control.c

duomotai_ap/apps/LLM_pic/app_mcp/tools/led_control.c 文件下添加代码:#include "app_mcp.h"
#include "app_led.h"
#include <string.h>
#include <zephyr/logging/log.h>
#include "cjson/cJSON.h"
LOG_MODULE_REGISTER(led_control, LOG_LEVEL_INF);
static mcp_result_t build_text_response(mcp_response_t *response, const char *text, mcp_result_t result)
{
if (!response) {
return MCP_RESULT_INVALID_PARAM;
}
cJSON *content_array = cJSON_CreateArray();
if (!content_array) {
response->result = MCP_RESULT_ERROR;
return MCP_RESULT_ERROR;
}
cJSON *text_item = cJSON_CreateObject();
if (!text_item) {
cJSON_Delete(content_array);
response->result = MCP_RESULT_ERROR;
return MCP_RESULT_ERROR;
}
cJSON_AddStringToObject(text_item, "type", "text");
cJSON_AddStringToObject(text_item, "text", text ? text : "");
cJSON_AddItemToArray(content_array, text_item);
response->content = content_array;
response->result = result;
return result;
}
static mcp_result_t led_control_handler(const mcp_context_t *ctx, mcp_response_t *response)
{
if (!ctx || !response) {
return MCP_RESULT_INVALID_PARAM;
}
const char *command = NULL;
for (uint32_t i = 0; i < ctx->param_count; i++) {
if (strcmp(ctx->params[i].name, "command") == 0 && cJSON_IsString(ctx->params[i].value)) {
command = ctx->params[i].value->valuestring;
break;
}
}
if (!command) {
return build_text_response(response, "错误:缺少必需参数 command", MCP_RESULT_INVALID_PARAM);
}
int ret = app_led_control(command);
if (ret < 0) {
return build_text_response(response, "错误:LED控制失败,command仅支持\"1\"或\"0\"", MCP_RESULT_INVALID_PARAM);
}
return build_text_response(response, "已完成操作", MCP_RESULT_SUCCESS);
}
cJSON *generate_led_control_schema(void)
{
cJSON *root = cJSON_CreateObject();
if (!root) {
return NULL;
}
if (!cJSON_AddStringToObject(root, "type", "object")) {
cJSON_Delete(root);
return NULL;
}
cJSON *properties = cJSON_CreateObject();
if (!properties) {
cJSON_Delete(root);
return NULL;
}
cJSON *command_prop = cJSON_CreateObject();
if (!command_prop) {
cJSON_Delete(properties);
cJSON_Delete(root);
return NULL;
}
cJSON *command_enum = cJSON_CreateArray();
if (!command_enum) {
cJSON_Delete(command_prop);
cJSON_Delete(properties);
cJSON_Delete(root);
return NULL;
}
cJSON_AddItemToArray(command_enum, cJSON_CreateString("1"));
cJSON_AddItemToArray(command_enum, cJSON_CreateString("0"));
if (!cJSON_AddStringToObject(command_prop, "type", "string") ||
!cJSON_AddStringToObject(command_prop, "description", "LED控制命令:\"1\"开灯,\"0\"关灯")) {
cJSON_Delete(command_enum);
cJSON_Delete(command_prop);
cJSON_Delete(properties);
cJSON_Delete(root);
return NULL;
}
cJSON_AddItemToObject(command_prop, "enum", command_enum);
cJSON_AddItemToObject(properties, "command", command_prop);
cJSON_AddItemToObject(root, "properties", properties);
cJSON *required = cJSON_CreateArray();
if (!required) {
cJSON_Delete(root);
return NULL;
}
cJSON_AddItemToArray(required, cJSON_CreateString("command"));
cJSON_AddItemToObject(root, "required", required);
return root;
}
MCP_REGISTER_TOOL_STATIC(led_control,
"led_control",
"控制LED开关,command=\"1\"开灯,command=\"0\"关灯",
"1.0",
generate_led_control_schema,
1,
led_control_handler,
false,
NULL);
执行以下指令进行代码编译(以 Windows CMD 终端为例):
lisa zep build -b csk6_duomotai_devkit apps/LLM_pic -p
使用 Type-C 数据线连接开发套件的 DAP_USB接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击
图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。

若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn 指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0。