当前位置: 首页 > news >正文

QT编程之CAN协议

一、CAN协议解析

1、定义与核心特性

CAN(Controller Area Network)是一种‌多主控制‌的串行通信协议,采用双绞线(CAN_H/CAN_L)传输差分信号,具有高可靠性和抗干扰能力‌24。其核心特性包括:

  • 多主控制‌:所有节点可主动发起通信,总线空闲时优先发送高优先级数据‌。
  • 实时性强‌:支持1Mbps高速传输(ISO11898标准),适用于工业控制、汽车电子等场景‌。
  • 错误处理机制‌:包含CRC校验、位填充、错误帧自动重传等机制,错误检出率>99%‌。
2、物理层结构
  1. 总线拓扑
    • 闭环结构‌:两端接120Ω终端电阻,支持高速通信(1Mbps),最大传输距离40m‌。
    • 开环结构‌:单端接2.2kΩ电阻,用于低速长距离传输(<125kbps)‌。
  2. 电平标准
    通过差分电压判定逻辑状态:
    • 高速CAN:显性电平(0)= 2V压差,隐性电平(1)= 0V压差‌。
    • 低速CAN:显性电平=3V压差,隐性电平=-1.5V压差‌。
3、协议层与帧结构
  1. 帧类型

    帧类型功能描述关键字段
    数据帧传输有效数据帧ID(11/29位)、数据段(0-8字节)、CRC校验‌
    远程帧请求数据发送无数据段,RTR标志位显性‌
    错误帧错误状态通知6位显性错误标志‌
    过载帧延迟数据传输帧间隔超时触发‌
  2. 仲裁机制

    • 基于‌报文ID优先级‌的非破坏性仲裁:ID值越小优先级越高,仲裁失败节点自动退出发送‌。
    • 采用‌CSMA/CD+AMP‌:载波侦听多路访问/冲突检测与仲裁机制‌。
4、典型应用场景
  1. 汽车电子‌:ECU(发动机控制单元)、仪表盘、ADAS系统等车载设备通信‌。
  2. 工业控制‌:PLC、传感器网络、机器人协同控制‌。
  3. 医疗设备‌:医疗仪器数据同步与状态监控‌。

二、QT中使用CAN协议

1、QT中CAN通讯模块

在Qt中实现CAN(Controller Area Network)通信通常涉及到使用Qt的QtSerialBus模块,特别是其中的QCanBus类。这个模块允许你与CAN总线进行交互,无论是通过PCAN硬件接口还是其他支持的CAN接口。

类名功能描述
QCanBus提供CAN设备插件管理,支持socketcan(Linux)/peakcan(Windows)等驱动‌
QCanBusFrame封装CAN帧数据,包含ID、Payload、时间戳等属性‌
QCanSignalDescription实验性API,用于解析CAN信号物理值(如温度、转速)‌
QCanBusDeviceInfo提供设备信息查询(接口名、通道状态等)‌
2、Qt项目文件(.pro) 
QT += core serialbus
LIBS += -lsocketcan  # Linux专用‌
3、开发流程 

1、初始化CAN总线设备‌
使用QCanBus类加载设备插件并创建连接对象:

QCanBusDevice *device = QCanBus::instance()->createDevice(
    "socketcan",  // 使用Linux SocketCAN插件‌
    "vcan0");     // 虚拟CAN接口名

 ‌2、设备配置与连接‌
设置通信参数并建立连接:

device->setConfigurationParameter(QCanBusDevice::BitRateKey, 500000); // 500kbps‌
if (!device->connectDevice()) {
    qDebug() << "连接失败:" << device->errorString(); // 错误处理‌
}

3、‌数据收发操作‌

  • 发送CAN帧
    QCanBusFrame frame;
    frame.setFrameId(0x123);
    QByteArray payload = QByteArray::fromHex("11223344");
    frame.setPayload(payload);
    device->writeFrame(frame);  // 异步写入‌
  • 接收数据
    通过信号槽机制处理接收:
    connect(device, &QCanBusDevice::framesReceived, ‌:ml-search[] {
        while (device->framesAvailable()) {
            const QCanBusFrame frame = device->readFrame();
            qDebug() << "ID:" << frame.frameId() 
                     << "数据:" << frame.payload().toHex();
        }
    });
4、清理资源

不要忘记在应用程序结束时断开并删除设备。

device->disconnectDevice(); // 断开设备连接
delete device; // 删除设备对象
5、高级功能

‌1)信号解码
使用实验性API将原始数据转换为工程值:

QCanSignalDescription signalDesc;
signalDesc.setDataEndian(QSysInfo::LittleEndian);
signalDesc.setStartBit(16);  // 信号起始位
signalDesc.setBitLength(12); // 信号长度(bit)

const double value = signalDesc.decode(frame.payload());

2‌)多设备管理
枚举系统可用CAN接口:

const QList<QCanBusDeviceInfo> devices = QCanBus::instance()->availableDevices("socketcan");
foreach (const auto &info, devices) {
    qDebug() << "接口:" << info.name() 
             << "描述:" << info.description();
}

三、完整CAN通信代码示例,支持Linux SocketCAN接口(如vcan0/can0)

#include <QCoreApplication>
#include <QCanBus>
#include <QCanBusFrame>
#include <QDebug>

