2021-09-04 09:17:44 索煒達電子 971
項目編號:E778
文件大?。?8M
源碼說明:帶中文注釋
開發(fā)環(huán)境:C編譯器
簡要概述:
一.上位機部分
使用QT-C++ 編寫的上位機
程序思路: 使用串口通訊進行發(fā)送規(guī)定的幀數(shù)據(jù),上位機會將BIN文件數(shù)據(jù)分析打包成每一幀傳送給下位機。 下位機,接受到數(shù)據(jù)后,進行ACK應答,程序接受到應答后,繼續(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 信號綁定到 read_com 這個槽函數(shù)上
connect(&mySerial,SIGNAL(readyRead()),this,SLOT(read_COM()));
此處讀取到下位機的ACK應答后,觸發(fā)自定義信號[readOK],再進行下一步發(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();
}
}
//將自定義的信號和發(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校驗碼: %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應答幀格式
3.下位機通用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ù)燒錄至外部儲存器
* 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
幀頭 幀頭 命令 長度高字節(jié) 長度低字節(jié) 數(shù)據(jù) 數(shù)據(jù) BCC校驗碼 幀尾 幀尾
如發(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ù)傳輸結束 應答
*************************************************************************************/
#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個Block,2048個Sector
//4Kbytes為一個Sector
//16個扇區(qū)為1個Block
//以下表示地址為W25QXX的第一個區(qū)塊的第0個扇區(qū)的第0個地址
#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)儲存的字節(jié)
u8 TBEF_recvBuf[1000]; //接受buf,最大單次傳輸字節(jié)數(shù)應不大于buf大小-8
u16 TBEF_recvBuf_tail = 0;
u8 TBEF_uart_recv_finish = 0, TBEF_uart_recving_flag = 0, TBEF_uart_recv_tim_cnt = 0;
//用戶回調函數(shù),此處修改需要燒錄的函數(shù)
void TBEF_data_CallBack(u8 *dataBuf, u16 len)
{
//根據(jù)需求修改此處
W25QXX_Write(dataBuf, TBEF_W25QXX_StorageAddress + bytesStored, len);//寫入flash
bytesStored += len;
}
//串口處理函數(shù),在串口中斷中調用,將接收到的字節(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; // 串口 接收標志
TBEF_uart_recv_tim_cnt = 0; // 串口接收定時器計數(shù)清零
}
if(TBEF_recvBuf_tail >= sizeof(TBEF_recvBuf))
{
TBEF_recvBuf_tail = 0; // 防止數(shù)據(jù)量過大
}
}
//定時器處理函數(shù),在定時器中斷中調用,1Ms一次
void TBEF_tim_process(void) //1MS調用一次
{
/* 串口接收完成判斷處理 */
if(TBEF_uart_recving_flag) // 如果 usart接收數(shù)據(jù)標志為1
{
TBEF_uart_recv_tim_cnt++; // usart 接收計數(shù)
if(TBEF_uart_recv_tim_cnt > 10) // 當超過 3 ms 未接收到數(shù)據(jù),則認為數(shù)據(jù)接收完成。
{
TBEF_uart_recv_finish = 1;
TBEF_uart_recving_flag = 0;
TBEF_uart_recv_tim_cnt = 0;
}
}
}
//在主函數(shù)中調用,需要一直循環(huán)調用,此函數(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; //幀頭錯誤
if(TBEF_recvBuf[1] != 0x5C)
return 1; //幀頭錯誤
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校驗碼錯誤
if(TBEF_recvBuf[6 + length] != 0x5C)
return 3; //幀尾錯誤
if(TBEF_recvBuf[7 + length] != 0xC5)
return 3; //幀尾錯誤
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 表示沒有錯誤
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;
}
}
三、使用教程
下位機移植完成后,連接串口至電腦。
點擊refresh按鈕,刷新串口列表,選擇下位機終端的COM口,連接
加載BIN文件
設置單次發(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