打印

ENC28J60 发送缓冲区的写入?

[复制链接]
5049|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kaly_liu|  楼主 | 2013-5-20 14:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 kaly_liu 于 2013-5-22 16:38 编辑

利用单片机和ENC28J60实现TCP数据发送,现在有个问题是数据太长,我是存在EEPROM的,直接读取,再发送回有问题,需要将数据分N次读出,然后存到ENC28J60的发送缓冲区,然后再一次性发送出去,我在驱动中试了改几下,不能实现,望有高人指教啊!下面是发送的程序。我是结合uip0.9进行的。
#define ETHERNET_MIN_PACKET_LENGTH        0x3C
#define ETHERNET_HEADER_LENGTH                0x0E
#define IP_TCP_HEADER_LENGTH 40
#define TOTAL_HEADER_LENGTH (IP_TCP_HEADER_LENGTH+ETHERNET_HEADER_LENGTH)
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);
    // write per-packet control byte
        enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
    // TODO, fix this up

    if( uip_len <= TOTAL_HEADER_LENGTH )
    {
        // copy the packet into the transmit buffer
                enc28j60WriteBuffer(len, packet);
    }
    else
    {
          len -= TOTAL_HEADER_LENGTH;
        enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
        enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
    }
        // Errata workaround #12, reset TX logic
    // send the contents of the transmit buffer onto the network
        enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
}


相关帖子

沙发
kaly_liu|  楼主 | 2013-5-20 15:58 | 只看该作者
本帖最后由 kaly_liu 于 2013-5-23 10:35 编辑

X uip_TCP服务器.zip (480.63 KB)
这是我的代码,这是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(...)里的长度,内容改了,那返回的信息和大程序中的会不会对不上,导致发送失败啊······
问题有点乱额·····

使用特权

评论回复
5
kaly_liu|  楼主 | 2013-5-21 08:55 | 只看该作者
本帖最后由 kaly_liu 于 2013-5-22 10:31 编辑

我想您说的要修改的函数应该是关键的,但是好像还有许多其他的地方需要修改的额···
关于IP和TCP头的格式的类型、数据长度、·····

使用特权

评论回复
6
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
7
kaly_liu|  楼主 | 2013-5-22 10:29 | 只看该作者
xyz769 发表于 2013-5-21 10:50
改驱动,将这一函数
void enc28j60PacketSend(u16_t len, u8_t* packet)
分解成三个函数,比如:

请问这一段代码表示什么意思啊,主要是那个if···
    if( uip_len <= TOTAL_HEADER_LENGTH )
    {
        // copy the packet into the transmit buffer
                enc28j60WriteBuffer(len, packet);
    }
    else
    {
          len -= TOTAL_HEADER_LENGTH;
        enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
        enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
    }

使用特权

评论回复
8
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协议,但是还是没有弄明白啊··

使用特权

评论回复
9
kaly_liu|  楼主 | 2013-5-22 10:51 | 只看该作者
huangxz 发表于 2013-5-20 19:23
改这一行
enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);

麻烦有空帮看看8#的问题啊~~:)
谢谢~~~~

使用特权

评论回复
10
xyz769| | 2013-5-22 16:25 | 只看该作者
kaly_liu 发表于 2013-5-22 10:29
请问这一段代码表示什么意思啊,主要是那个if···

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

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
kaly_liu + 1
11
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........”数据后,就没有返回了,卡住了好像·················额··············

使用特权

评论回复
12
kaly_liu|  楼主 | 2013-5-22 16:46 | 只看该作者
我就改了一个字符,这个数据的类型、长度什么的都没变,应该是可以发送回来的啊,是什么原因呢?

使用特权

评论回复
13
kaly_liu|  楼主 | 2013-5-24 08:41 | 只看该作者
本帖最后由 kaly_liu 于 2013-5-24 12:01 编辑


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

使用特权

评论回复
14
kaly_liu|  楼主 | 2013-5-24 09:41 | 只看该作者
xyz769 发表于 2013-5-22 16:25
如果有上层数据,则先发送包头,再发送上层数据,否则,直接发送包头。
这段代码与上层有关联,要结合上 ...

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

void dev_send(void)
{
  if(uip_appdata[1]=='q')
   {
    uip_len=(uip_len - TOTAL_HEADER_LENGTH)*2;
    uip_buf[17]=uip_len>>8;
    uip_buf[18]=uip_len;
   }
enc28j60Packet_len(uip_len);
enc28j60Packet_data(uip_len, uip_buf);
enc28j60Packet_Send();
}
void enc28j60Packet_data(u16_t len,u8_t* packet)
{ if( uip_len <= TOTAL_HEADER_LENGTH )
    {
     enc28j60WriteBuffer(len, packet);
    }
    else
    {  len -= TOTAL_HEADER_LENGTH;
enc28j60WriteBuffer(TOTAL_HEADER_LENGTH, packet);
          if(uip_appdata[1]=='q')
                {
                len=len/2;
               enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
               enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
                }
           else       
              enc28j60WriteBuffer(len, (unsigned char *)uip_appdata);
    }
}

使用特权

评论回复
15
kaly_liu|  楼主 | 2013-5-24 12:00 | 只看该作者

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

使用特权

评论回复
16
xyz769| | 2013-5-25 15:15 | 只看该作者
稍微看了一遍你的代码,感觉不会出现你11#描述的情况。。你尝试跟踪一下看看吧。。。

使用特权

评论回复
17
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。这个时候是如何进行发送的呢?程序跑到哪里去了呢??是怎么执行的??

使用特权

评论回复
18
xyz769| | 2013-5-27 22:05 | 只看该作者
你看看UIP的代码,如果有数据要发送,UIP会自动填充各层包头,将数据发送出去的。

使用特权

评论回复
19
kaly_liu|  楼主 | 2013-5-28 11:15 | 只看该作者
最后发送数据肯定会调用dev_send()所以我想在网卡驱动里面改了··可惜不行哦··,说不定是在修改数据的时候单片机的RAM被用光了,导致跑飞了···纯属自己的猜测额····还是自己在琢磨琢磨!!

使用特权

评论回复
20
kaly_liu|  楼主 | 2013-5-28 11:17 | 只看该作者
问题还是没解决哦,先结贴了吧···

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

23

主题

344

帖子

3

粉丝