延伸阅读:
目录
本模块用于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