ENC28J60 发送缓冲区的写入?

[复制链接]
5761|23
 楼主| kaly_liu 发表于 2013-5-20 14:27 | 显示全部楼层 |阅读模式
本帖最后由 kaly_liu 于 2013-5-22 16:38 编辑

利用单片机和ENC28J60实现TCP数据发送,现在有个问题是数据太长,我是存在EEPROM的,直接读取,再发送回有问题,需要将数据分N次读出,然后存到ENC28J60的发送缓冲区,然后再一次性发送出去,我在驱动中试了改几下,不能实现,望有高人指教啊!下面是发送的程序。我是结合uip0.9进行的。
  1. #define ETHERNET_MIN_PACKET_LENGTH        0x3C
  2. #define ETHERNET_HEADER_LENGTH                0x0E
  3. #define IP_TCP_HEADER_LENGTH 40
  4. #define TOTAL_HEADER_LENGTH (IP_TCP_HEADER_LENGTH+ETHERNET_HEADER_LENGTH)
  5. void enc28j60PacketSend(u16_t len, u8_t* packet)
  6. {
  7.     // Set the write pointer to start of transmit buffer area
  8.         enc28j60Write(EWRPTL, TXSTART_INIT);
  9.     enc28j60Write(EWRPTH, TXSTART_INIT>>8);
  10.     // Set the TXND pointer to correspond to the packet size given
  11.         enc28j60Write(ETXNDL, (TXSTART_INIT+len));
  12.     enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
  13.     // write per-packet control byte
  14.         enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
  15.     // TODO, fix this up

  16.     if( uip_len <= TOTAL_HEADER_LENGTH )
  17.     {
  18.         // copy the packet into the transmit buffer
  19.                 enc28j60WriteBuffer(len, packet);
  20.     }
  21.     else
  22.     {
  23.           len -= TOTAL_HEADER_LENGTH;
  24.         enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
  25.         enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
  26.     }
  27.         // Errata workaround #12, reset TX logic
  28.     // send the contents of the transmit buffer onto the network
  29.         enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
  30. }


 楼主| kaly_liu 发表于 2013-5-20 15:58 | 显示全部楼层
本帖最后由 kaly_liu 于 2013-5-23 10:35 编辑


这是我的代码,这是TCP服务器的 IP为 192.168.1.14 端口8000  串口波特是 9600
当TCP客户端连接上时,TCP客户端发送‘C’,服务器就会返回一串信息,我现在想让 TCP服务器接收到‘C’后,不是发送那一串数据,而是发送里一个很长的数据,而此时单片机的RAM不够用,需要将这个数据先存入 ENC28J60的发送缓冲中,最后再一次发送。有高人指点说是可以在网卡驱动中编写边发送,但是我还是不知道这么修改啊,现在代码都弄上来了,有人有空给看看啊,呵呵~~多谢了~~~~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
huangxz 发表于 2013-5-20 19:23 | 显示全部楼层
kaly_liu 发表于 2013-5-20 15:58
这是我的代码,这是TCP服务器的 IP为 192.168.1.14 端口8000  串口波特是 9600
当TCP客户端连接上时,TCP客 ...

改这一行
enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);

评分

参与人数 1威望 +1 收起 理由
kaly_liu + 1

查看全部评分

 楼主| kaly_liu 发表于 2013-5-21 08:54 | 显示全部楼层
huangxz 发表于 2013-5-20 19:23
改这一行
enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);

我开始有改过,但是不行。就是在发送函数,开始的时候有个申请缓冲空间大小,这个和len有关,如果在后面轻易修改,最后会出错额。
还有一个疑问就是,我们发送数据的时候,对方的TCP客户端,是要返回信息的,如果我在这里吧这个enc28j60writebuffer(...)里的长度,内容改了,那返回的信息和大程序中的会不会对不上,导致发送失败啊······
问题有点乱额·····
 楼主| kaly_liu 发表于 2013-5-21 08:55 | 显示全部楼层
本帖最后由 kaly_liu 于 2013-5-22 10:31 编辑

我想您说的要修改的函数应该是关键的,但是好像还有许多其他的地方需要修改的额···
关于IP和TCP头的格式的类型、数据长度、·····
xyz769 发表于 2013-5-21 10:50 | 显示全部楼层
本帖最后由 xyz769 于 2013-5-21 10:51 编辑
kaly_liu 发表于 2013-5-20 15:58
这是我的代码,这是TCP服务器的 IP为 192.168.1.14 端口8000  串口波特是 9600
当TCP客户端连接上时,TCP客 ...

