赞
踩
使用qt编写上位机,电脑通过USB转串口工具与单片机连接,使用自定义协议进行bin文件传送
总共有四帧协议:
type1:上位机点击“下载文件”按钮后,会连续发送这帧命令,查询STM32是否准备好
type10:上位机下发文件,一帧最多下发4096字节数据
type10:在APP程序中STM32接受到type1帧后软件复位进入bootload程序,bootload程序接收到type1帧后发送type2帧告诉上位机准备完成,等待下发文件
type20:STM32接收到一帧数据后写入到FLASH,返回成功或失败响应
程序跳转部分代码
#define APP_ADDR 0x8020000 /* 应用程序首地址定义 */ static void iap_load_app(void) { void (*AppMemBootJump)(void); /* 声明一个函数指针 */ /* 关闭全局中断 */ DISABLE_INT(); /* 关闭滴答定时器,复位到默认值 */ SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; /* 设置所有时钟到默认状态,使用 HSI 时钟 */ HAL_RCC_DeInit(); /* 关闭所有中断,清除所有中断挂起标志 */ for (int i = 0; i < 8; i++) { NVIC->ICER[i]=0xFFFFFFFF; NVIC->ICPR[i]=0xFFFFFFFF; } /* 使能全局中断 */ ENABLE_INT(); /* 设置重映射到系统 Flash */ __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); /* 跳转到APP程序,首地址是 MSP,地址+4 是复位中断服务程序地址 */ AppMemBootJump = (void (*)(void)) (*((uint32_t *) (APP_ADDR + 4))); /* 设置朱堆栈指针 */ __set_MSP(*(uint32_t *)APP_ADDR); /* 在 RTOS 工程,这条语句很重要,设置为特权级模式,使用 MSP 指针 */ __set_CONTROL(0); /* 跳转至APP */ AppMemBootJump(); /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */ while (1) { } }
协议解析和程序写入
/* 进入主程序循环体 */ while (1) { static int tim_100ms = 0; static int mode = 0; static int tim_1000ms = 0; uint8_t com6_rx_data = 0; uint16_t crc = 0; if (tim_1ms_flag == 1) /* 1ms执行一次 */ { tim_1ms_flag = 0; if (mode == 0) { if (++tim_1000ms > 1000) iap_load_app(); /* 超时未进入下载模式,跳转到APP */ } if (++tim_100ms > 100) /* 指示灯闪缩 */ { tim_100ms = 0; HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } } while(comGetChar(COM6, (uint8_t*)&com6_rx_data)) { tRx.buf[tRx.cnt++] = com6_rx_data; switch (tRx.cnt) { case 1: { if (com6_rx_data != 0xEE) tRx.cnt = 0; } break; case 2: { if (com6_rx_data != 0xAA) tRx.cnt = 0; } break; case 7: { tRx.type = tRx.buf[2]; tRx.num = (tRx.buf[3] << 8) + tRx.buf[4]; tRx.lenght = (tRx.buf[5] << 8) + tRx.buf[6]; } break; } if (tRx.cnt == tRx.lenght + 9) /* 一帧数据 */ { tRx.cnt = 0; crc = CRC16_Modbus(tRx.buf, tRx.lenght + 7); /* 校验帧头+帧类型+帧号+数据长度+数据 */ if (crc == (tRx.buf[tRx.lenght + 9 - 2] << 8) + tRx.buf[tRx.lenght + 9 - 1]) /* 校验成功 */ { if (tRx.type == 0x01) { mode = 1; /* 进入下载模式 */ send_ack(0x10, 0x00, 0x00, 0x00); /* boot程序接收准备应答 */ } else if (tRx.type == 0x02) { if (bsp_WriteCpuFlash(add, tRx.buf + 7, tRx.lenght) == 0) { add += tRx.lenght; send_ack(0x20, tRx.num, 0x01, 0x01); /* 文件下载成功应答 */ } else { send_ack(0x20, tRx.num, 0x01, 0x02); /* 文件下载失败应答 */ } if (tRx.num == 0xffff) { tim_1000ms = 0; mode = 0; } } } } } }
协议应答
/* ********************************************************************************************************* * 功能说明: 应答 ********************************************************************************************************* */ static void send_ack(uint8_t type, uint16_t num, uint16_t length, uint8_t data) { uint8_t send_buf[20] = {0}; uint8_t i =0; send_buf[i++] = 0xEE; send_buf[i++] = 0xAA; send_buf[i++] = type; send_buf[i++] = num>>8; send_buf[i++] = num; send_buf[i++] = length>>8; send_buf[i++] = length; for (int a=0; a<length; a++) { send_buf[i++] = data; } uint16_t crc = CRC16_Modbus(send_buf, i); send_buf[i++] = crc>>8; send_buf[i++] = crc; comSendBuf(COM6, (uint8_t *)&send_buf, i); }
接收进入bootload指令的协议解析
struct RX_{ uint8_t buf[20]; /* 接收缓存 */ uint16_t cnt; /* 接收计数 */ uint8_t type; /* 帧类型 */ uint16_t num; /* 帧序号 */ uint16_t lenght; /* 数据长度 */ } tRx; void bootloader_start(uint8_t data) { tRx.buf[tRx.cnt++] = data; switch (tRx.cnt) { case 1: { if (data != 0xEE) tRx.cnt = 0; } break; case 2: { if (data != 0xAA) tRx.cnt = 0; } break; case 7: { tRx.type = tRx.buf[2]; tRx.num = (tRx.buf[3] << 8) + tRx.buf[4]; tRx.lenght = (tRx.buf[5] << 8) + tRx.buf[6]; } break; } if (tRx.cnt == tRx.lenght + 9) /* 一帧数据 */ { tRx.cnt = 0; uint16_t crc = CRC16_Modbus(tRx.buf, tRx.lenght + 7); /* 校验帧头+帧类型+帧号+数据长度+数据 */ if (crc == (tRx.buf[tRx.lenght + 9 - 2] << 8) + tRx.buf[tRx.lenght + 9 - 1]) /* 校验成功 */ { if (tRx.type == 0x01) { tx_thread_sleep(1000); HAL_NVIC_SystemReset(); /* 软件复位 */ } } } }
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); /* 定义串口类,将串口读取函数映射到serialPortReadyRead */ serialPort = new QSerialPort(this); connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead())); /* 获取串口号并显示到COM显示框 */ QStringList serialNamePort; foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { serialNamePort<<info.portName(); } ui->serial_Box1_com->addItems(serialNamePort); /* 将获取的串口号打印到COM显示框 */ /* 禁止下载按钮 */ ui->pushButton_download_feil->setDisabled(true); /* 初始化定时器 */ m_pTimer = new QTimer(this); m_pTimer->setInterval(10); m_pTimer->setSingleShot(false); connect(m_pTimer, &QTimer::timeout, this, &Widget::handleTimeout); m_pTimer->start(); } Widget::~Widget() { delete ui; } /* 定时器 */ void Widget::handleTimeout(void) { int dt = 10; static int last_sendedBytes = 0; static QByteArray fileBuf; static QByteArray rx_buf; static uint16_t rx_cnt = 0; static uint8_t rx_type = 0; static uint16_t rx_num = 0; static uint16_t rx_lenght = 0; static uint16_t tx_num = 0; static uint16_t tx_file_state = 0; static int tim2000ms_flag = 0; QDateTime time = QDateTime::currentDateTime(); QString sdate = time.toString("yyyy-MM-dd"); QString stime = time.toString("hh:mm:ss.zzz "); while (rx_queue.size()) { if (rx_cnt == 0) rx_buf.clear(); rx_buf.append(rx_queue.dequeue()); /* 从队列里面读取一个字节 */ rx_cnt++; switch (rx_cnt) { case 1: { if ((uint8_t)rx_buf.at(0) != 0xEE) rx_cnt = 0; } break; case 2: { if ((uint8_t)rx_buf.at(1) != 0xAA) rx_cnt = 0; } break; case 7: { rx_type = (uint8_t)rx_buf.at(2); rx_num = ((uint8_t)rx_buf.at(3) << 8) + (uint8_t)rx_buf.at(4); rx_lenght = ((uint8_t)rx_buf.at(5) << 8) + (uint8_t)rx_buf.at(6); } break; } if (rx_cnt == rx_lenght + 9) /* 一帧数据 */ { rx_cnt = 0; uint16_t crc = CRC16_Modbus(rx_buf, rx_lenght + 7); /* 校验帧头+帧类型+帧号+数据长度+数据 */ if (crc == ((uint8_t)rx_buf.at(rx_lenght + 9 - 2) << 8) + (uint8_t)rx_buf.at(rx_lenght + 9 - 1)) /* 校验成功 */ { if (rx_type == 0x10) /* stm32准备应答 */ { if (state == 1) state = 2; /* 打印下载信息 */ ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + "设备链接成功"); } else if (rx_type == 0x20) /* stm32文件接收应答 */ { if ((uint8_t)rx_buf.at(7) == 0x01) /* stm32文件接收成功 */ { tx_file_state = 0x01; } else if ((uint8_t)rx_buf.at(7) == 0x02) /* stm32文件接收校验失败 */ { tx_file_state = 0x02; } } } } } switch (state) { case 1: { /* 查询设备 */ fileBuf.clear(); send_buf(0x01, 0, 0, fileBuf); tim2000ms_flag += dt; if (tim2000ms_flag > 2000) { tim2000ms_flag = 0; /* 打印下载信息 */ ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + "设备链接超时。。。"); } } break; case 2: { /* 获取文件段 */ fileBuf.clear(); last_sendedBytes = sendedBytes; if (unSendedBytes >= 4096) { fileBuf = file_array.mid(sendedBytes, 4096); sendedBytes += 4096; unSendedBytes -= 4096; tx_num++; } else { fileBuf = file_array.mid(sendedBytes, unSendedBytes); sendedBytes += unSendedBytes; unSendedBytes -= unSendedBytes; tx_num = 0xffff; /* 最后一帧 */ } send_buf(0x02, tx_num, fileBuf.size(), fileBuf); /* 发送文件帧 */ tim2000ms_flag = 0; state = 3; } break; case 3: { /* 发送文件 */ if ((tx_num == rx_num) && (tx_file_state == 0x01)) /* stm32接收成功 */ { if (tx_num == 0xffff) { ui->pushButton_download_feil->setText("下载文件"); tx_num = 0; state = 0; } else { state = 2; } /* 打印下载信息 */ ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + QString::number((float)last_sendedBytes/1024.0f, 'f', 2) + "KB---" + QString::number((float)sendedBytes/1024.0f, 'f', 2) + "KB " + "下载完成"); /* 更新进度条 */ ui->progressBar_download_progress->setValue((float)(sendedBytes) / (float)(file_array.size()) * 100); tx_file_state = 0; } else { tim2000ms_flag += dt; if (tim2000ms_flag > 2000) { tim2000ms_flag = 0; /* 打印下载信息 */ QDateTime time = QDateTime::currentDateTime(); QString sdate = time.toString("yyyy-MM-dd"); QString stime = time.toString("hh:mm:ss.zzz "); ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + QString::number((float)last_sendedBytes/1024.0f, 'f', 2) + "KB---" + QString::number((float)sendedBytes/1024.0f, 'f', 2) + "KB " + "下载超时。。。"); send_buf(0x02, tx_num, fileBuf.size(), fileBuf); /* 超时重发 */ } } } } } /* 串口发送数据 */ void Widget::send_buf(uint8_t type, uint16_t num, uint16_t length, QByteArray filebuf) { QByteArray sendBuf; sendBuf.clear(); sendBuf.append("\xEE"); sendBuf.append("\xAA"); sendBuf.append((uint8_t)(type)); sendBuf.append((uint8_t)(num >> 8)); sendBuf.append((uint8_t)(num)); sendBuf.append((uint8_t)(length >> 8)); sendBuf.append((uint8_t)(length)); sendBuf.append(filebuf); uint16_t crc = CRC16_Modbus(sendBuf, sendBuf.size()); sendBuf.append((uint8_t)(crc >> 8)); sendBuf.append((uint8_t)crc); serialPort->write(sendBuf); /* 通过串口发送数据 */ } /* 串口数据接收 */ void Widget::serialPortReadyRead() { QByteArray mytemp = serialPort->readAll(); /* 读取串口数据 */ int cnt = 0; while (cnt < mytemp.size()) { rx_queue.enqueue((uint8_t)mytemp.at(cnt++)); /* 压入接收队列 */ } } /* 点击‘打开串口’按钮 */ void Widget::on_pushButton_open_serial_clicked() { QDateTime time = QDateTime::currentDateTime(); QString sdate = time.toString("yyyy-MM-dd"); QString stime = time.toString("hh:mm:ss.zzz "); if (ui->pushButton_open_serial->text() == tr("打开串口")) { //打开串口按键按下时→初始化串口 QSerialPort::BaudRate baudRate; QSerialPort::DataBits dataBits; QSerialPort::Parity checkBits; QSerialPort::StopBits stopBits; if (ui->serial_Box2_baud->currentText() == "4800") { baudRate = QSerialPort::Baud4800; } else if (ui->serial_Box2_baud->currentText() == "9600") { baudRate = QSerialPort::Baud9600; } else if (ui->serial_Box2_baud->currentText() == "115200") { baudRate = QSerialPort::Baud115200; } if (ui->serial_Box3_data->currentText() == "6") { dataBits = QSerialPort::Data6; } else if (ui->serial_Box3_data->currentText() == "7") { dataBits = QSerialPort::Data7; } else if (ui->serial_Box3_data->currentText() == "8") { dataBits = QSerialPort::Data8; } if (ui->serial_Box4_check->currentText() == "none") { checkBits = QSerialPort::NoParity; } if (ui->serial_Box5_stop->currentText() == "1") { stopBits = QSerialPort::OneStop; } else if (ui->serial_Box5_stop->currentText() == "1.5") { stopBits = QSerialPort::OneAndHalfStop; } else if (ui->serial_Box5_stop->currentText() == "2") { stopBits = QSerialPort::TwoStop; } serialPort->setPortName(ui->serial_Box1_com->currentText()); //获取选择的串口号 serialPort->setBaudRate(baudRate); //设置波特率 serialPort->setDataBits(dataBits); serialPort->setParity(checkBits); serialPort->setStopBits(stopBits); if (serialPort->open(QIODevice::ReadWrite) == true) { //QMessageBox::information(this, "提示", "打开成功"); //打开成功 ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + "打开:" + ui->serial_Box1_com->currentText()); ui->pushButton_open_serial->setText(tr("关闭串口")); } else { QMessageBox::critical(this, "提示", "打开失败"); } } else { ui->pushButton_open_serial->setText(tr("打开串口")); serialPort->close(); // 关闭串口 } } /* 点击‘清空窗口’按钮 */ void Widget::on_pushButton_clicked() { ui->log_plainTextEdit->clear(); } /* 点击‘COM列表’ */ void Widget::on_serial_Box1_com_activated(const QString &arg1) { QDateTime time = QDateTime::currentDateTime(); QString sdate = time.toString("yyyy-MM-dd"); QString stime = time.toString("hh:mm:ss.zzz "); ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + arg1); ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + "关闭:" + ui->serial_Box1_com->currentText()); ui->pushButton_open_serial->setText(tr("打开串口")); serialPort->close(); // 关闭串口 } /* 点击‘打开文件’按钮 */ void Widget::on_pushButton_open_file_clicked() { QDateTime time = QDateTime::currentDateTime(); QString sdate = time.toString("yyyy-MM-dd"); QString stime = time.toString("hh:mm:ss.zzz "); /* 打开资源管理器 */ QString file_address = QFileDialog::getOpenFileName(this, QString::fromLocal8Bit("file"), qApp->applicationDirPath(), QString::fromLocal8Bit("file(*.bin)")); if (file_address.isEmpty()) { return; /* 未选择文件 */ } QFile file(file_address); file.open(QIODevice::ReadOnly); file_array = file.readAll(); /* 读取文件内容到缓存 */ ui->lineEdit_file_address->setText(file_address); /* 打印文件地址到文件路径 */ ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + "文件地址:" + file_address); /* 打印文件地址LOG窗口 */ ui->log_plainTextEdit->appendPlainText(sdate + " " + stime + ": " + "文件大小:" + QString::number((float)file_array.size()/1024.0f, 'f', 2) + "KB"); /* 打印文件大小到LOG窗口 */ ui->progressBar_download_progress->setValue(0); /* 设置下载进度条为0 */ ui->pushButton_download_feil->setEnabled(true); /* 使能下载按钮 */ sendedBytes = 0; unSendedBytes = file_array.size(); /* 未发送字节个数 */ file.close(); /* 关闭文件 */ } /* 点击‘下载文件’按钮 */ void Widget::on_pushButton_download_feil_clicked() { if (state != 1) { state = 1; /* 开始和设备通讯,准备下载 */ sendedBytes = 0; unSendedBytes = file_array.size(); /* 未发送字节个数 */ ui->pushButton_download_feil->setText("取消下载"); } else { state = 0; /* 取消下载 */ ui->pushButton_download_feil->setText("下载文件"); } } /* CRC 高位字节值表 */ static const uint8_t s_CRCHi[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 } ; /* CRC 低位字节值表 */ static const uint8_t s_CRCLo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 }; /* CRC校验 */ uint16_t CRC16_Modbus(QByteArray _pBuf, uint16_t _usLen) { uint8_t ucCRCHi = 0xFF; /* 高CRC字节初始化 */ uint8_t ucCRCLo = 0xFF; /* 低CRC 字节初始化 */ uint16_t usIndex; /* CRC循环中的索引 */ uint16_t i =0; while (_usLen--) { uint8_t temp = _pBuf.at(i++); usIndex = ucCRCHi ^ temp; /* 计算CRC */ ucCRCHi = ucCRCLo ^ s_CRCHi[usIndex]; ucCRCLo = s_CRCLo[usIndex]; } return ((uint16_t)ucCRCHi << 8 | ucCRCLo); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。