基於MFC的USB上位機開發(3)資料傳輸模組
延伸閱讀:
目錄
本模組用於FPGA環路程式的除錯,在上位機視窗上包括兩個區域:資料控制區域和資料顯示區域。當FPGA需要讀取USB的資料時,上位機可向USB端傳送指定數目和數值或者512位元組遞增的資料,當FPGA往USB寫好資料時,上位機也可以手動接收來至USB的512位元組資料。上位機接收的資料不僅可以顯示在視窗上,還可以儲存至電腦本地檔案中。在FPGA環路除錯中,如果USB的FIFO管道內出現了非512位元組整數倍的無效資料,可使用清空管道命令來完成USB管道的清空,本模組的介面效果如下:
1. 設計思路
1.1 傳送資料
由於FPGA與USB之間的資料線位數為16bit,為單位元組(8bit)的偶數倍,所以傳送資料的數量必須為偶數,其大小範圍是0~512。
待發送的資料可以按指定數目和數值的方式進行發生,只要累積傳送512位元組,上位機端就可以收到512位元組資料。待發送的資料也可以是512位元組遞增資料,資料包含2個從0x 00遞增至0x FF的256位元組資料。
傳送模組的程式流程圖如下,在上位機的Public區定義了變數Increment_req,用於判斷是否傳送遞增資料的請求。當按下“傳送指定資料”按鈕時,上位機會向USB傳送指定數目和大小的資料。如果按下“傳送512位元組遞增資料”按鈕,公共變數Increment_req會賦值true,上位機會向USB傳送512位元組遞增資料,在該次執行緒結束時Increment_req會賦值false。
1.2 接收資料
接收模組的程式流程圖如下,當接收按鈕按下上位機立馬建立接收512位元組資料的執行緒,如果接收成功就將資料進行顯示和儲存,如果接收失敗就提醒先向FPGA傳送資料,與此同時將該按鈕禁用。512位元組資料的顯示是本環節的設計難點,涉及到陣列轉換為字串和字串多行顯示的知識點,詳細介紹請閱讀第2.4 節長陣列進行分行顯示。
1.3 清空管道
在進行FPGA環路程式碼除錯之前,是不清楚USB的端點EP6內有多少位元組資料未讀出,EP6的深度為2KByte,那麼USB管道內的無效資料數量NUM會介於0~2KByte之間。
(1)當NUM=2KByte時,上位機通過接收4次512位元組資料即可完成管道清空;
(2)當NUM<512Byte時,上位機需要通過判斷NUM的具體數字,來清空管道;
(3)當NUM介於512B和2KB之間時,需要進行1~3次512位元組資料接收再加一次無效資料位元組數的判斷,即可完成管道的清空。
清空管道的程式流程如下:
2. MFC控制元件相關操作
2.1 Edit Control控制元件數值操作
將上位機文字框數值賦給內部變數:UpdateData(true);
將內部變數值更新到上位機文字框內:UpdateData(false);
2.2 使用時間命名
有關C++時間結構體CTime的知識可以閱讀參考文章[1]和[2],下列程式碼中Y、m、d、H、M和S,依次表示年、月、日、時、分和秒,str字串交代了檔案的儲存路徑是“C:\USB_file_recevie”,儲存的檔名形式是file_20181219213250.hex。
CTime t=CTime::GetCurrentTime();
str=t.Format(_T("C:\\USB_file_recevie\\file_%Y%m%d%H%M%S.hex"));
2.3 資料儲存
有關C++檔案操作的知識可以閱讀參考文章[3],本上位機僅用到檔案的開啟、清空、寫入和關閉等操作,具體程式碼如下:
mFile.Open(str,CFile::modeWrite|CFile::modeCreate); //開啟檔案
mFile.SetLength(0); //清空檔案
mFile.SeekToEnd();
mFile.Write(data,nLen); //向檔案內寫入512位元組資料
mFile.Flush(); //強制將緩衝區資料寫入磁碟檔案
mFile.Close(); //關閉檔案
2.4 長陣列進行分行顯示
為了方便觀察接收到的512位元組資料,需要將資料進行分行顯示。上位機將資料按位元組分成32行16列,具體的實現方法如下方所示:
void CUSBprojDlg::Matrix_to_String(UCHAR * data_512)
{
int i=0;
int j=0;
int line=1;
CString str=_T("line00: ");
CString tmp_str=_T("");
for(i=0;i<512;i++)
{
tmp_str.Format(_T("%02X "),data_512[i]);
str+=tmp_str;
if((j!=0)&&(j!=511)&&((j+1)%16==0))
{
str+=_T(" \r\n");
tmp_str.Format(_T("line%02d: "),line);
str+=tmp_str;
line++;
}
j++;
}
data_display +=str;
data_display +=_T(" \r\n");
}
程式碼的設計思路是,將512位元組陣列data_512分成32段,在每段的開頭新增line n:,n從0增至31。每個位元組的後面帶兩個空格,每16個位元組的後面新增換行符“ \r\n”。有關陣列轉換為字串的知識可以閱讀參考文章[4]和[5]。
2.5 開啟資料夾
void CUSBprojDlg::OnBnClickedOPEN_FOLDER()
{
ShellExecute(NULL, _T("open"), _T("C:\\USB_file_recevie"), NULL, NULL, SW_SHOWNORMAL);
}
3. 功能測試
3.1 傳輸512位元組固定數值資料
先向USB傳送512位元組0x FF
再向USB接收512位元組資料
3.2 傳輸512位元組遞增資料
先向USB傳送512位元組遞增資料
再向USB接收512位元組資料
3.3 傳輸混合固定數值資料
先向USB傳送510位元組0x 00和2位元組0x FF
再向USB接收512位元組資料
3.4 清空管道
首先,模擬USB管道有無效資料的情況:向USB傳送10位元組0x 00。
接著,向USB傳送512位元組0x 01,再接收512位元組資料
由於USB的管道內有10位元組無效的資料0x 00,導致接收的512位元組資料的前10位元組發生了改變,如何解決以上現象呢,有以下兩種方法:
方法1:讓USB開發板重新上電,在電路啟動時USB的FIFO會自動清空。
方法2:使用上位機的清空管道按鈕,通過軟體的方式實現USB的FIFO清空。
現對方法2進行驗證,先點選管道清空按鈕,接著再向USB傳送512位元組0x 02,最後接收512位元組資料。
從上方資料可以發現USB管道內的10位元組0x 01已通過上位機軟體清空,所以接收的資料在數值上與上次傳送的資料保持一致。
3.5 開啟資料記錄
點選“開啟資料記錄”按鈕,即可彈出資料的保持目錄,開啟的目錄路徑為“C:\USB_file_recevie”,和預設的路徑是一致的。每接收512位元組資料都會儲存在以時刻命名的hex檔案中,hex檔案可以使用UltraEdit軟體檢視。
4. 參考
[1] MFC中獲取系統當前時間GetCurrentTime用法
https://blog.csdn.net/naibozhuan3744/article/details/78773780
[2] VC中CTime怎麼轉換成字串?
https://bbs.csdn.net/topics/60232871
[3] VC++檔案操作之最全篇(總結一下希望對大家有用)
https://blog.csdn.net/u010258235/article/details/24477429
[4] MFC怎麼讓編輯框多行顯示文字內容
https://bbs.csdn.net/topics/390936461
[5] MFC在編輯框中顯示一個二維陣列
https://blog.csdn.net/shufac/article/details/20497225