最近在开发集成蓝牙模块的MCU,选来选去选择了CH592。之前用的是MCU+蓝牙透传芯片来做。
RISC-V内核BLE5.4 MCU/SoC CH592 - 南京沁恒微电子股份有限公司
WCHISPTool_Setup.exe - 南京沁恒微电子股份有限公司
官方链接下面有资料下载。
买了一块CH592EVT,下载好资料和安装集成开发环境(MounRiver Studio),下载工具WCHISPTool。
一、功能需求:
- GPIO点灯
- GPIO按键
- 蓝牙通讯
二、GPIO部分:
三、蓝牙部分:
首先先看评估板说明说了解,资料包结构。PUB里面是资料,EXAM里面是源码。
打开:CH592EVT\EVT\PUB\CH592评估版说明书.pdf和CH592SCH.pdf
这里开发蓝牙使用的例程是:CH592EVT\EVT\EXAM\BLE\Central
3.1下载程序
说一下程序下载这部分,开始我是用MounRiver Studio编译和下载的,但是一直下不进去,后来看手册说用下载工具WCHISPTool下载。
我选择用USB下载方式下载,拿一个type-c转USB连接开发板和电脑。

3.2调试信息(串口)
type-c并不带串口的,需要自己准备一个USB TO TTL串口,PA8接TXD,PA9接RXD。
3.3修改程序
首先我需要根据从机蓝牙名称连接从机。
参考链接:蓝牙BLE主机Central讲解一(建立连接) - SweetTea_lllpc - 博客园
CH573 CH582 CH579蓝牙主机(Central)例程讲解一(主机工作流程) - WCH蓝牙应用分享 - 博客园
3.3.1 根据设备名称连接
了解上边这两个之后,改了根据设备名称连接
cpp
static uint8_t* PeerDeviceName = "BSJ-FLIP-03"; //输入待连接的从机名称
在函数centralEventCB中
case GAP_DEVICE_INFO_EVENT:
{
// Add device to list
if((pbuf = strstr(pEvent->deviceInfo.pEvtData, PeerDeviceName)) != 0)//对比扫描到的名称
{
PRINT("pbuf = %s\n", pbuf);
centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
}
// centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
}
break;
然后根据调试信息,观察主机工作流程。
3.3.2 发现根本没有服务的打印信息
在函数centralStartDiscovery里面
cpp
uint8_t uuid[ATT_BT_UUID_SIZE] = {LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)};
在gattprofile.h中宏定义
// Simple Profile Service UUID
#define SIMPLEPROFILE_SERV_UUID 0xFFE0
我的从机根本没有UUID为0xFFE0的服务。
我用手机BLE调试助手连了一下从机设备:

我在FFF1服务的上箭头,发送数据,从机可以接收到。那么就想办法让主机给FFF1的从机服务发送数据应该就行。
所以我改了:
cpp
#define UNKNOWN_SERV_UUID 0xFFF0
#define UNKNOWN_SERV_RW_UUID 0xFFF1
uint8_t uuid[ATT_BT_UUID_SIZE] = {LO_UINT16(UNKNOWN_SERV_UUID),
HI_UINT16(UNKNOWN_SERV_UUID)};
这回有服务信息了。
输出了"Write success"的信息,但是从机没有收到数据。
然后我怀疑是服务没有获取正确。CH592EVT蓝牙Central例程没有开启枚举服务 - 沁恒微电子社区
3.3.3 枚举从机所有服务
官方给了枚举从机所有服务的链接:
CH5xx 主机枚举从机所有服务 - WCH蓝牙应用分享 - 博客园

问了一下DeepSeek,不知道什么是服务、特征、描述符。
BLE的通用属性协议(GATT)的核心数据层次结构:设备 -> 服务 -> 特征 -> **描述符。**这是一个从大到小、层层包含的关系。
蓝牙BLE主机Central讲解三(服务枚举) - SweetTea_lllpc - 博客园
将central.c中两个函数全部替换。能够发送数据。
3.3.4 单字节写改为多字节写
在Central_ProcessEvent函数中if(events & START_READ_OR_WRITE_EVT),if(centralDoWrite)
里面
cpp
原:
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralCharHdl;
req.len = 1;
req.pValue = GATT_bm_alloc(centralConnHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
*req.pValue = centralCharVal;
if(GATT_WriteCharValue(centralConnHandle, &req, centralTaskId) == SUCCESS)
{
centralProcedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
tmos_start_task(centralTaskId, START_READ_OR_WRITE_EVT,DEFAULT_READ_OR_WRITE_DELAY);
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
改为:
attPrepareWriteReq_t req;
req.handle = centralCharHdl;
req.offset = 0; // 必须设置偏移量(从0开始)
req.len = sizeof(ModbusSeq); // 数组长度
req.pValue = ModbusSeq; // 指向整个数组
if(req.pValue != NULL)
{
*req.pValue = ModbusSeq[0];
if(GATT_WriteLongCharValue(centralConnHandle, &req, centralTaskId) == SUCCESS)
{
centralProcedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
tmos_start_task(centralTaskId, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
}
}

