一、主要任务:读取txt的CAN帧数据内容并提取ID和DATA
txt内容如下:
0 接收 0x0068ff75 0x00000110 数据帧 标准帧 0x08 00 00 00 00 00 00 00 00
1 接收 0x0068ff7a 0x00000115 数据帧 标准帧 0x08 03 34 03 35 03 36 03 37
2 接收 0x0068ff7f 0x00000110 数据帧 标准帧 0x08 00 00 00 00 00 00 00 00
3 接收 0x0068ff84 0x0000012b 数据帧 标准帧 0x08 0c 08 0c 09 0c 0a 0b ef
4 接收 0x0068ff88 0x00000115 数据帧 标准帧 0x08 02 ba 02 bb 02 bc 02 bd
5 接收 0x0068ff8d 0x00000169 数据帧 标准帧 0x08 0b fb 0b fc 0b fd 0b fe
6 接收 0x0068ff92 0x00000116 数据帧 标准帧 0x08 02 ba 02 bb 02 bc 02 bd
二、前期打印效果预览
如图:
三、实现步骤
1、建立浏览文件UI,用来查找浏览CAN记录文本。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->setWindowTitle("文件浏览");
this->setMaximumSize(600,600);
this->setMinimumSize(600,300);
filename = new QLineEdit(this);
filename->setGeometry(QRect(50,50,230,25));
button = new QPushButton(this);
button->setGeometry(QRect(280,50,80,25));
button->setText("浏览");
connect(button,SIGNAL(clicked()),this,SLOT(showFiles()));
}
void MainWindow:: showFiles()
{
QString str = QFileDialog::getOpenFileName(this,"open file","/","text\
file(*.txt);;C file(*.cpp);;All file(*.*)");
filename->setText(str.toUtf8());
loadFile(str);
}
/**
*功能:加载文档并转换成数据流
*/
void MainWindow::loadFile(QString filename)
{
QFile file(filename);
if(file.open(QIODevice::ReadOnly|QIODevice::Text))
{
QTextStream textStream(&file);
while(!textStream.atEnd())
{
buf = textStream.readLine();
ParseData(buf);//解析数据函数
}
}
}
2、ParseData()函数,解析如下类型的数据,提取如类型的数据的id和data数据段
1 接收 0x0068ff7a 0x00000115 数据帧 标准帧 0x08 03 34 03 35 03 36 03 37
SIMPLEFRAMES MainWindow::ParseData(QString buf)
{
QByteArray ByteBuf,ByteBuf1;
int t,j,index;
uint8_t RevData[8]={0};
ByteBuf=NULL,ByteBuf1=NULL;
uint8_t temp;
uint32_t id_text;
t = 0,index=0,j=0,id_text=0;
if(buf.size()>2)
{
ByteBuf = buf.toLatin1();//转换为字节数组
qDebug()<<"size="<<ByteBuf.size();
//截取CAN帧的data数据字符串
for (int i=ByteBuf.size()-1;i>=ByteBuf.size()-24;i--)
{
t = ((uint32_t)ByteBuf[i]);
//qDebug()<<"data0="<<t;
//转移到另一个缓存
if((t>=48&&t<=57)||(t>=65&&t<=70)||(t>=97&&t<=102))
{
//qDebug()<<"data1="<<t;
ByteBuf1[j++]=ByteBuf[i];
}
}
temp = 0;
//ascii至数值类型转换
for (int i=0;i<j;i++)
{
t = ((uint32_t)ByteBuf1[i]);
//ascii码值转换到0~9数值
if((t>=48)&&(t<=57)){
t=t-48;
}else if((t>=65)&&(t<=70)){
//A~F
t=10+t-65;
}else if((t>=97)&&(t<=102)){
//a~f
t=10+t-97;
}
//高低4位组合成u8数据
if(i%2==0){
temp=(uint8_t)t;
}else{
temp+=(uint8_t)t<<4;
//整理顺序
RevData[7-(index++)]=temp;
}
}
//预览
for (int i = 0;i<8;i++)
{
qDebug()<<"Data["<<i<<"]"<<QString::number(RevData[i],16);
}
temp=0;
index=0;
j=0;
t=0;
id_text=0;
//id的数据的处理,方法同上
for (int i=ByteBuf.size()-48;i>=ByteBuf.size()-55;i--)
{
ByteBuf1[j++]=ByteBuf[i];
}
id_text=0;
for (int i=0;i<j;i++)
{
t = ((uint32_t)ByteBuf1[i]);
if((t>=48)&&(t<=57)){
t=t-48;
}else if((t>=65)&&(t<=70)){
t=10+t-65;
}else if((t>=97)&&(t<=102)){
t=10+t-97;
}
//qDebug()<<"@"<<t;
id_text+= t<<(4*i);
}
//id数据预览
qDebug()<<"CAN_ID:"<<QString::number(id_text,16);
//can数据打包,方便调用
can_frame.ID = id_text;
for (int i=0;i<8;i++) {
can_frame.data.byte[i] = RevData[i];
}
}
return can_frame;
//返回can数据值
}
四、拓展增加定时器触发读取
1、缓存数据到QList<QString>类型的列表中并增加定时器
mytimer = new QTimer(this);
if(file.open(QIODevice::ReadOnly|QIODevice::Text))
{
QTextStream textStream(&file);
while(!textStream.atEnd())
{
buf = textStream.readLine();
//ParseData(buf);
if(buf.length()>1)
{
//数据存入到字符串列表中
stringList.append(buf);
}
}
//删除第一行列首
stringList.removeFirst();
}
//启动定时器
if(!mytimer->isActive())
{
qDebug()<<"stringList.len="<<stringList.length();
//连接定时器信号和槽函数
connect(mytimer,SIGNAL(timeout()),this,SLOT(print()));
mytimer->start(1000);
}
2、槽函数的编写
void MainWindow::print()
{
//qDebug()<<"ceshi=";
if(cnt>=stringList.length())
{
//发送到列表结尾,从头开始读取
cnt = 0;
}
//qDebug()<<"ceshi="<<stringList[cnt++];
frame = ParseData(stringList[cnt++]);
qDebug()<<"id:"<<QString::number(frame.ID,16);
qDebug()<<"data:"<<QString::number(frame.data.byte[0],16)\
<<QString::number(frame.data.byte[1],16)\
<<QString::number(frame.data.byte[2],16)\
<<QString::number(frame.data.byte[3],16)\
<<QString::number(frame.data.byte[4],16)\
<<QString::number(frame.data.byte[5],16)\
<<QString::number(frame.data.byte[6],16)\
<<QString::number(frame.data.byte[7],16);
}
3、打印模拟的效果
结束语:通过移植以上的函数,可以通过更改txt的can数据和代码中的定时器间隔时间,可以模拟硬件电路板上发的数据,从而脱离硬件环境进行关于CAN的应用软件的开发。作者水平有限,仅供备忘吧~ ~