CH347应用:基于开源libmodbus及CH343PT库实现远程GPIO控制
CH347介绍
CH347作为一款USB转接芯片,之前的博客中实现了他的SPI、JTAG、I2C的功能。
本次介绍其GPIO功能,我们可以使用沁官方的CH343PT库对WCH的U串系列进行GPIO控制,同时该库还有很多实用功能,例如对WCH的U串芯片的配置数据进行改写,串口热插拔检测等。
CH343PT库下载链接:https://www.wch.cn/downloads/CH343SER_ZIP.html
使用介绍可参考:https://blog.csdn.net/WCH_TechGroup/article/details/127514913
开源项目libmodbus
一个易用的Modbus开源库,目前Github 3.5K star,支持Modbus RTU、Modbus TCP与Modbus ascii。纯C编写,支持多平台。
项目地址:https://github.com/stephane/libmodbus
实现流程
利用modbus RTU的读写保持线圈功能(功能码:0x01)去控制CH347的GPIO电平。
借助CH347转双串口的功能,将一个串口作为modbus rtu协议的slave端,另一串口使用CH343PT库去控制GPIO。
master端每隔五秒读取slave端的两个保持线圈并将他们翻转,再写入。
slave端则读取GPIO电平并每五秒回复一次GPIO的状态。
代码如下:
#include "modbus.h"
#include <iostream>
#include <Windows.h>
#include <stdio.h>
#include <string>
#include "CH343PT.H"
using namespace std;
struct ModbusInfo
{
modbus_t* mb;
modbus_mapping_t* mbMap;
};
struct ModbusInfo MBInfo;
HANDLE hCom; //串口句柄
UCHAR ChipType;
ChipPropertyS ChipPro = { 0 };
//打开串口
BOOL OpenCom(string comname)
{
std::string strComName;
strComName += "\\\\.\\";
strComName += comname;
BOOL Retval;
hCom = CreateFile(strComName.c_str(), GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
NULL,
NULL);
if (hCom == INVALID_HANDLE_VALUE)
{
return FALSE;
}
ChipType = CH343PT_GetChipProperty(hCom, &ChipPro); //获取串口芯片信息
Retval = (ChipType != 0xFF);
if (!Retval)
{
printf("芯片信息获取失败!");
CloseHandle(hCom);
hCom = INVALID_HANDLE_VALUE;
return FALSE;
}
return TRUE;
}
BOOL OpenModbus(string comname)
{
string com = string("\\\\.\\") + comname;
MBInfo.mb = modbus_new_rtu(com.c_str(), 115200, 'N', 8, 1);
if (MBInfo.mb == NULL) {
modbus_free(MBInfo.mb);
printf("new rtu failed: %s\n", modbus_strerror(errno));
return FALSE;
}
//gpio:3~7
MBInfo.mbMap = modbus_mapping_new_start_address(0, 2, 0, 0, 0, 0, 0, 0);
if (MBInfo.mbMap == NULL)
{
modbus_free(MBInfo.mb);
printf("new mapping failed: %s\n", modbus_strerror(errno));
return FALSE;
}
modbus_set_slave(MBInfo.mb, 1);
if (modbus_connect(MBInfo.mb) == -1) {
printf("modbus_connect err.");
return FALSE;
}
return TRUE;
}
int main(int argc, char* argv[])
{
ULONG gpioEnable = ULONG_MAX;
ULONG gpioStatus = 0;
uint8_t query[50];
if (argc < 3) {
printf("Missing necessary input parameters\n");
return -1;
}
if (!OpenModbus(argv[1])) {
printf("打开ModBus失败!");
return -1;
}
if (!OpenCom(argv[2])) {
printf("打开串口失败!");
return -1;
}
CH910x_GpioGet(hCom, &ChipPro, &gpioStatus);
for (size_t i = 0; i < 2; i++) {
MBInfo.mbMap->tab_bits[i] = (gpioStatus >> i) & 0x01 ? 1 : 0;
}
int ret = 0;
std::cout << "Modbus slave running!\n";
Sleep(100);
while (1) {
do {
ret = modbus_receive(MBInfo.mb, query); //轮询串口数据,
} while (ret == 0);
if (ret > 0) {
printf("receive data\n");
modbus_reply(MBInfo.mb, query, ret, MBInfo.mbMap);
} else {
printf("modbus_receive err.\n");
break;
}
for (size_t i = 0; i < 2; i++) {
if (MBInfo.mbMap->tab_bits[i]) {
gpioStatus |= (0x01 << i);
} else {
gpioStatus &= ((ULONG_MAX - 1) << i);
}
}
printf("gpioStatus = %x\n", gpioStatus);
CH910x_GpioSet(hCom, &ChipPro, gpioEnable, gpioStatus);
}
modbus_close(MBInfo.mb);
modbus_free(MBInfo.mb);
}
试验结果
这里的COM16是与CH347串口相连的CH9102。
通过逻辑分析仪可看到CH347的两个GPIO口每隔五秒发生了一次翻转:
引伸
1、如需进行更多的GPIO控制,可使用CH348(USB2.0转8串口)或CH348+CH334(USB2.0 4端口USB Hub)实现。
2、实现modbus RTU与modbus TCP网关,实现功能更加完善的远程GPIO控制。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)