工控论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 12|回复: 0

CAN Bootloader协议介绍与C++源码

[复制链接]

425

主题

430

帖子

262

积分

初级会员

Rank: 2

工控币
262
发表于 2020-4-30 00:07:54 | 显示全部楼层 |阅读模式
CAN Bootloader命令列表
命令名称    命令值(Hex)    说明
GET_ADDR(1)    000    向主机请求本机地址
ERASE(2)    XX1    擦除应用程序
WRITE(3)    XX2    将程序写入Flash
READ(4)    XX3    将程序从Flash中读出
GO(5)    XX4    执行应用程序
SET_WRITE_ADDR    XX5    设置写数据起始地址
WRITE_CONTINUOUS    XX6    连续写数据,写数据地址自动递增
SET_READ_ADDR    XX7    设置读数据起始地址
READ_CONTINUOUS    XX8    连续读数据,读数据起始地址递增
GET_VERSION    XX9    获取Bootloader固件版本
ADDR_OK    XXC    请求地址可用
ADDR_ERROR    XXD    请求地址不可用
CMD_OK    XXE    命令执行成功
CMD_ERROR    XXF    命令执行失败
1、本机地址为7bit,所以在CAN总线上最多只能连接128个节点,本命令由从机发出,主机会给从机分配一个临时地址并回复CMD_OK,如果主机地址使用完毕则回复CMD_ERROR,从机可以根据接收到的主机反馈判断本机地址设置是否成功;
2、擦除应用程序命令会带擦除起始地址和擦除结束地址;
3、写数据命令带4字节写数据地址参数和4字节的数据;
4、读数据命令会携带4字节地址,从机返回4字节数据;
5、执行应用程序;

命令详解
GET_ADDR:
该命令由从机发送给主机,主机接收到该命令后会分配一个地址给从机,如果主机无法分配地址则发送ADDR_ERROR回复从机,此时从机应进入无法获取地址的错误处理程序中。主机和从机在发送命令的时候必须携带8字节物理地址,也就是说DLC为8。从机如果正确获取到地址后可以设置过滤器为只接收和自己地址匹配的数据,这样可以减少CPU的负担。
ERASE:
擦除应用程序储存地址区域的数据,该命令由主机发送给从机,命令携带8字节数据,前4字节数据为擦出起始地址,后4字节为擦出结束地址,从机接收到该命令后可回复CMD_OK或CMD_ERROR给主机。
WRITE:
将一个字(4Byte)的数据写入指定的Flash地址,该命令由主机发送给从机,命令携带8字节数据,前4字节为数据写入地址,后4字节为准备写入的数据。
READ:
从指定的Flash地址读取4字节的数据,该命令由主机发送给从机或者从机发送给主机,主机发送给从机的时候携带4字节地址参数,从机发送给主机的时候携带4字节的数据。
GO:
执行应用程序,该命令由主机发送给从机,命令携带4字节的地址参数,从机接收到该命令后从指定的地址开始执行程序。
SET_WRITE_ADDR:
设置连续写数据的起始地址,该命令由主机发送给从机,命令携带4字节的地址参数。
WRITE_CONTINUOUS:
连续写数据到Flash中,该命令由主机发送给从机,从机根据SET_WRITE_ADDR命令设置的起始地址将程序数据写入Flash中,该命令携带最多8字节的程序数据。
SET_READ_ADDR:
设置连续读数据起始地址,该命令由主机发送给从机,命令携带4字节的地址参数。
READ_CONTINUOUS:
连续读数据,该命令由主机发送给从机或者由从机发送给主机,由主机发送给从机时DLC为0,从机接收到这个命令后将该命令携带最多8字节数据返回给主机。
GET_VERSION:
获取Bootloader固件版本号,版本号由两字节组成,第一字节为主版本号,第二字节为从版本号。
ADDR_OK:
返回合法的从机地址。
ADDR_ERROR:
不能正常分配从机地址。
CMD_OK:
命令支持成功。
CMD_ERROR:
命令执行失败。

