TL6678-EVM基于NDK实现单张图像收发

一 准备开发环境

1.硬件

PC:win10 64位
开发板:TL6678-EVM
仿真器:TL-XDS200
网线*1

2.软件

DSP集成开发环境:CCSv5.5 ,Sys/Bios平台,NDK组件,C语言
上位机开发环境:vs2019 ,C#语言
辅助工具:DHCPsrvV1.7、Beyond Compare 4

二 图像数据处理与传输框架

1. 上位机通过PC网口发送一张BMP图片

1)vs2019建立C#工程。
1.1)控件介绍
From.cs窗口布局拉出8个控件。如图1.1。TextBox1显示所选图片的路径,“选择”按钮触发文件对话框,选择一张要发送的BMP图片。TestBox2提供给用户输入DSP服务器的IP地址,TextBox3提供给用户输入端口号。TestBox2、TextBox3会直接显示我在代码里写好的IP地址和端口号值,不用我每次连接都输入一遍。“发送”按钮触发建立Socket通信,连接服务器。TextBox4区域显示用户提示信息。Label区域显示PC接收DSP回发数据后保存为BMP图时生成的绝对路径。PictureBox显示新生成的BMP图片,其控件属性SizeMode已经设置为图片显示自适应控件大小。
图1.1
2)代码简析

打开文件选择对话框

 /// <summary>
        /// 选择文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butChoose_Click(object sender, EventArgs e)
        {
            //打开文件
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "请选择要传的文件";
            ofd.InitialDirectory = @"C:\Users\Administrator\Desktop";
            ofd.Filter = "所有文件|*.*|文本文件|*.txt|表格文件|*.xlsx|视频文件|*.avi";
            ofd.ShowDialog();
            //得到选择文件的路径
            textFile.Text = ofd.FileName;
        }

设定服务器的IP地址及端口号

  private void Form1_Load(object sender, EventArgs e)
        {
            //不检测跨线程之间的空间调用
            Control.CheckForIllegalCrossThreadCalls = false;
            textIP.Text = "192.168.0.186";
            textPort.Text = "1025";
        }

创建Socket通信,连接DSP服务器

private void butConnect_Click(object sender, EventArgs e)          //点击了发送按钮就进入了这个成员函数
        {

           
            try
            {
                //创建负责通信的socket
                socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //获取服务端的IP
                IPAddress ip = IPAddress.Parse(textIP.Text.Trim());
                //获取服务端的端口号
                IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(textPort.Text));
                //获得要连接的远程服务器应用程序的IP地址和端口号
                socketSend.Connect(port);
                ShowMsg("连接成功,正在发送.......");

文件操作,读取并发送BMP图片数据

 using (FileStream fsread = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read))
                {
               
                    byte[] buffer_header = new byte[54];                     //声明一个54个字节大小的数组
                    byte[] buffer = new byte[1024 * 1024 * 8];               //声明一个8KB字节大小的数组

                    fsread.Read(buffer_header, 0, 54);                      //读取54个字节的内容到buffer_header数组
                    socketSend.Send(buffer_header, 0, 54, SocketFlags.None);//往DSP发送54个字节

                    while (true)
                    {

                        int r2 = fsread.Read(buffer, 0, buffer.Length);
                        file_lenth += r2;
                        if (r2 == 0)
                        {
                            file_lenth += 54;
                            ShowMsg("发送完成/累计发送字节:" + file_lenth.ToString());
                            file_lenth1 = file_lenth;
                            file_lenth = 0;
                            break;
                        }
                        socketSend.Send(buffer,0, r2, SocketFlags.None);
                    }
                }

2. DSP通过ETH0接收图片完整数据

