当前位置:   article > 正文

STM32使用QT上位机下载程序,bootload+app

STM32使用QT上位机下载程序,bootload+app

说明

使用qt编写上位机,电脑通过USB转串口工具与单片机连接,使用自定义协议进行bin文件传送image.png

协议

image.png总共有四帧协议:
type1:上位机点击“下载文件”按钮后,会连续发送这帧命令,查询STM32是否准备好
type10:上位机下发文件,一帧最多下发4096字节数据
type10:在APP程序中STM32接受到type1帧后软件复位进入bootload程序,bootload程序接收到type1帧后发送type2帧告诉上位机准备完成,等待下发文件
type20:STM32接收到一帧数据后写入到FLASH,返回成功或失败响应

STM32程序部分

bootload程序

程序跳转部分代码

#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)
	{
		
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

协议解析和程序写入

/* 进入主程序循环体 */
	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;
						}
					}
				}
			}
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

协议应答

/*
*********************************************************************************************************
*    功能说明: 应答
*********************************************************************************************************
*/
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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

APP程序

接收进入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(); /* 软件复位 */
			}
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

QT程序部分

image.png

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号