PCAN(PeakCAN)二次开发时,如何区分多个设备
正版
没用过,但是应该估计直接设置设备ID即可
盗版
前言
本文仅针对使用 https://github.com/moonglow/pcan_cantact 项目下固件的设备
本文由于缺少关键步骤截图,因此并非手把手教学
使用的设备如图


现象
尽管通过PCANBasic API中的SetValue和GetValue方法设置ID。
但是这种ID无法保存,每次重新上电后,读到的ID仍然为默认值255。
思路
重新编译固件,在固件中修改ID默认值,以此来区分。
修改位置
注意这里有坑 固件返回的ID并非为 Src/pcan_protocol.c文件中的device_id,而是莫名其妙的返回了Src/usbd_desc.c中 bcdDevice的低位字节
static struct
{
uint8_t bus_active;
uint8_t ext_vcc_state;
uint8_t led_mode;
uint16_t last_timestamp_sync;
uint16_t last_flush;
struct
{
/* error handling related */
uint8_t err;
uint8_t ecc;
uint8_t rx_err;
uint8_t tx_err;
/* config */
uint8_t btr0;
uint8_t btr1;
uint8_t silient;
uint8_t loopback;
uint8_t err_mask;
uint32_t quartz_freq;
}
can;
uint8_t sja1000_shadow[6];
uint8_t sja1000_ic_mode;
uint8_t device_id;
uint32_t device_serial;
}
pcan_device =
{
.device_id = 0xFF, // 根本就tm不是这个
.device_serial = 0xFFFFFFFF,
.can =
{
.quartz_freq = PCAN_USB_CRYSTAL_HZ,
.loopback = 0,
},
};
修改方法
在Src/usbd_desc.c中
- 修改 bcdDevice 中的后两位,改成啥,调用GetDeviceID就读到啥。
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
0x12, /*bLength */
USB_DESC_TYPE_DEVICE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x00,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
LOBYTE(USBD_VID), /*idVendor*/
HIBYTE(USBD_VID), /*idVendor*/
LOBYTE(USBD_PID_FS), /*idProduct*/
HIBYTE(USBD_PID_FS), /*idProduct*/
0x01, /*bcdDevice*/ // 修改此处可以改变上位机GetDeviceID的结果
0x54,
10, /*Index of manufacturer string*/
4, /*Index of product string*/
0, /*Index of serial number string*/
USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/
};
此外,作为bcdDevice字段,上图的0x5401可以在usb设备的硬件Id里获取到。类似下图中的REV_xxxx。

2. (可选)然后修改cfg_descriptor,这是总线已报告设备描述。这样在枚举USB设备的时候对用户比较友好
uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
__ALIGN_BEGIN static const uint16_t cfg_descriptor[1+8] __ALIGN_END =
{
0x0312,
'P','C','A','N','-','0','0','1' // 本来是 XCAN-USB,这里随便改改
};
*length = sizeof( cfg_descriptor );
return (uint8_t*)cfg_descriptor;
}
在usb设备的总线已报告设备描述里可以获取到。通过同时获取硬件id和总线已报告设备描述,我们便可以建立起两者的关系。

WSL编译
由于项目中cmake相关的命令使用shell脚本,这里选择在WSL环境中编译。需要安装 build-essential, arm-none-eabi-gcc
然后在项目目录下执行 make cantact_8 或者 make canable 或者别的 取决于你的设备。
对于上图设备,使用cantact_8固件
下载程序
可以使用stm32cubeProgrammer配合JLink
(需要先解除读保护)这不是本文重点,略
上位机调用方法
C#伪代码表示
var 目标id = 0x01; // 范围0-255
// 遍历所有handle(具体参考API手册)
foreach(var handle in usbHandles){
// 需要先初始化才能成功获取ID
pcanApi.init(handle);
// 判断ID是否为目标ID
if(pcanApi.getID(handle) == 目标id){
// 成功逻辑
}
// 释放掉不要的设备
pcanApi.uninit(handle);
}
// 失败逻辑
浙公网安备 33010602011771号