改驱动,将这一函数
void enc28j60PacketSend(u16_t len, u8_t* packet)
分解成三个函数,比如:
void enc28j60PacketSendBegin(u16_t len)//开始发送,填充报头等
void enc28j60PacketSendBuffer(u16_t len, u8_t* packet)//填充数据,可多次调用
void enc28j60PacketSendEnd(u16_t crc)//报文准备完毕,填充CRC并发送

评分

参与人数 1威望 +1 收起 理由
kaly_liu + 1

查看全部评分

 楼主| kaly_liu 发表于 2013-5-22 10:29 | 显示全部楼层
xyz769 发表于 2013-5-21 10:50
改驱动,将这一函数
void enc28j60PacketSend(u16_t len, u8_t* packet)
分解成三个函数,比如:

请问这一段代码表示什么意思啊,主要是那个if···
  1.     if( uip_len <= TOTAL_HEADER_LENGTH )
  2.     {
  3.         // copy the packet into the transmit buffer
  4.                 enc28j60WriteBuffer(len, packet);
  5.     }
  6.     else
  7.     {
  8.           len -= TOTAL_HEADER_LENGTH;
  9.         enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
  10.         enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
  11.     }
 楼主| kaly_liu 发表于 2013-5-22 10:50 | 显示全部楼层
1.我在example0.c中的代码,判断如果收到的是'C'那么就会调用一次 uip_send()我看了那个uip_send函数就是把数据、长度这两个的值赋给uip_appdata、以及uip_len。这个时候是如何进行发送的呢?难道是当uip_send函数将数据指针设置后(此时uip_len就大于0了),然后通过uip_periodic()这个来发送数据的?还是另有途径呢?

2.如果我现在想在uip收到数据后,然后发送一串很长的数据,由于受单片机的RAM限制,我只能在网卡驱动函数中修改,在里面不断的读取EEPROM中的数据并送到网卡的缓冲中,当把所需要的数据读取到网卡的缓冲中后,再执行发送命令。这样就可以将数据发送出去了。但是有一个问题,在发送的数据中有IP头、TCP头之类的东东,这些东东放在哪里了?那些里面包含了数据的类型、数据长度等,这个我在哪里修改?我才是在packet里面,packet是uip_buf映射过来的,我分析了下uip_buf的结构发现前40字节好像是头信息,现在就是搞不明白这40字节里面那几个字节是数据长度的信息,希望指点下,这40个字节是如何分布的。我看了IP TCP协议,但是还是没有弄明白啊··
 楼主| kaly_liu 发表于 2013-5-22 10:51 | 显示全部楼层
huangxz 发表于 2013-5-20 19:23
改这一行
enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);

麻烦有空帮看看8#的问题啊~~:)
谢谢~~~~
xyz769 发表于 2013-5-22 16:25 | 显示全部楼层
kaly_liu 发表于 2013-5-22 10:29
请问这一段代码表示什么意思啊,主要是那个if···

如果有上层数据,则先发送包头,再发送上层数据,否则,直接发送包头。
这段代码与上层有关联,要结合上层去看。。

评分

参与人数 1威望 +1 收起 理由
kaly_liu + 1

查看全部评分

 楼主| kaly_liu 发表于 2013-5-22 16:45 | 显示全部楼层
本帖最后由 kaly_liu 于 2013-5-23 10:40 编辑

当接收到TCP数据,执行如下的代码,将受到的TCP数据发回去。
void example0_app(void)
{
       u16_ti;//
if(uip_connected()){
printu("example0 is connected!\r\n");
       }
       if(uip_newdata()|| uip_rexmit()) {
              printu("example0is uip_newdata!\r\n");      
              for(i=0;i<uip_len;i++)   {
                     printuf("%c",uip_appdata);       //输出字符串
              }
           if(uip_appdata[0]=='C'){
              uip_send(&uip_appdata[0],uip_len);
}
}
}

我在enc28j60.c的程序中,将驱动添加了如下的红色代码,想如果收到数据的第二位是‘q’就把它换成‘x’然后再发回去的,但是我发现如果我输入数据”Cbcdefg”可以正确的返回的,但是如果我输入”Cqcdefg”就没有返回了,好像卡住了似得,需要重新断开TCP连接,然后再连上,才可以工作(但,还是不可以发送第二个是’q’的数据的)不知道问题出在哪里了?
void enc28j60PacketSend(u16_t len, u8_t*packet)
{
   // Set the write pointer to start of transmit buffer area
       enc28j60Write(EWRPTL,TXSTART_INIT);
   enc28j60Write(EWRPTH, TXSTART_INIT>>8);
   // Set the TXND pointer to correspond to the packet size given
       enc28j60Write(ETXNDL,(TXSTART_INIT+len));
   enc28j60Write(ETXNDH, (TXSTART_INIT+len)>>8);
       enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM,0, 0x00);

