• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

卢晓春的博客

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

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中

  1. 修改 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);
}
// 失败逻辑

posted on 2025-03-19 20:01  卢晓春  阅读(286)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3