Skip to main content

编写一个 CAN 总线设备

本例程演示如何利用 librm 中的 CAN 总线设备框架实现一个通过 CAN 总线接收数据的设备。

librm 对 CAN 总线和设备的封装使用观察者模式,如果不熟悉这种设计模式,建议先自行了解一下。

CAN 设备向 CAN 总线类"注册"自己,并且告知自己要接收哪些 ID 的报文; 基于具体平台实现,CAN 总线类会用轮询或接管中断的方式接收所有报文,每接收到一条报文,它就会寻找有没有注册过想要接收这条报文的设备, 如果有,这个设备的 RxCallback()函数就会被 CAN 总线类调用。

整个过程分为以下几个步骤:

  1. 继承rm::device::CanDevice

  2. 在构造函数的初始化列表中代理构造,向 CAN 总线类表明自己要注册到这一条 CAN 总线上、说明自己要接收哪些 ID 的报文

  3. 实现private void RxCallback(const hal::CanMsg *msg)成员函数,在这个回调函数中编写收到报文时的处理逻辑

下面是一段在 Linux 平台下的例程代码,例程实现了一个最基本的 CAN 设备,它接收can0总线上的0x123标准帧 ID 的报文,并且把报文的内容打印到屏幕上。

代码

#include "librm.hpp"

#include <iostream>

using rm::device::CanDevice;
using rm::hal::Can;

class BasicCanDevice : public CanDevice {
public:
BasicCanDevice(rm::hal::CanInterface &can, uint32_t rx_std_id)
: CanDevice{can, rx_std_id} {}

private:
void RxCallback(const rm::hal::CanMsg *msg) override {
// 在这里处理接收到的报文
std::printf("Received a message! stdid=%d, dlc=%d\n", msg->rx_std_id,
msg->dlc);
for (int i = 0; i < msg->dlc; i++) {
std::printf("%02X ", msg->data[i]);
}
std::printf("\n");
}
};

int main() {
Can can0{"can0"};
BasicCanDevice device{can0, 0x123}; // 我想要接收can0上的0x123标准帧ID的报文!

can0.Begin();

while (true) {
}

return 0;
}