1)建立DSP工程
在CCSv5.5的集成开发环境中,导入广州创龙提供的TL6678-EVM评估板SYS/BIOS系统例程,打开NDK_TCP例程,接下来所有的代码修改基本都在TCP.c这个文件里。
在这里插入图片描述
2)修改内存配置
打开这个工程下的app.cfg文件,打开后点击下方的cfg Script这一项,再定位到“内存配置”这一栏,修改原先创龙公司分配的堆空间大小,具体修改大小自行斟酌,我这里修改为250MB。原本分配的堆空间大小只有1MB,如若不修改,当你使用堆内存存储PC传输的大文件时,必定报错,大概意思就是heap error,这也是我遇到并修复的问题之一。在这里插入图片描述
3)配置DSP使用ETH0和动态获取IP地址
在创龙提供的用户例程开发手册里已经提供了网络配置的方法,百度一下也有了,基本上都差不多,都是基于TI的官方例程来修改的。创龙默认是配置为使用ETH1和静态IP地址的,所以我要重新配置,完了之后没有获取到IP地址的,最后我找到了一个可以辅助我们的CCS自动获取IP地址的工具DHCPsrvV1.7,这个工具非常好用,我也会放到资源上,大家需要的话可以下载。

FHCPsrvV1.7资源下载地址;
https://download.csdn.net/download/weixin_42696672/12272936

4)代码简析

先接收BMP图像的前54个字节,并根据公式解析出图像的像素大小

	int nr,total=0;												//nr:保存返回值 ;total:协助计算接收的字节数
    unsigned char *pBuf54;										//存放位图文件头的变量
	pBuf54 = (unsigned char*)malloc(54);  						//动态分配给pBuf54变量54个字节的空间
	nr=(int)recvnc( s, (void**)&pBuf54, 0, &hBuffer );  		 //接收PC端发送过来的信息,存放在pBuf54	
	int W1,H1;   																							              //保存图像的宽度、高度的变量
	W1 = (int)(pBuf54[18])+(int)(pBuf54[19]) * 256 +(int)(pBuf54[20]) * 256 * 256 + (int)(pBuf54[21]) * 256 * 256 * 256;  //计算图像宽度的公式,根据位图信息头里面保存的数据可知,第18个~21个字节
	H1 = (int)(pBuf54[22])+(int)(pBuf54[23]) * 256 +(int)(pBuf54[24]) * 256 * 256 + (int)(pBuf54[25]) * 256 * 256 * 256;  //计算图像高度的公式,根据位图信息头里面保存的数据可知,第22~25个字节

	printf("W1 = %d,H1 = %d,W1*H1*3 = %d Bytes\n",W1,H1,W1*H1*3);

完整接收PC发来的图像数据,首先开辟出一个图片大小的堆空间以存储数据,接着不断接收数据包,并且通过改变指针下标存储到堆内存。

	unsigned char *imagedatatuGUODU;   							 //存放PC端发送过来的图像本身的数据变量,PC段会从图像的最后一个数据开始往DSP端发
	imagedatatuGUODU = (unsigned char*)malloc(W1 * H1 * 3);  	 //根据前面计算出来的图像宽度和高度,动态分配内存空间的大小
	if( imagedatatuGUODU == NULL )
	{
		printf("imagedatatuGUODU malloc failed!!!\n");
		exit(1);
	}
	else
	{
		printf("imagedatatuGUODU malloc successed!!!\n");		//成功分配了空间
	}

	nr = 0;														//这里也是协助存放空间的地址往后偏移

	//这段是接收PC端发来的图像本身的数据
	while(1)
	{

		nr = recv(s,(unsigned char*)(imagedatatuGUODU+total),unit,0);
		if (nr > 0)
		{
			total += nr;

			if (total == W1*H1*3)
			{
				printf("DSP recv complete!!! Integrated reception %d bytes\n ",total);
				break;											 //当累计接收到的数据==图像本身数据大小时,表明接收完整,可以退出这个循环。
			}
		}
		else
		{
			printf( "peer close the socket.recv fail!!!" );		 //对端关闭了连接
			break;												 //真的出错了
		}

	}

3. DSP对图片数据进行处理(略)

这部分处理我没有做,有能力者请自行在DSP代码里添加一段图像处理的功能函数,如对像素值取补,处理后为灰度图,或者是旋转、缩放等等,最后要在回发数据前被调用就可以了。这里我也给大家一个参考的链接,是别人写的博客。

参考博客
https://blog.csdn.net/fengyhack/article/details/43529379

