用一个按钮实现打开关闭can。
参照qt5.6里can例程写的。点击打开can时没提示,虽然不知道有没有成功打开。关闭时直接提示没有无法关闭没有连接的器件。难道是打开没成功?
void NuvotonCan::toggleDevice(bool open)
83 {
84 if(open)
85 {
86 btnCanPort->setText(tr("关闭"));
87 canDevice = QCanBus::instance()->createDevice(cmbCanPlugin->currentText().toL ocal8Bit(), cmbCanPort->currentText());
88 }
89 else
90 {
91 btnCanPort->setText(tr("打开"));
92 if(!canDevice)
93 return;
94 canDevice->disconnectDevice();
95 delete canDevice;
96 canDevice = nullptr;
97 }
98 }
root@nuc972 /mnt/nfs# ./nuc972can
Can not disconnect an unconnected device
Can not disconnect an unconnected device
Can not disconnect an unconnected device
Can not disconnect an unconnected device
最近编辑记录 Gentlepig (2020-04-17 09:50:41)
离线
if(!canDevice)
{
QMessageBox::information(this, tr("hmmm..."), tr("Error creating device") );
}
调用createDevice()函数后,加了以上部分。
结果点击打开后,没有弹窗提示。
-------------------------------------------
我试了屏蔽掉createDevice()这句,结果点击打开后,有弹窗了。再点击关闭,结果串口终端没那个提示了。
最近编辑记录 Gentlepig (2020-04-17 10:07:57)
离线
QCanDevie除了有disconnectDevice()这个方法外,对应的还有connectDevice()这个方法。
应该在creatDevie()后,调用connectDevice()这个方法。
目前,打开和关闭can,不再报以上那个错误了。
但是,打开can后,连接了QCanDevice的framewritten()信号到一个方法,该方法里用qdeug输出“发送完成”,结果点击发送按钮后没反应...
打开/关闭can接口部分:
111 void NuvotonCan::toggleDevice(bool open)
112 {
113 if(open)
114 {
115 btnCanPort->setText(tr("关闭"));
116 canDevice = QCanBus::instance()->createDevice(cmbCanPlugin->currentText().toLocal8Bit(), cmbCanPort->currentText());
117 if(!canDevice)
118 {
119 QMessageBox::information(this, tr("hmmm..."), tr("Error creating device"));
120 }
121 if(!canDevice->connectDevice())
122 {
123 QMessageBox::information(this, tr("hmmm..."), tr("Error connect device"));
124 }
125 else
126 {
127 connect(canDevice, &QCanBusDevice::errorOccurred, this, &NuvotonCan::recvErr);
128 connect(canDevice, &QCanBusDevice::framesReceived, this, &NuvotonCan::checkMessages);
129 connect(canDevice, &QCanBusDevice::framesWritten, this, &NuvotonCan::framesWritten);
130 btnSend->setEnabled(true);
131 }
132 }
133 else
134 {
135 btnCanPort->setText(tr("打开"));
136 btnSend->setEnabled(false);
137 if(!canDevice)
138 return;
139 canDevice->disconnectDevice();
140 delete canDevice;
141 canDevice = nullptr;
142 }
143 }
发送部分:
175 void NuvotonCan::sendMessage()
176 {
177 if(!canDevice)
178 return;
179
180 QByteArray writings = dataFromHex(txtSend->toPlainText());
181 QCanBusFrame frame;
182 int size = writings.size();
183 writings = writings.left(size);
184 frame.setPayload(writings);
185
186 quint32 id = lntId->displayText().toInt(nullptr, 16);
187 if(ckbExt->checkState() && id > 2047)
188 id = 2047;
189
190 frame.setFrameId(id);
191 frame.setExtendedFrameFormat(ckbExt->checkState());
192
193 if(rdbRemote->isChecked())
194 frame.setFrameType(QCanBusFrame::RemoteRequestFrame);
195 else if(rdbError->isChecked())
196 frame.setFrameType(QCanBusFrame::ErrorFrame);
197 else
198 frame.setFrameType(QCanBusFrame::DataFrame);
199
200 canDevice->writeFrame(frame);
201 qDebug() << "ready to write." << endl;
202 }
-----------------------------------
发现:canDevice->writeFrame(frame);这句返回的是flase。是不是因为没有外接其他can设备的原因?
最近编辑记录 Gentlepig (2020-04-18 11:54:06)
离线
在命令行下执行ifconfig -a,可以看到有can0设备:
root@nuc972 /sys/devices/platform/nuc970-can1/net/can0# ifconfig -a
can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:16 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:10
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:59
。。。
可执行ifconfig can0 up,却失败:
root@nuc972 /# ifconfig can0 up
nuc970-can1 nuc970-can1 can0: bit-timing not yet defined
nuc970-can1 nuc970-can1 can0: failed to open can device
ifconfig: SIOCSIFFLAGS: Invalid argument
设置速度,也失败:
root@nuc972 /# ip link set can0 type can bitrate 125000
ip: either "dev" is duplicate, or "type" is garbage
离线
把bsp里的demo里的can例程,编译后放到板子上运行:
root@nuc972 /mnt/nfs# ./can_demo
nuc970-can1 nuc970-can1 can0: setting BTR=1b09 BRPE=0000
Cannot find device "can1"
Cannot find device "can1"
看样子,例程能运行,can0好像能打开。
那么,我linux命令行里输入的命令不对?
还有,我想qt画个界面打开can接口,不能按qt例程里的来,而是要按nuc972的这个c例程来?
最近编辑记录 Gentlepig (2020-04-18 17:33:19)
离线
root@nuc972 /mnt/nfs# ./can_demo
nuc970-can1 nuc970-can1 can0: setting BTR=1b09 BRPE=0000
Please connect CAN0 and CAN1 to CAN bus
CAN0 transfer id: 256
CAN0 transfer dlc: 8
CAN0 transfer Data:
0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
write error !!
CAN1 receive id = 156892
CAN1 receive dlc = 0
CAN1 receive Data:
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Cannot find device "can
看了下nuvoton的can例程,应该是can0发送can1接收,我把开始的can1初始化关闭了,然后程序可以再往下运行了,虽然后来还是因为接收的问题停止。
这么看,新塘的c例程,是可以运行的,虽然我还没实际测can上有没有信号。
但是我想用qt编界面,如果能直接用QCanDevice这个类就好了。
-------------------------------------------------------------------
运行can_demo例程后,退出,然后在执行ifconfing can0 up,竟然可以打开can0了。
root@nuc972 /mnt/nfs# ifconfig can0 up
nuc970-can1 nuc970-can1 can0: setting BTR=1b09 BRPE=0000
而运行ip命令还是报错。
root@nuc972 /mnt/nfs# ip link set can0 up type can bitrate 125000
ip: either "dev" is duplicate, or "type" is garbage
---------------------------------------------------------------------
https://blog.csdn.net/tiger15605353603/article/details/81296501
搜到这篇文章,busybox制作的ip命令不支持soketcan设置,需要iproute2。我就去buildroot菜单里看,有iproute2这个选项。勾上,重新编译,烧录后执行ifconig can0 up,仍提示没设置速率。然后用ip 命令设置速率,可以打开can0了。
有一点变化,之前我的命令行提示符前显示的当前用户是nuc972,重新编译后,显示的是root。
最近编辑记录 Gentlepig (2020-04-20 12:34:37)
离线
设置速率时,命令行总是提示:
Cannot apply parameter: QCanBusDevice::ConfigurationKey(BitRateKey) with value: QVariant(int, 10000)
这是设置速率的相关语句:
canDevice->setConfigurationParameter(QCanBusDevice::BitRateKey, cmbBitrate->itemData(cmbBitrate->currentIndex()).toInt())
函数原型:
void QCanBusDevice::setConfigurationParameter(int key, const QVariant &value)
我直接交叉编译can例程,放到arm板上运行,尝试用sockecan插件打开can0,会直接有:
No such device。
而我仿照can例程写的程序,则是以上那个错误。
--------------------------------------------
我试着改成这样:
canDevice->setConfigurationParameter(QCanBusDevice::BitRateKey, QVariant::fromValue(cmbBitrate->itemData(cmbBitrate->currentIndex()).toInt()));
结果一样。
这个函数的第二个参数该怎么引入呢?
我这样写:
canDevice->setConfigurationParameter(QCanBusDevice::BitRateKey, "3000");
结果一样:
Cannot apply parameter: QCanBusDevice::ConfigurationKey(BitRateKey) with value: QVariant(QString, "3000")
这样:
canDevice->setConfigurationParameter(4, 3000);
结果:
Cannot apply parameter: QCanBusDevice::ConfigurationKey(BitRateKey) with value: QVariant(int, 3000)
----------------------------------------
查了下ConfigurationKey枚举:
QCanBusDevice::BitRateKey 4 This key defines the bitrate in bits per second.
感觉就应该是Int类型。
最近编辑记录 Gentlepig (2020-04-24 16:41:35)
离线
enum QCanBusDevice::ConfigurationKey
This enum describes the possible configuration options for the CAN bus connection.
Constant Value Description
QCanBusDevice::RawFilterKey 0 This configuration determines the type of CAN bus frames that the current device accepts. The expected value is QList<QCanBusDevice::Filter>. Passing an empty list clears all previously set filters including default filters. For more details see QCanBusDevice::Filter.
QCanBusDevice::ErrorFilterKey 1 This key defines the type of error that should be forwarded via the current connection. The associated value should be of type QCanBusFrame::FrameErrors.
QCanBusDevice::LoopbackKey 2 This key defines whether the CAN bus device should operate in loopback mode. The expected value for this key is bool.
QCanBusDevice::ReceiveOwnKey 3 This key defines whether this CAN device can send messages. The expected value for this key is bool.
QCanBusDevice::BitRateKey 4 This key defines the bitrate in bits per second.
QCanBusDevice::CanFdKey 5 This key defines whether sending and receiving of CAN FD frames should be enabled. The expected value for this key is bool.
QCanBusDevice::UserKey 30 This key defines the range where custom keys start. It's most common purpose is to permit platform-specific configuration options.
以上是QCanBusDevice::ConfigurationKey枚举的详细说明,我试了用setConfigurationParameter()函数配置,其中1,2,3,5都可以配置,4和30配置的话,就会报错。
canDevice->setConfigurationParameter(0, 0);
canDevice->setConfigurationParameter(1, 0);
canDevice->setConfigurationParameter(2, 0);
canDevice->setConfigurationParameter(3, 0);
canDevice->setConfigurationParameter(4, 0);
canDevice->setConfigurationParameter(5, 0);
canDevice->setConfigurationParameter(30, 0);
Cannot apply parameter: QCanBusDevice::ConfigurationKey(BitRateKey) with value: QVariant(int, 0)
Cannot apply parameter: QCanBusDevice::ConfigurationKey(UserKey) with value: QVariant(int, 0)
最近编辑记录 Gentlepig (2020-04-25 09:17:51)
离线
尝试用nuc972官方bsp里的demos里的can例程。
因为该例程是用can0和can1实现自收发,我这里硬件上只有can0,所以屏蔽掉了接收部分。
原程序貌似只发一次,我修改为每隔一秒发一次。
结果,除了第一次发送时不报错,以后的发送都会报错。
int main(int argc, char **argv)
{
struct can_frame frame;
struct can_frame Rx_frame;
struct ifreq ifr;
struct sockaddr_can addr;
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
int dlc = 8;
int s[2], ret, i, rtr = 0, extended = 0;
int j;
int ret1;
can_set_bitrate("can0", 500000);
can_do_start("can0");
// can_set_bitrate("can1", 500000); //any
// can_do_start("can1"); //any
while(1)
{
for(j = 0; j <= 0; j++) //any
{
if(j == 0)
{
strcpy(ifr.ifr_name, "can0");
}
else if(j == 1)
{
strcpy(ifr.ifr_name, "can1");
}
s[j] = socket(family, type, proto);
if (s[j] < 0)
{
printf("ERROR");
return 1;
}
addr.can_family = family;
if (ioctl(s[j], SIOCGIFINDEX, &ifr) < 0)
{
printf("ERROR");
return 1;
}
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s[j], (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
printf("ERROR");
return 1;
}
}
for(i = 0; i < dlc; i++)
{
frame.data[i] = 0x31 + i;
Rx_frame.data[i] = 0;
}
frame.can_id = 0x100;
frame.can_dlc = dlc;
if (extended)
{
frame.can_id &= CAN_EFF_MASK;
frame.can_id |= CAN_EFF_FLAG;
}
else
{
frame.can_id &= CAN_SFF_MASK;
}
if (rtr)
frame.can_id |= CAN_RTR_FLAG;
printf("\n Please connect CAN0 and CAN1 to CAN bus\n");
printf("\n CAN0 transfer id: %d", frame.can_id);
printf("\n CAN0 transfer dlc: %d", frame.can_dlc);
printf("\n CAN0 transfer Data:\n");
for (i = 0; i < frame.can_dlc; i++)
printf(" 0x%02x", frame.data[i]);
printf("\n");
ret1 = 0;
while(ret1 < sizeof(frame))
{
ret = write(s[0], &frame, sizeof(frame));
if (ret == -1)
{
printf("write error !! \n");
}
ret1 += ret;
}
// ret1 = 0;
// while(ret1 < sizeof(Rx_frame))
// {
// ret = read(s[1], &Rx_frame, sizeof(Rx_frame));
// if (ret == -1)
// {
// printf("write error !! \n");
// }
// ret1 += ret;
// }
// printf("\n CAN1 receive id = %d", Rx_frame.can_id);
// printf("\n CAN1 receive dlc = %d", Rx_frame.can_dlc);
// printf("\n CAN1 receive Data:\n");
// for (i = 0; i < frame.can_dlc; i++)
// printf(" 0x%02x", Rx_frame.data[i]);
// printf("\n");
can_do_stop("can0");
// can_do_stop("can1");
sleep(1);
}
return 0;
}
root@h /mnt/nfs# ./can_demo
nuc970-can1 nuc970-can1 can0: setting BTR=1b09 BRPE=0000
Please connect CAN0 and CAN1 to CAN bus
CAN0 transfer id: 256
CAN0 transfer dlc: 8
CAN0 transfer Data:
0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
Please connect CAN0 and CAN1 to CAN bus
CAN0 transfer id: 256
CAN0 transfer dlc: 8
CAN0 transfer Data:
0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
write error !!
Please connect CAN0 and CAN1 to CAN bus
CAN0 transfer id: 256
CAN0 transfer dlc: 8
CAN0 transfer Data:
0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
write error !!
------------------------------
晕了,看到can_do_stop(can0)了。
------------------------------
改了下,把can_do_stop(can0)放到最后一个}前了,运行后,发送了23帧没报错,然后就又“Write error!!”了。
而且,我pc端用can和监控,设的同样的速率,但是没收到。
-------------------------------
晕死了,can芯片的1、4脚是收发管脚,2、3是电源管脚,我搞反了。
最近编辑记录 Gentlepig (2020-04-25 15:50:33)
离线
现在的进展是,运行新塘的can例程,可以正常发送信息,我在win下用usb can盒能接收到正确信息。
可如果启动后直接运行我画的qt界面,打开can0还是报错,点击发送信息,报write faild.
Cannot apply parameter: QCanBusDevice::ConfigurationKey(Bit)
Cannot apply parameter: QCanBusDevice::ConfigurationKey(Use)
write faild.
write faild.
如果先用ip命令设置速率并打开can0,再运行qt程序,虽然打开can0时报错,但点击发送会成功,示波器能观测到信号。
Cannot apply parameter: QCanBusDevice::ConfigurationKey(Bit)
Cannot apply parameter: QCanBusDevice::ConfigurationKey(Use)
Number of frames written: 1
ready to write.
---------------------------
在win下用putty调试,发现并没有返回“Cannot apply parameter: QCanBusDevice::ConfigurationKey(Bit)”这样的语句。虽然点发送还是提示:“write faild.”
暂时总结下,qt下打开can口设置速率失败,如果在运行qt界面前,先用ip命令设置速率并打开can口的话,qt界面可以发送信息。
最近编辑记录 Gentlepig (2020-04-26 16:33:35)
离线
如果说是qt的candevice类不能成功调用系统函数打开can的话,为什么会提示的是:
Cannot apply parameter: QCanBusDevice::ConfigurationKey(BitRateKey) with value: QVariant(int, 500000)
Cannot apply parameter: QCanBusDevice::ConfigurationKey(UserKey) with value: QVariant(QString, "0")
这样的提示,像是我给的参数不对。
离线
canDevice->setConfigurationParameter(0, 0);
canDevice->setConfigurationParameter(1, 0);
canDevice->setConfigurationParameter(2, 0);
canDevice->setConfigurationParameter(3, 0);
canDevice->setConfigurationParameter(4, 0);
canDevice->setConfigurationParameter(5, 0);
canDevice->setConfigurationParameter(30, 0);
这就是我传的参数,4和30报错。
我试过传整数或者传字符串,都报错。
最近编辑记录 Gentlepig (2020-04-28 08:50:15)
离线
// Apply all stored configurations except bitrate and receive own,
// because these cannot be applied after opening the device
请教下这句话是从哪里找到的?
在设置速率之前,我并没有打开canDevice呢,只是创建了。
/*!
Sets the configuration parameter \a key for the CAN bus connection
to \a value. The potential keys are represented by \l ConfigurationKey.
A parameter can be unset by setting an invalid \l QVariant.
Unsetting a parameter implies that the configuration is reset to
its default setting.
\note In most cases, configuration changes only take effect
after a reconnect.
\sa configurationParameter()
*/
void QCanBusDevice::setConfigurationParameter(int key, const QVariant &value)
这是我下载的qserialbus5.6的源码找到的这个函数的定义,并没有特殊的说明。
最近编辑记录 Gentlepig (2020-04-28 14:31:17)
离线
其实是从这里了下载的,选择5.6分支。
https://github.com/qt/qtserialbus/blob/5.6/src/serialbus/qcanbusdevice.cpp
最近编辑记录 Gentlepig (2020-04-28 15:38:03)
离线
这个链接里我也没搜到前边你提到的那句话,能否详细指出是哪个文件哪一行吗?
就是这句话:
// Apply all stored configurations except bitrate and receive own,
// because these cannot be applied after opening the device
最近编辑记录 Gentlepig (2020-04-28 16:42:57)
离线
这个是systeccan插件,我用的是socketcan插件。socketcan插件里的open函数没这个提示。
----------------------------------------------------------------------
看到了这个函数,可能和这里有关。
void SocketCanBackend::resetConfigurations()
{
QCanBusDevice::setConfigurationParameter(
QCanBusDevice::LoopbackKey, true);
QCanBusDevice::setConfigurationParameter(
QCanBusDevice::ReceiveOwnKey, false);
QCanBusDevice::setConfigurationParameter(
QCanBusDevice::ErrorFilterKey,
QVariant::fromValue(QCanBusFrame::FrameErrors(QCanBusFrame::AnyError)));
QCanBusDevice::setConfigurationParameter(
QCanBusDevice::CanFdKey, false);
}
这么说的话,socketcan只能设置参数1、2、3、5.
-----------------------------
不对,这个是resetConfigrations()不是setConfigrations().
------------------------------------------
bool SocketCanBackend::connectSocket()函数中调用了bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &value)函数。如果返回错误,则报错: qWarning() << "Cannot apply parameter:" << QCanBusDevice::ConfigurationKey(key) << "with value:" << param; 我看到的报错由此而来。
而bool SocketCanBackend::applyConfigurationParameter(int key, const QVariant &value)函数中,有switch(key)语句,只是判断了几种情况,没有bitrate选项。
粗略的看了下,直到qt5.14在这个函数里才有了bitrate选项,在里面有libSocketCan->setBitrate(canSocketName, bitRate);
好奇,qt5.14之前的版本,socketcan如何设置速率...
最近编辑记录 Gentlepig (2020-04-28 17:45:02)
离线
如果是例程没有添加这个模块的处理逻辑。 可以添加上去试试。 这是例程不是底层源码, 你可以添加试试
不是例程,就是底层源码,qtserialbus/src/plugins/canbus/socketcan/socketcanbackend.cpp。
如果用QCanBusDevice的socketcan插件不能实现配置速率的话,那么只能在命令行里用ip命令来设置速率了。可是,如何在qt里执行ip命令呢?比如我要执行
ip link set can0 up type can bitrate 500000
在qt程序里该如何实现呢?
---------------------------------------------
目前的方法:
QProcess::execute("ip link set can0 up type can bitrate 500000");
最近编辑记录 Gentlepig (2020-04-30 09:57:13)
离线
调用C语言的库函数 system( ) 就可以了.
system("ip link set can0 up type can bitrate 500000");
刚看到,谢谢。
既然qt有现成的类,我还是用qt的方法吧。
离线
你跑的是这个例程吗: D:\Qt\Qt5.12.3\Examples\Qt-5.12.3\serialbus\can.pro
是参照这个例程写的。因为970官方的buildroot,可选qt5版本只有5.6。所以是参找qt5.6的can例程写的。
离线
https://github.com/lalten/libsocketcan/blob/master/include/libsocketcan.h
https://github.com/lalten/libsocketcan/blob/master/src/libsocketcan.c
也可以用 libsocketcan 里面的接口 获取/设置 bitrate
感谢,其实新塘提供了类似这个的socketcan例程。只是,我想用qt画界面,所以就想当然的用QCanBusDevicele了。如果用参考这个例程的话,这就是c编程了吧,qt和c编程如何混用?比如我点击打开can接口的按钮,那么信号如何绑定到c函数呢?
我现在的水平,就知道绑定到某个对象的某个函数上,可c函数不属于对象了。
离线
建议先解决其他问题,最后再来解决这个问题,反正调用 system 函数肯定没有问题嘛。
修改速率用QProcess()类,调用ip link set 命令,可以实现修改速率。
然后用QCanBusDevice的writeFrame(),可以发送can信息。pc端能监控到正确信息。
然后我用pc端发送信息,结果我的arm板这里没有反应...
离线
很简单的, 槽函数不需要一定是对象的方法:
#include <QApplication> #include <QDebug> #include <QTimer> //C 函数 void someFunction() { qDebug() << "Some function"; } int main(int argc, char* argv[]) { QApplication app(argc, argv); QTimer timer; QWidget widget ; QLineEdit editor; widget.resize(800, 480); //连接 定时器超时信号 与 槽函数someFunction QObject::connect(&timer, &QTimer::timeout, someFunction); timer.start(1000); widget.show(); app.exec(); }
上面的代码是没问题的。
感谢,我试试,这样行的话就可以调用官方例程的函数了。
离线
再请教个问题。
我看nuc972官方提供的can例程里,can读取是死等读取的。像stm32的can读取,是可以用中断的。这样的话,只能定时读取了?
int main(int argc, char **argv)
{
...
ret1 = 0;
while(ret1 < sizeof(Rx_frame))
{
ret = read(s[1], &Rx_frame, sizeof(Rx_frame));
if (ret == -1)
{
printf("write error !! \n");
}
ret1 += ret;
}
...
}
最近编辑记录 Gentlepig (2020-05-06 09:41:19)
离线
open的时候有个参数是 NO_BLOCK,可以试一试。
没找到相关部分。
不过群里有朋友回复,可以创建个线程,线程里不断进行can接收。
离线