API 编程接口
Alius USB2CAN 双路调试器提供开源的 CANAL API DLL,方便开发者通过编程方式控制设备。本文档详细介绍了 API 的使用方法、函数说明和代码示例,帮助您快速集成 Alius USB2CAN 调试器到您的应用程序中。
CANAL API 概述
CANAL(CAN Abstraction Layer)是一个开源的 CAN 总线抽象层 API,提供了一套统一的接口函数来访问各种 CAN 接口设备。Alius USB2CAN 调试器完全支持 CANAL API,使得开发者可以编写与硬件无关的应用程序。
API 特点
- 跨平台:支持 Windows 和 Linux 操作系统
- 多语言支持:支持 C/C++、C#、Python、Java、LabVIEW 等多种编程语言
- 开源:源代码开放,可根据需要进行修改和定制
- 易于使用:提供简洁、直观的 API 函数
安装与配置
Windows 环境
- 将 CANAL API DLL(通常为
canal.dll)复制到您的应用程序目录或系统目录(如C:\Windows\System32) - 在您的项目中添加 CANAL API 头文件(
canal.h) - 配置项目链接到 CANAL API 库
Linux 环境
- 安装 CANAL API 共享库(通常为
libcanal.so) - 在您的项目中包含 CANAL API 头文件
- 编译时链接 CANAL API 库(使用
-lcanal选项)
API 函数说明
1. 打开连接
long CanalOpen(char *pDevice, unsigned long flags);
功能:打开与 CAN 设备的连接
参数:
pDevice:设备名称或路径(例如,COM 端口号)flags:打开标志(通常设置为 0)
返回值:
- 成功:返回设备句柄(> 0)
- 失败:返回 0
示例:
long hDevice = CanalOpen("COM3", 0);
if (0 == hDevice) {
printf("无法打开设备\n");
return -1;
}
2. 关闭连接
int CanalClose(long handle);
功能:关闭与 CAN 设备的连接
参数:
handle:设备句柄(由CanalOpen返回)
返回值:
- 成功:返回 1
- 失败:返回 0
示例:
if (0 == CanalClose(hDevice)) {
printf("关闭设备失败\n");
}
3. 获取设备状态
int CanalGetStatus(long handle, canalsystemstatus *pStatus);
功能:获取设备的当前状态
参数:
handle:设备句柄pStatus:指向canalsystemstatus结构的指针
返回值:
- 成功:返回 1
- 失败:返回 0
4. 获取统计信息
int CanalGetStatistics(long handle, canalstatistics *pStatistics);
功能:获取设备的通信统计信息
参数:
handle:设备句柄pStatistics:指向canalstatistics结构的指针
返回值:
- 成功:返回 1
- 失败:返回 0
5. 发送 CAN 报文
int CanalSend(long handle, canalmsg *pCanMsg);
功能:发送一个 CAN 报文
参数:
handle:设备句柄pCanMsg:指向canalmsg结构的指针
返回值:
- 成功:返回 1
- 失败:返回 0
示例:
canalmsg canMsg;
memset(&canMsg, 0, sizeof(canalmsg));
canMsg.id = 0x100; // CAN 报文 ID
canMsg.flags = 0; // 标准帧,无 RTR
canMsg.sizeData = 8; // 数据长度
canMsg.data[0] = 0x01; // 数据字节 0
canMsg.data[1] = 0x02; // 数据字节 1
// ... 设置其他数据字节
if (0 == CanalSend(hDevice, &canMsg)) {
printf("发送报文失败\n");
}
6. 接收 CAN 报文
int CanalReceive(long handle, canalmsg *pCanMsg);
功能:接收一个 CAN 报文
参数:
handle:设备句柄pCanMsg:指向canalmsg结构的指针
返回值:
- 成功:返回 1
- 失败:返回 0
- 无报文:返回 0(需要检查
pCanMsg->sizeData)
示例:
canalmsg canMsg;
memset(&canMsg, 0, sizeof(canalmsg));
if (CanalReceive(hDevice, &canMsg)) {
printf("收到报文:ID=0x%X, DLC=%d\n", canMsg.id, canMsg.sizeData);
for (int i = 0; i < canMsg.sizeData; i++) {
printf("%02X ", canMsg.data[i]);
}
printf("\n");
} else {
printf("接收报文失败或无报文\n");
}
7. 设置过滤器
int CanalSetFilter(long handle, unsigned long filter);
功能:设置硬件验收过滤器
参数:
handle:设备句柄filter:过滤器值
返回值:
- 成功:返回 1
- 失败:返回 0
8. 设置屏蔽
int CanalSetMask(long handle, unsigned long mask);
功能:设置验收屏蔽
参数:
handle:设备句柄mask:屏蔽值
返回值:
- 成功:返回 1
- 失败:返回 0
数据结构
canalmsg 结构
typedef struct {
unsigned long id; // CAN 报文 ID
unsigned char flags; // 标志位
unsigned char sizeData; // 数据长度(0-8)
unsigned char data[8]; // 数据字节
unsigned long timestamp; // 时间戳(ms)
} canalmsg;
标志位定义:
0x00:标准帧(11 位 ID)0x01:扩展帧(29 位 ID)0x02:远程帧(RTR)
canalsystemstatus 结构
typedef struct {
unsigned long channel_status; // 通道状态
unsigned long lasterrorcode; // 最后一个错误代码
unsigned long lasterrorsource;// 最后一个错误源
unsigned long errorcounter; // 错误计数器
} canalsystemstatus;
canalstatistics 结构
typedef struct {
unsigned long cntReceiveFrames; // 接收帧计数
unsigned long cntTransmitFrames; // 发送帧计数
unsigned long cntReceiveData; // 接收数据字节计数
unsigned long cntTransmitData; // 发送数据字节计数
unsigned long cntOverruns; // 溢出计数
unsigned long cntBusWarnings; // 总线警告计数
unsigned long cntBusOff; // 总线关闭计数
} canalstatistics;
代码示例
C++ 示例
#include <stdio.h>
#include "canal.h"
int main() {
// 打开设备
long hDevice = CanalOpen("COM3", 0);
if (0 == hDevice) {
printf("无法打开设备\n");
return -1;
}
printf("设备打开成功,句柄:%ld\n", hDevice);
// 发送报文
canalmsg txMsg;
memset(&txMsg, 0, sizeof(canalmsg));
txMsg.id = 0x100;
txMsg.sizeData = 8;
for (int i = 0; i < 8; i++) {
txMsg.data[i] = i;
}
if (CanalSend(hDevice, &txMsg)) {
printf("报文发送成功\n");
} else {
printf("报文发送失败\n");
}
// 接收报文(等待 1 秒)
canalmsg rxMsg;
memset(&rxMsg, 0, sizeof(canalmsg));
for (int i = 0; i < 100; i++) {
if (CanalReceive(hDevice, &rxMsg)) {
printf("收到报文:ID=0x%X, DLC=%d, 数据:", rxMsg.id, rxMsg.sizeData);
for (int j = 0; j < rxMsg.sizeData; j++) {
printf("%02X ", rxMsg.data[j]);
}
printf("\n");
}
Sleep(10); // 等待 10 ms
}
// 关闭设备
CanalClose(hDevice);
return 0;
}
Python 示例
import ctypes
import time
# 加载 CANAL DLL
canal = ctypes.CDLL("canal.dll")
# 定义数据结构
class CanalMsg(ctypes.Structure):
_fields_ = [
("id", ctypes.c_ulong),
("flags", ctypes.c_ubyte),
("sizeData", ctypes.c_ubyte),
("data", ctypes.c_ubyte * 8),
("timestamp", ctypes.c_ulong)
]
# 打开设备
hDevice = canal.CanalOpen("COM3", 0)
if 0 == hDevice:
print("无法打开设备")
exit(-1)
print(f"设备打开成功,句柄:{hDevice}")
# 发送报文
txMsg = CanalMsg()
txMsg.id = 0x100
txMsg.sizeData = 8
for i in range(8):
txMsg.data[i] = i
if canal.CanalSend(hDevice, ctypes.byref(txMsg)):
print("报文发送成功")
else:
print("报文发送失败")
# 接收报文
rxMsg = CanalMsg()
for i in range(100):
if canal.CanalReceive(hDevice, ctypes.byref(rxMsg)):
print(f"收到报文:ID=0x{rxMsg.id:X}, DLC={rxMsg.sizeData}, 数据:", end="")
for j in range(rxMsg.sizeData):
print(f"{rxMsg.data[j]:02X} ", end="")
print()
time.sleep(0.01)
# 关闭设备
canal.CanalClose(hDevice)
高级功能
1. 多通道操作
Alius USB2CAN 调试器支持两个独立的 CAN 通道。您可以通过打开多个设备句柄来同时操作两个通道。
2. 错误处理
在使用过程中,可能会遇到各种错误,如总线关闭、接收溢出等。建议您定期检查设备状态,并根据错误类型采取相应的措施。
3. 性能优化
- 使用硬件过滤器减少不必要的数据接收
- 使用较大的接收缓冲区
- 在单独的线程中处理接收的数据
常见问题
问题 1:无法加载 CANAL DLL
解决方法:确保 DLL 文件位于正确的路径,并检查 DLL 的依赖项是否满足。
问题 2:发送报文失败
解决方法:检查设备是否已打开、CAN 总线是否连接正确、波特率是否匹配。
问题 3:接收报文丢失
解决方法:增加接收缓冲区大小、及时处理接收到的报文、降低波特率。
技术支持
如果您在使用过程中遇到任何问题,请联系 Alius 技术支持团队。我们将竭诚为您服务。