4. DSP回发数据给PC

将前面存储的数据全部回发给PC端,第一次要先发前54个字节,后面就是不断发数据包。其实PC端和DSP端的收发代码思路是一样的。


	//以下往PC回发数据
	send(s,pBuf54,54,0);

	int III;
	int end = W1 * H1 * 3;
	int data_total = end;
	int send_zijie_total = 0;			  						//协助实现地址偏移
	int send_zijie_ret = 0;			  							//记录发送出去的字节数
	//发送图像本身的数据,直到发送完成则跳出循环
	while(1)
	{

		if (end >= unit)
		{
			III = unit;											//剩余很多信息,所以下次继续取unit个字节来发送
		}
		else
		{
			III = end;						   				    //剩下的已经不足一块unit字节,就读剩下的字节数
		}

		send_zijie_ret= send(s, (unsigned char *)(imagedatatuGUODU+send_zijie_total),III,0);
		send_zijie_total += send_zijie_ret;

		//当发送的字节数和图像本身的总字节数相等时,表明发送完成,可以退出循环
		if ( send_zijie_total == data_total )
		{
			printf("The image transmission completion !!! accumulated transmission %d bytes\n",send_zijie_total);
			break;
		}
		if(send_zijie_ret == SOCKET_ERROR)
		{
			printf("send() failed!\n");
			break;
		}
		end -= unit;											 //每发送一次减一次
	}

5. 上位机接收数据并另存为BMP图片

5.1)获取当前系统时间,转换为字符串,作为生成的bmp图片名。


	//保存接收的文件
	string filePath = "";
	filePath = @"F:\Data\";
	string createPath = filePath + '\\' + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".bmp";

5.2)打开生成的BMP图,进行文件操作,写入接收到的数据。


                using (FileStream fsWrite = new FileStream(createPath, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    long recive_length = 0;                  //接收大文件总的字节数
                    byte[] recv_header = new byte[54];
                    byte[] buffer = new byte[1024 * 1024 * 8];

                    socketSend.Receive(recv_header); //先接收54个字节数
                    fsWrite.Write(recv_header, 0, 54);     //将接收到的数据都写入保存的图片里

                    while (true)
                    {

                        int r1 = socketSend.Receive(buffer); //实际接收的有效字节数

                        recive_length += r1;

                        if( r1 > 0 )
                            fsWrite.Write(buffer, 0, r1);     //将接收到的数据都写入保存的图片里

2)当已经接收到的数据的累计大小和原文件大小一样时,说明文件接受完成,就可以关闭当前文件流,并跳出循环了。还可以将当前接收的图片加载显示到控件pictureBox

 if (recive_length == (file_lenth1 - 54) )
  {
       recive_length += 54;
       ShowMsg("接收完成/累计接收字节:" + recive_length.ToString());
       file_lenth1 = 0;
      // ShowMsg("保存路径:" + createPath);

       fsWrite.Close();
       fsWrite.Dispose();

       saveName.Text = createPath ;

       if (createPath != string.Empty)          
       {
           try
           {     
               this.pictureBox.Load(createPath); //显示图片
           }
           catch (Exception ex)
           {
               MessageBox.Show(ex.Message);
           }
       } 
       
       break;
   }

三 测试效果

在这里插入图片描述
肉眼有时候无法分辨出两张图片有无区别,我们可以通过其他软件对原图和接收的图片进行二进制格式转换,再对比,看两张图片是否完全一样。我使用Beyond Compare 4这个软件,它有30天的免费使用。
打开后,点击右侧箭头切换到下一页,选择图片比较。
在这里插入图片描述
分别打开两张图片,自动会对比,结果很快就会出现,左下方显示“二进制相同”说明两张图片是完全一样的。
在这里插入图片描述

Beyond Compare 4资源下载地址
由于上传的资源审核不通过,理由是违规,所以我放到下面我的工程里的文件夹里,需要的可以下载。

附录

完整DSP工程和上位机工程资源及Beyond Compare 4下载地址:
https://download.csdn.net/download/weixin_42696672/12275460

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值