class CanBusManager : public QObject {
    Q_OBJECT
public:
    explicit CanBusManager(QObject *parent = nullptr) : QObject(parent), m_canDevice(nullptr) {
        // 初始化CAN接口(需root权限)
        system("sudo ip link set can0 type can bitrate 500000 restart-ms 100");
        system("sudo ifconfig can0 up");

        // 创建CAN设备实例‌:ml-citation{ref="2,5" data="citationList"}
        m_canDevice = QCanBus::instance()->createDevice("socketcan", "can0");
        if (!m_canDevice) {
            qFatal("设备创建失败,请检查驱动或接口名");
        }

        // 连接设备‌:ml-citation{ref="5,7" data="citationList"}
        if (!m_canDevice->connectDevice()) {
            qCritical() << "连接失败:" << m_canDevice->errorString();
            return;
        }

        // 绑定数据接收信号‌:ml-citation{ref="2,5" data="citationList"}
        connect(m_canDevice, &QCanBusDevice::framesReceived, this, &CanBusManager::readFrames);
    }

    ~CanBusManager() {
        if (m_canDevice && m_canDevice->state() == QCanBusDevice::ConnectedState) {
            m_canDevice->disconnectDevice();
            system("sudo ifconfig can0 down"); // 关闭接口‌:ml-citation{ref="1,7" data="citationList"}
        }
    }

public slots:
    // 发送CAN帧‌:ml-citation{ref="2,4" data="citationList"}
    void sendFrame(uint frameId, const QByteArray &data) {
        QCanBusFrame frame;
        frame.setFrameId(frameId);
        frame.setPayload(data);

        if (m_canDevice->writeFrame(frame)) {
            qDebug() << "发送成功:" << QString::number(frameId, 16);
        } else {
            qWarning() << "发送失败:" << m_canDevice->errorString();
        }
    }

private slots:
    // 接收数据解析‌:ml-citation{ref="5,8" data="citationList"}
    void readFrames() {
        while (m_canDevice->framesAvailable()) {
            const QCanBusFrame frame = m_canDevice->readFrame();
            qDebug() << "接收帧ID: 0x" + QString::number(frame.frameId(), 16)
                     << "数据:" << frame.payload().toHex();
        }
    }

private:
    QCanBusDevice *m_canDevice;
};

// 主函数测试
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    CanBusManager can;
    QTimer::singleShot(1000, ‌:ml-search[&can] {
        can.sendFrame(0x123, QByteArray::fromHex("11223344")); // 发送测试数据
    });

    return a.exec();
}

#include "main.moc"

关键配置说明

   1‌)Qt项目文件(.pro)

QT += core serialbus
LIBS += -lsocketcan  # Linux专用

‌    2)设备权限配置‌

  • 创建/etc/udev/rules.d/99-can.rules
    KERNEL=="can*", GROUP="plugdev", MODE="0660"  # 避免使用sudo‌

    3)‌接口初始化命令

sudo modprobe can_raw  # 加载内核模块
sudo ip link set can0 type can bitrate 500000  # 设置比特率‌

四、注意事项 

‌1)平台差异‌

  • Linux推荐使用SocketCAN子系统,需提前加载vcan模块:
    sudo modprobe vcan && sudo ip link add dev vcan0 type vcan‌
    

‌2)错误处理‌
监听errorOccurred信号实现异常捕获: 

connect(device, &QCanBusDevice::errorOccurred, [](QCanBusDevice::CanBusError error) {
    qDebug() << "CAN错误码:" << error; 

3)错误处理增强

connect(m_canDevice, &QCanBusDevice::errorOccurred, [](QCanBusDevice::CanBusError error) {
    qDebug() << "错误类型:" << error;  // 监听错误信号‌
});

4)多线程优化

QCanBusDevice::setConfigurationParameter(QCanBusDevice::ReceiveOwnMessages, true);  // 禁止接收自身发送的帧‌

5)CAN FD支持

frame.setFlexibleDataRateFormat(true);  // 启用FD模式‌

6)验证工具

使用candump工具可验证通信数据‌。Windows平台需更换插件为peakcanvectorcan‌。

相关文章:

  • DeepSeek与GPT的全方位对比及其为编程工作带来的巨大变革
  • 熊猫精灵脚本助手官网_找图找色-脚本精灵2025最新版下载
  • 深入解析 Java 类加载机制及双亲委派模型
  • 【MARK-2小车】小车教程、上位机教程
  • 高等数学-第七版-上册 选做记录 习题5-4
  • 表的约束及代码练习
  • django入门教程之templates和static资源【五】
  • 八纲辨证总则
  • 如何优化 docker 镜像体积?
  • 【深度学习基础 2】 PyTorch 框架
  • EMQX Dashboard
  • Java 大视界 -- Java 大数据在智能金融区块链跨境支付与结算中的应用(154)
  • C#多态性入门:从零到游戏开发实战
  • Unity URP自定义Shader支持RenderLayer
  • 【Unity3D实现UI轮播效果】
  • 无人机+evtol:低空经济市场硬通货技术详解
  • HCIP(二)
  • 六十天Linux从0到项目搭建(第八天)(缓冲区、gitee提交)
  • 让 AI 更智能的检索增强生成(Retrieval-Augmented Generation)
  • 组态软件之万维组态介绍(web组态、html组态、vue2/vue3组态、组态软件、组态编辑器)
  • AG600“鲲龙”批生产首架机完成生产试飞
  • 玛丽亚·凯莉虹口连唱两夜,舞台绽放唤醒三代人青春记忆
  • 解锁儿时愿望!潘展乐战胜孙杨,全国冠军赛男子400自夺冠
  • 高途一季度净利润同比增长1108%: “与吴彦祖一起学英语”短时间内就实现了盈利
  • 中国首艘海洋级智能科考船“同济”号试航成功,可搭载水下遥控机器人
  • 阿里上财年营收增6%,蒋凡:会积极投资,把更多淘宝用户转变成即时零售用户