Linux+QT+SocketCAN:使用信号槽机制实现数据收发

本文介绍了如何在Linux+QT环境下利用SocketCAN库,通过信号槽机制实现CAN数据的收发。在Ubuntu16.04上,使用QT 5.13.1,创建一个单独的线程处理CAN消息的接收,同时通过对象间的信号槽连接,简化Motor对象与CAN对象的数据交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux+QT+SocketCAN:使用信号槽机制实现数据收发

最近在考虑采用面对对象的方式重新搭建机器人的主控程序框架,虽然之前的框架也是有这种思想在里面,但是总感觉还是有程序化编程的影子,很多地方的处理都不太理想,而且虽然之前也是一直在采用QT Creator作为IDE开发程序,但是实际上并没有怎么用QT的库,只是单纯的作为一个IDE来用,未免也是空守宝山而不入。
因此这次决定充分利用QT的库和信号槽机制来对程序框架进行重新构建。

0.开发环境

  1. HOST平台: Ubuntu16.04
  2. ARM平台:at91sam9x35
  3. QT版本: 5.13.1

1.分析

针对Linux上的CAN通信,Socket CAN提供了一种十分简单方便的解决方案,QT中并没有像QTcpSocket一样的库可以使用,因此仍然使用linux内核中提供的库。
考虑到电机等设备会循环向主控返回电机的状态信息,CAN的接收工作十分耗时,因此选择新建一个继承QObject的类,将其Moveto一个QThread中单独执行循环接收工作。
考虑到CAN和Motor对象均为Robot类的对象成员,而各个Motor对象需要调用CAN的发送接口向其他对象发送数据,为避免各对象成员之间的数据交互造成各种麻烦,因此在各对象成员中建立signal与slot,在Robot中进行connect。
eg:
Robot具有两个对象成员CAN和Motor

class Robot:public QObject
{
   
	Q_OBJECT
public:
	Robot();
	~Robot();
	...
	CAN *mCAN;
	Motor *Wheel_1;
	...
}

CAN中构建数据发送槽

class CAN:public QObject
{
   
	Q_OBJECT
	...
public slots:
    void Transmit(can_frame pFrame);
    ...
}

Motor中构建数据发送信号

class Motor:public QObject
{
   
	Q_OBJECT
	...
signals:
	void sendCanMeg(can_frame pFrame);
	...
}

Robot中将其连接

Robot::Robot()
{
   
	...
	mCAN = new CAN("can1");
	Wheel_1= new Motor(WHEEL_1,SPEED_MODE)
	connect(Wheel_1,&Motor::sendCanMeg,mCAN ,&CAN::Transmit);
	...
}

2.源码

2.1 can.h

#ifndef CAN_H
#define CAN_H
#include <QObject>
#include <QThread>
#include <QtCore>
#include <fcntl.h>        /*文件控制定义*/
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <Utilities.h>
#include <QDebug>
#include <unistd.h>
// CAN接收线程
class CAN_RcvThread :public QObject
{
   
    Q_OBJECT
public:
    CAN_RcvThread(QObject *parent = 0) ;
public slots:
    void RcvMegThread(int s);
    void stopRcvThread();
private:
    bool isStop=
Linux下面QTCan通信程序,网络上有很多例子都是互相抄的;本人因为项目原因,通过源代码Socket函数,写了完整的程序,含有2个案例;分享给大家; 这里主要是包含几个步骤,1:绑定Socket;2:cna/can1的设置,3:波特率的设置(如果发送和接收波特率不一致肯定不行的);4:发送;5:接收处理; 下面就贴出部分代码: void MyWindow::startcan(int number) { int ret = 0; //can先关闭 设置好波特率后 再开启can if(number == 0) //can0 { system("ifconfig can0 down");//先关闭 system("ip link set can0 up type can bitrate 50000 triple-sampling on");//设置波特率 system("ifconfig can0 up");//再开启 } else //can1 { system("ifconfig can1 down");//先关闭 system("ip link set can1 up type can bitrate 50000 triple-sampling on");//设置波特率 system("ifconfig can1 up");//再开启 } socket = ::socket(PF_CAN,SOCK_RAW,CAN_RAW); struct ifreq ifr; strcpy((char *)(ifr.ifr_name),number == 0 ? "can0" : "can1"); ioctl(socket,SIOCGIFINDEX,&ifr); addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; ret = bind(socket,(struct sockaddr*)&addr,sizeof(addr)); if (ret OpenCan(50000); ArmCan = new Thread(zyhapi,socket,port); ArmCan->start(); } void MyWindow::stopcan(int number) { if(ArmCan) { ArmCan->stop(); ArmCan->terminate(); ArmCan->wait(); } zyhapi->CloseCan(number); } //发送 void MyWindow::on_sendbtn_clicked() { /* struct can_frame frame; memset(&frame,0,sizeof(struct can_frame)); std::string str=ui->edit->text().toStdString(); if(str.length() > 8) { QMessageBox::about(this,"error","length of send string must less than 8 bytes"); return; } */ struct can_frame frame; memset(&frame,0,sizeof(struct can_frame)); char buf[8]={0X20,0XFF,0X01,0X02,0X03,0X04,0XFF,0XFF}; frame.can_id = 0x00000020;//发出去的帧ID即:0X00000020 frame.can_dlc = 8;//帧数据长度 for(int i=0;i<frame.can_dlc;i++) { frame.data[i]=buf[i];//帧数据 } //frame.can_id = 0x123; //strcpy((char*)frame.data,str.c_str()); //frame.can_dlc = str.length(); sendto(socket,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr,sizeof(addr)); /* struct can_frame frame; char buf[8]={0X20,0XFF,0X01,0X02,0X03,0X04,0XFF,0XFF}; frame.can_id = 0x00000020;//发出去的帧ID即:0X00000020 frame.can_dlc = 8;//帧数据长度 for(int i=0;iWriteCan(frame.can_id,frame.data,frame.can_dlc);//发数据,通过can端口-- 暂时默认 CAN0 端口 */ }
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值