Skip to main content

编写一个 CAN 总线设备

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

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

CAN 设备向 CAN 总线类"注册"自己,并且告知自己要接收哪些 ID 的报文; CAN 总线类会处理对接硬件 API 接收报文的逻辑,每接收到一条报文,它就会寻找有没有注册过想要接收这条报文的设备,如果有,这个设备的 RxCallback() 函数就会被 CAN 总线类调用。

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

  1. 继承rm::device::CanDevice

  2. 委托构造CanDevice,向 CAN 总线类表明自己要注册到这一条 CAN 总线上、列出自己要接收哪些 ID 的报文

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

warning

Linux 下,RxCallback()函数会在一个单独的线程中被调用,因此请注意线程安全问题。

代码

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

#include <iostream>

#include <librm.hpp>

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

private:
void RxCallback(const rm::hal::CanFrame *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() {
rm::hal::Can can0{"can0"};
BasicCanDevice device{can0, 0x123}; // 我想要接收can0上的0x123标准帧ID的报文!

can0.Begin();

while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}

return 0;
}