2021-09-04 09:17:44 索煒達(dá)電子 983
項(xiàng)目編號(hào):E778
文件大?。?8M
源碼說明:帶中文注釋
開發(fā)環(huán)境:C編譯器
簡(jiǎn)要概述:
一.上位機(jī)部分
使用QT-C++ 編寫的上位機(jī)
程序思路: 使用串口通訊進(jìn)行發(fā)送規(guī)定的幀數(shù)據(jù),上位機(jī)會(huì)將BIN文件數(shù)據(jù)分析打包成每一幀傳送給下位機(jī)。 下位機(jī),接受到數(shù)據(jù)后,進(jìn)行ACK應(yīng)答,程序接受到應(yīng)答后,繼續(xù)發(fā)送數(shù)據(jù),直至完成發(fā)送。
1.幀協(xié)議格式:
如發(fā)送數(shù)據(jù):C5 5C 00 00 04 22 33 44 FF AE 5C C5 BCC = 除了幀頭幀尾和bcc本身的異或 BCC = 00 ^ 00 ^ 04 ^ 22 ^ 33 ^ 44 ^ FF = AE
2.QT部分程序
//將串口的 readyread 信號(hào)綁定到 read_com 這個(gè)槽函數(shù)上
connect(&mySerial,SIGNAL(readyRead()),this,SLOT(read_COM()));
此處讀取到下位機(jī)的ACK應(yīng)答后,觸發(fā)自定義信號(hào)[readOK],再進(jìn)行下一步發(fā)送
void MainWindow::read_COM()
{
QByteArray mytemp = mySerial.readAll();
if(!mytemp.isEmpty())
{
//qDebug() << mytemp.toHex();
if((mytemp.at(0) & 0xff) != 0xC5)
return;
if((mytemp.at(1) & 0xff) != 0x5C)
return;
if((mytemp.at(5) & 0xff) == 0x00){
ui->textEdit_Log->append("send Data OK!");
sendedBytes += currentLen;
unSendedBytes = file_length - sendedBytes;
if(unSendedBytes < 0)
unSendedBytes = 0;
ui->label_sendedBytes->setNum(sendedBytes);
ui->label_unSendedBytes->setNum(unSendedBytes);
ui->progressBar->setValue(static_cast<int>((static_cast<float>(sendedBytes) / static_cast<float>(file_length)) * 100));
if(unSendedBytes > 0){
emit(recvOK());
}else {
ui->textEdit_Log->append("all data send over!");
ui->pushButton_StartSending->setEnabled(true);
}
}
else {
ui->pushButton_StartSending->setEnabled(true);
ui->textEdit_Log->append("send Data failed!");
ui->textEdit_Log->append(QString("ERROR:%1").arg(mytemp.at(5) & 0xff));
}
//mytemp.clear();
}
}
//將自定義的信號(hào)和發(fā)送函數(shù)連接
connect(this, &MainWindow::recvOK, this, &MainWindow::sendOnce);
void MainWindow::sendOnce(){
QByteArray sendBuf, dataBuf;
char file_length0,file_length1;
QString str;
char bcc = 0x00;
if(unSendedBytes >= ui->lineEdit_ByteNum->text().toInt()){
dataBuf = file_array.mid(sendedBytes, ui->lineEdit_ByteNum->text().toInt());
currentLen = ui->lineEdit_ByteNum->text().toInt();
}
else {
dataBuf = file_array.mid(sendedBytes, unSendedBytes);
currentLen = unSendedBytes;
}
//qDebug() << dataBuf.size();
sendBuf.clear();
sendBuf.append("\xC5\x5C");
sendBuf.append(static_cast<char>(0));
file_length0 = static_cast<char>(currentLen / 0xFF);
file_length1 = static_cast<char>(currentLen % 0xFF);
sendBuf.append(file_length0);
sendBuf.append(file_length1);
//qDebug() << sendBuf.toHex().toUpper();
sendBuf.append(dataBuf);
//qDebug() << sendBuf.toHex().toUpper();
for(int i = 2; i < sendBuf.size(); i++){
//str.append((QString("%1 ").arg(file_array.at(i) & 0xff, 2, 16, QLatin1Char('0')).toUpper()));
bcc ^= sendBuf.at(i) & 0xff;
}
sendBuf.append(bcc);
sendBuf.append("\x5C\xC5");
//qDebug() << sendBuf.toHex().toUpper();
for(int i = 5; i < sendBuf.size() - 3; i++){
str.append((QString("%1 ").arg(sendBuf.at(i) & 0xff, 2, 16, QLatin1Char('0')).toUpper()));
}
ui->textEdit_Status->append("---------------------------------------");
ui->textEdit_Status->append(QString("地址[ %1 ] to [ %2 ] 的數(shù)據(jù):").arg(sendedBytes).arg(sendedBytes + currentLen - 1));
ui->textEdit_Status->append(str);
ui->textEdit_Status->append(QString("--- BCC校驗(yàn)碼: %1 ---").arg(bcc & 0xff, 2, 16, QLatin1Char('0')).toUpper());
ui->textEdit_Log->append(QString("send [ %1 ] to [ %2 ] Data ...").arg(sendedBytes).arg(sendedBytes + currentLen - 1));
mySerial.write(sendBuf);
}
2.ACK應(yīng)答幀格式
3.下位機(jī)通用C++代碼(Lib)
//"transfer_BIN_to_EX_FLASH.h"
#ifndef __transfer_BIN_to_EX_FLASH
#define __transfer_BIN_to_EX_FLASH
extern u8 TBEF_uart_recv_finish , TBEF_uart_recving_flag , rTBEF_uart_recv_tim_cnt;
//extern u8 TBEF_recvBuf[400];
//extern u16 TBEF_recvBuf_tail;
void TBEF_uart_receive_process(u8 data);
void TBEF_tim_process(void);
void TBEF_SendACK(u8 ERROR);
void TBEF_clearRecvBuf();
u8 TBEF_framePrasing();
void TBEF_mainFun();
void TBEF_data_CallBack(u8 *dataBuf, u16 len);
#endif
/************************************************************************************
* Copyright (c), 2020, LXG.
*
* FileName :
* Author :firestaradmin
* Version :1.0
* Date :2020.7.21
* Description :串口接收BIN文件數(shù)據(jù)燒錄至外部?jī)?chǔ)存器
* History :
*
*
*************************************************************************************
幀協(xié)議格式:
Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 … last but two Byte last but one Byte Last Byte
0xC5 0x5C XX XX XX XX XX XX 0x5C 0xC5
幀頭 幀頭 命令 長(zhǎng)度高字節(jié) 長(zhǎng)度低字節(jié) 數(shù)據(jù) 數(shù)據(jù) BCC校驗(yàn)碼 幀尾 幀尾
如發(fā)送數(shù)據(jù):C5 5C 00 00 04 22 33 44 FF AE 5C C5
BCC = 除了幀頭幀尾和bcc本身的異或
BCC = 00 ^ 00 ^ 04 ^ 22 ^ 33 ^ 44 ^ FF = AE
命令: 0x00 0x01 0x02 0xFF
備注: 數(shù)據(jù) 數(shù)據(jù)傳輸開始 數(shù)據(jù)傳輸結(jié)束 應(yīng)答
*************************************************************************************/
#include "stm32f10x.h"
#include "../bsp/transfer_BIN_to_EX_FLASH/transfer_BIN_to_EX_FLASH.h"
#include "../bsp/w25qxx/w25qxx.h"
#include "../BSP/usart/usart.h"
//W25Q64
//容量為8M字節(jié),共有128個(gè)Block,2048個(gè)Sector
//4Kbytes為一個(gè)Sector
//16個(gè)扇區(qū)為1個(gè)Block
//以下表示地址為W25QXX的第一個(gè)區(qū)塊的第0個(gè)扇區(qū)的第0個(gè)地址
#define W25QXX_STORAGE_Block 1
#define W25QXX_STORAGE_Sector 0
#define W25QXX_STORAGE_Sector_OFFSET 0
u32 TBEF_W25QXX_StorageAddress = W25QXX_STORAGE_Block * 4 * 1024 * 16 + 4 * 1024 * W25QXX_STORAGE_Sector + W25QXX_STORAGE_Sector_OFFSET; //要燒錄的具體地址
u32 bytesStored = 0; //已經(jīng)儲(chǔ)存的字節(jié)
u8 TBEF_recvBuf[1000]; //接受buf,最大單次傳輸字節(jié)數(shù)應(yīng)不大于buf大小-8
u16 TBEF_recvBuf_tail = 0;
u8 TBEF_uart_recv_finish = 0, TBEF_uart_recving_flag = 0, TBEF_uart_recv_tim_cnt = 0;
//用戶回調(diào)函數(shù),此處修改需要燒錄的函數(shù)
void TBEF_data_CallBack(u8 *dataBuf, u16 len)
{
//根據(jù)需求修改此處
W25QXX_Write(dataBuf, TBEF_W25QXX_StorageAddress + bytesStored, len);//寫入flash
bytesStored += len;
}
//串口處理函數(shù),在串口中斷中調(diào)用,將接收到的字節(jié)傳入data
void TBEF_uart_receive_process(u8 data)
{
if(TBEF_uart_recv_finish == 0){
TBEF_recvBuf[TBEF_recvBuf_tail++] = data; // 存入緩存數(shù)組
TBEF_uart_recving_flag = 1; // 串口 接收標(biāo)志
TBEF_uart_recv_tim_cnt = 0; // 串口接收定時(shí)器計(jì)數(shù)清零
}
if(TBEF_recvBuf_tail >= sizeof(TBEF_recvBuf))
{
TBEF_recvBuf_tail = 0; // 防止數(shù)據(jù)量過大
}
}
//定時(shí)器處理函數(shù),在定時(shí)器中斷中調(diào)用,1Ms一次
void TBEF_tim_process(void) //1MS調(diào)用一次
{
/* 串口接收完成判斷處理 */
if(TBEF_uart_recving_flag) // 如果 usart接收數(shù)據(jù)標(biāo)志為1
{
TBEF_uart_recv_tim_cnt++; // usart 接收計(jì)數(shù)
if(TBEF_uart_recv_tim_cnt > 10) // 當(dāng)超過 3 ms 未接收到數(shù)據(jù),則認(rèn)為數(shù)據(jù)接收完成。
{
TBEF_uart_recv_finish = 1;
TBEF_uart_recving_flag = 0;
TBEF_uart_recv_tim_cnt = 0;
}
}
}
//在主函數(shù)中調(diào)用,需要一直循環(huán)調(diào)用,此函數(shù)為阻塞函數(shù)
void TBEF_mainFun()
{
u8 ret = TBEF_framePrasing();
TBEF_recvBuf_tail = 0;
TBEF_uart_recv_finish = 0;
TBEF_SendACK(ret);
}
u8 TBEF_framePrasing()
{
u16 length = 0;
u8 cmd = 0;
u8 bcc = 0x00;
while(TBEF_uart_recv_finish != 1); //wait receive finish
if(TBEF_recvBuf[0] != 0xC5)
return 1; //幀頭錯(cuò)誤
if(TBEF_recvBuf[1] != 0x5C)
return 1; //幀頭錯(cuò)誤
cmd = TBEF_recvBuf[2];
length = TBEF_recvBuf[3] * 0xFF + TBEF_recvBuf[4];
for(u16 i = 2; i < 5 + length; i ++){
bcc ^= TBEF_recvBuf[i];
}
if(bcc != TBEF_recvBuf[5 + length])
return 2; //bcc校驗(yàn)碼錯(cuò)誤
if(TBEF_recvBuf[6 + length] != 0x5C)
return 3; //幀尾錯(cuò)誤
if(TBEF_recvBuf[7 + length] != 0xC5)
return 3; //幀尾錯(cuò)誤
if(cmd == 0x00)
{
TBEF_data_CallBack(TBEF_recvBuf + 5, length);
}
else if(cmd == 0x01)
{
bytesStored = 0;
}
else if(cmd == 0x02)
{
}else {
}
return 0;
}
//如:C5 5C FF 00 01 00 FE 5C C5 表示沒有錯(cuò)誤
void TBEF_SendACK(u8 ERROR)
{
u8 sendBuf[9] = {0xC5, 0x5C, 0xFF, 0x00, 0x01, ERROR, 0x00, 0x5C, 0xC5};
sendBuf[6] = sendBuf[2] ^ sendBuf[3] ^ sendBuf[4] ^ sendBuf[5] ;
UartSendMultByte(USART1, sendBuf, 9);
}
void TBEF_clearRecvBuf()
{
while(TBEF_recvBuf_tail--)
{
TBEF_recvBuf[TBEF_recvBuf_tail] = 0;
}
}
三、使用教程
下位機(jī)移植完成后,連接串口至電腦。
點(diǎn)擊refresh按鈕,刷新串口列表,選擇下位機(jī)終端的COM口,連接
加載BIN文件
設(shè)置單次發(fā)送字節(jié)數(shù)
開始發(fā)送,等待發(fā)送完成即可
目錄│文件列表:
└ Uart_Transfer_BIN_to_exFlash
│ GB2312等線16_垂直掃描_高位在前.bin
│ GB2312等線24_垂直掃描_高位在前.bin
│ GBK2312等線24_水平掃描高位在前.bin
│ uart_transfer_BIN_to_EX-Flash_boxed.exe
├ Code
│ ├ QT
│ │ └ uart_transfer_BIN_to_EX-Flash
│ │ │ main.cpp
│ │ │ main.h
│ │ │ mainwindow.cpp
│ │ │ mainwindow.h
│ │ │ mainwindow.ui
│ │ │ mythread.cpp
│ │ │ mythread.h
│ │ │ uart_transfer_BIN_to_EX-Flash.pro
│ │ │ uart_transfer_BIN_to_EX-Flash.pro.user
│ │ │ uart_transfer_BIN_to_EX-Flash.pro.user.a68afde
│ │ │ 傳輸協(xié)議.docx
│ │ └ 思路草圖.JPG
│ └ STM32F103
│ └ NestlingV2.1_F103_UART_transfer_BIN_to_EX-FLASH
│ ├ Bsp
│ │ ├ delay
│ │ │ │ delay.c
│ │ │ └ delay.h
│ │ ├ LED
│ │ │ │ LED.c
│ │ │ └ LED.h
│ │ ├ SPI
│ │ │ │ spi.c
│ │ │ └ spi.h
│ │ ├ SRAM
│ │ │ │ sram.c
│ │ │ └ sram.h
│ │ ├ TIM
│ │ │ │ myTIM.c
│ │ │ └ myTIM.h
│ │ ├ transfer_BIN_to_EX_FLASH
│ │ │ │ transfer_BIN_to_EX_FLASH.c
│ │ │ └ transfer_BIN_to_EX_FLASH.h
│ │ ├ USART