if( uip_len<= TOTAL_HEADER_LENGTH ){
              enc28j60WriteBuffer(len, packet);
    }
   else
   {   len -= TOTAL_HEADER_LENGTH;
       enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
             if(uip_appdata[1]=='q') uip_appdata[1]='x';
       enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
    }
       enc28j60WriteOp(ENC28J60_BIT_FIELD_SET,ECON1, ECON1_TXRTS);
}


我更新了,2#,的代码了··
TCP服务器,ip192.168.1.14  端口是 8000
需要用TCP客户端连上去。开机后,小等一下再连。

客户端TCP发送 “C.......”的数据就会返回元数据,但是当客户端发送“Cq........”数据后,就没有返回了,卡住了好像·················额··············
 楼主| kaly_liu 发表于 2013-5-22 16:46 | 显示全部楼层
我就改了一个字符,这个数据的类型、长度什么的都没变,应该是可以发送回来的啊,是什么原因呢?
 楼主| kaly_liu 发表于 2013-5-24 08:41 | 显示全部楼层
本帖最后由 kaly_liu 于 2013-5-24 12:01 编辑


改了这个,也不行哦~~~~我分析的结果是:uip_buf的第12 13 是length;16 17 是TCP的length。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| kaly_liu 发表于 2013-5-24 09:41 | 显示全部楼层
xyz769 发表于 2013-5-22 16:25
如果有上层数据,则先发送包头,再发送上层数据,否则,直接发送包头。
这段代码与上层有关联,要结合上 ...

首先是我的 11#问题要麻烦您看看,我目前还没解决啊。
其次是我另外改了下程序:如果收到一串数据,那么就在程序中将这段数据复制下,然后将这两串数据写入发送缓冲区,再一次性发送出去,结果还是不行···我实在是不知道哪里还可以改了,球指教啊!第二个我修改的代码如下,我把程序改为了三步,第一步写入长度初始化发送缓冲区,并修改数据包头里的长度信息;第二步写入数据,根据数据长度写入数据的头和数据包;第三部发送数据;具体代码如下:

  1. void dev_send(void)
  2. {
  3.   if(uip_appdata[1]=='q')
  4.    {
  5.     uip_len=(uip_len - TOTAL_HEADER_LENGTH)*2;
  6.     uip_buf[17]=uip_len>>8;
  7.     uip_buf[18]=uip_len;
  8.    }
  9. enc28j60Packet_len(uip_len);
  10. enc28j60Packet_data(uip_len, uip_buf);
  11. enc28j60Packet_Send();
  12. }
  1. void enc28j60Packet_data(u16_t len,u8_t* packet)
  2. { if( uip_len <= TOTAL_HEADER_LENGTH )
  3.     {
  4.      enc28j60WriteBuffer(len, packet);
  5.     }
  6.     else
  7.     {  len -= TOTAL_HEADER_LENGTH;
  8. enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
  9.           if(uip_appdata[1]=='q')
  10.                 {
  11.                 len=len/2;
  12.                enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
  13.                enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
  14.                 }
  15.            else       
  16.               enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
  17.     }
  18. }
 楼主| kaly_liu 发表于 2013-5-24 12:00 | 显示全部楼层

改了这个,也不行哦~~~~我分析的结果是:uip_buf的第12 13 是length;16 17 是TCP的length。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
xyz769 发表于 2013-5-25 15:15 | 显示全部楼层
稍微看了一遍你的代码,感觉不会出现你11#描述的情况。。你尝试跟踪一下看看吧。。。
 楼主| kaly_liu 发表于 2013-5-27 08:38 | 显示全部楼层
本帖最后由 kaly_liu 于 2013-5-27 09:38 编辑

虽然还是没有解决,但是还是先谢谢各位的热心帮助啊~~~本帖继续等待解答啊~~~~


1.我在example0.c中的代码,判断如果收到的是'C'那么就会调用一次 uip_send()我看了那个uip_send函数就是把数据、长度这两个的值赋给uip_appdata、以及uip_len。这个时候是如何进行发送的呢?程序跑到哪里去了呢??是怎么执行的??
xyz769 发表于 2013-5-27 22:05 | 显示全部楼层
你看看UIP的代码,如果有数据要发送,UIP会自动填充各层包头,将数据发送出去的。
 楼主| kaly_liu 发表于 2013-5-28 11:15 | 显示全部楼层
最后发送数据肯定会调用dev_send()所以我想在网卡驱动里面改了··可惜不行哦··,说不定是在修改数据的时候单片机的RAM被用光了,导致跑飞了···纯属自己的猜测额····还是自己在琢磨琢磨!!
 楼主| kaly_liu 发表于 2013-5-28 11:17 | 显示全部楼层
问题还是没解决哦,先结贴了吧···
您需要登录后才可以回帖 登录 | 注册

本版积分规则

23

主题

344

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部