部分源程序如下:
  1.     QCoreApplication::processEvents(QEventLoop::AllEvents);
  2.     //检测在线状态
  3.     for(i=0;i<model->rowCount();i++){
  4.         uint32_t local_addr,retry=0;
  5.         if(!model->item(i,0)->text().isEmpty()){
  6.             //清除之前接收的数据
  7.             VCI_ClearBuffer(VCI_USBCAN2,
  8.                             ui->deviceIndexComboBox->currentIndex(),
  9.                             ui->channelIndexComboBox->currentIndex());
  10.             local_addr = model->item(i,0)->text().toInt(NULL,0);
  11.             //发送在线检测命令
  12.             CAN_SendData.DataLen = 0;
  13.             CAN_SendData.ExternFlag = 0;
  14.             CAN_SendData.RemoteFlag = 0;
  15.             CAN_SendData.SendType = 0;
  16.             CAN_SendData.ID = (local_addr<<4)|ONLINE_CHECK;
  17.             ret = VCI_Transmit(VCI_USBCAN2,
  18.                                ui->deviceIndexComboBox->currentIndex(),
  19.                                ui->channelIndexComboBox->currentIndex(),
  20.                                &CAN_SendData,
  21.                                1);
  22.             if(ret!=1){
  23.                 QMessageBox::warning(this,"Warning","Send Data Error!");
  24.             }
  25.             retry = 0;
  26.             while(1){
  27.                 ret = VCI_Receive(VCI_USBCAN2,
  28.                                   ui->deviceIndexComboBox->currentIndex(),
  29.                                   ui->channelIndexComboBox->currentIndex(),
  30.                                   &CAN_ReadData[0],
  31.                                   1);
  32.                 if((ret==1)&&(local_addr==(CAN_ReadData[0].ID>>4))&&((CAN_ReadData[0].ID&0xF)==CMD_OK)){
  33.                     mac_str.sprintf("%02X%02X%02X%02X%02X%02X%02X%02X",
  34.                                     CAN_ReadData[0].Data[0],CAN_ReadData[0].Data[1],
  35.                                     CAN_ReadData[0].Data[2],CAN_ReadData[0].Data[3],
  36.                                     CAN_ReadData[0].Data[4],CAN_ReadData[0].Data[5],
  37.                                     CAN_ReadData[0].Data[6],CAN_ReadData[0].Data[7]);
  38.                     model->item(i,1)->setText(mac_str);
  39.                     break;
  40.                 }else{
  41.                     if(retry<10){
  42.                         Sleep(10);
  43.                         retry++;
  44.                     }else{
  45.                         for(int c=0;c<model->columnCount();c++){
  46.                             model->item(i,c)->setText("");
  47.                         }
  48.                         can_addr.local_addr[i+1]=0;
  49.                         break;
  50.                     }
  51.                 }
  52.             }
  53.         }
  54.     }
  55.     QCoreApplication::processEvents(QEventLoop::AllEvents);
  56.     //获取版本信息
  57.     for(i=0;i<model->rowCount();i++){
  58.         uint32_t local_addr,retry=0;
  59.         if(!model->item(i,0)->text().isEmpty()){
  60.             //清除之前接收的数据
  61.             VCI_ClearBuffer(VCI_USBCAN2,
  62.                             ui->deviceIndexComboBox->currentIndex(),
  63.                             ui->channelIndexComboBox->currentIndex());
  64.             local_addr = model->item(i,0)->text().toInt(NULL,0);
  65.             //发送在线检测命令
  66.             CAN_SendData.DataLen = 0;
  67.             CAN_SendData.ExternFlag = 0;
  68.             CAN_SendData.RemoteFlag = 0;
  69.             CAN_SendData.SendType = 0;
  70.             CAN_SendData.ID = (local_addr<<4)|GET_VERSION;
  71.             ret = VCI_Transmit(VCI_USBCAN2,
  72.                                ui->deviceIndexComboBox->currentIndex(),
  73.                                ui->channelIndexComboBox->currentIndex(),
  74.                                &CAN_SendData,
  75.                                1);
  76.             if(ret!=1){
  77.                 QMessageBox::warning(this,"Warning","Send Data Error!");
  78.             }
  79.             retry = 0;
  80.             while(1){
  81.                 ret = VCI_Receive(VCI_USBCAN2,
  82.                                   ui->deviceIndexComboBox->currentIndex(),
  83.                                   ui->channelIndexComboBox->currentIndex(),
  84.                                   &CAN_ReadData[0],
  85.                                   1);
  86.                 if((ret==1)&&(local_addr==(CAN_ReadData[0].ID>>4))&&((CAN_ReadData[0].ID&0xF)==GET_VERSION)){
  87.                     str.sprintf("V%d.%d",CAN_ReadData[0].Data[0],CAN_ReadData[0].Data[1]);
  88.                     model->item(local_addr-1,2)->setText(str);
  89.                     break;
  90.                 }else{
  91.                     if(retry<10){
  92.                         Sleep(10);
  93.                         retry++;
  94.                     }else{
  95.                         break;
  96.                     }
  97.                 }
  98.             }
  99.         }
  100.     }
  101. }

  102. void MainWindow::on_openFilePushButton_clicked()
  103. {
  104.     QString fileName;
  105.     fileName=QFileDialog::getOpenFileName(this,
  106.                                           tr("Open files"),
  107.                                           "",
  108. ……………………

  109. …………限于本文篇幅 余下代码请下载附件…………
复制代码


CAN Bootloader.rar  [预览压缩包] (440.04 KB, 售价: 1 工控币)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

免责声明: 工控技术网(www.eleok.com)所有内容均为网友自行发布,不代表网站立场。如有版权纠纷,请联系本站删除:1370723259@qq.com

QQ|小黑屋|手机版|工控技术网 |网站地图

GMT+8, 2020-6-3 07:46

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表