[STM32F4] 【Nucleo设计分享】基于411RET6板卡的W5500网络UDP温度传输_申酷

[复制链接]
4390|21
湛只为无双 发表于 2015-2-23 11:06 | 显示全部楼层 |阅读模式
本帖最后由 湛只为无双 于 2015-2-23 11:33 编辑



W5500_UDP_DS18B20调试笔记


本次设计中主要涉及了对W5500的底层操作,以及怎样进行UDP连接,TCPService连接和TCPClient连接三种常用的传输层协议。根据以前所写的程序,由于TCP连接是可靠的连接,需要三次握手释放的时候需要再次进行释放,底层的不可靠,导致了TCP进行连接后无法进行第二次连接,这是一个BUG,而且查阅了很多资料都没有一个良好的解决方法,通过这次查阅资料和查看别人的程序,无意中成功了,可以随时进行连接和断开,并且不会出现死机的情况。


具体的更改方法如下:


一、源码的移植:


首先是进行底层驱动的移植,这里参考了EmbedNet论坛飞鸿踏雪的移植教程,并把其中不需要的部分给去除了(原网页—— http://www.embed-net.com/thread-55-1-1.html)。接着是下载http://wizwiki.net/wiki/doku.php?id=products:w5500:driver网站下的驱动源码,添加进入工程后需要更改所下载源码的四个地方,分别是片选确定,片选取消,SPI读函数以及SPI写函数,具体如下:
wizchip_config.c中的_WIZCHIP结构体由:
  1. _WIZCHIP  WIZCHIP =
  2. {
  3.         .id                  = _WIZCHIP_ID_,
  4.         .if_mode             = _WIZCHIP_IO_MODE_,
  5.         .CRIS._enter         = wizchip_cris_enter,
  6.         .CRIS._exit          = wizchip_cris_exit,
  7.         .CS._select          = wizchip_cs_select,
  8.         .CS._deselect        = wizchip_cs_deselect,
  9.     .IF.BUS._read_byte   = wizchip_bus_readbyte,
  10.     .IF.BUS._write_byte  = wizchip_bus_writebyte
  11. //        .IF.SPI._read_byte   = wizchip_spi_readbyte,
  12. //        .IF.SPI._write_byte  = wizchip_spi_writebyte
  13. };
改为:

  1. _WIZCHIP  WIZCHIP =
  2. {
  3.         .id                  = _WIZCHIP_ID_,
  4.         .if_mode             = _WIZCHIP_IO_MODE_,
  5.         .CRIS._enter         = wizchip_cris_enter,
  6.         .CRIS._exit          = wizchip_cris_exit,
  7.         .CS._select          = wizchip_cs_select,
  8.         .CS._deselect        = wizchip_cs_deselect,
  9. //    .IF.BUS._read_byte   = wizchip_bus_readbyte,
  10. //    .IF.BUS._write_byte  = wizchip_bus_writebyte
  11.         .IF.SPI._read_byte   = wizchip_spi_readbyte,
  12.         .IF.SPI._write_byte  = wizchip_spi_writebyte
  13. };

也就是注释掉IF.BUS,使用IF.SPI接口,然后更改void  wizchip_cs_select(void)函数中的内容和void wizchip_cs_deselect(void)函数中的内容如下:

  1. void wizchip_cs_select(void)
  2. {
  3.         GPIO_ResetBits(GPIOB,GPIO_Pin_6);
  4. };

  5. void wizchip_cs_deselect(void)
  6. {
  7.         GPIO_SetBits(GPIOB,GPIO_Pin_6);
  8. };

     这里使用你打算使用的片选信号的拉高和拉低;然后是SPI接口的读写
SPI读函数:
  1. uint8_t wizchip_spi_readbyte(void)
  2. {
  3.         return SPI1_ReadWriteByte(0xff);
  4. }

    和SPI写函数:
  1. void wizchip_spi_writebyte(uint8_t wb)
  2. {
  3.         SPI1_ReadWriteByte(wb);
  4. }




当你把这些都完成了以后,就可以使用W5500的移植了。


二、接口的初始化操作:


接口的初始化主要包括了对SPI1的模式设置,以及开启SPI1,还有就是GPIO接口模式的初始化,以及片选的设置。
SPI的初始化:
  1. void SPI1_Init(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         SPI_InitTypeDef  SPI_InitStructure;
  5.         static int SPI1_InitFlag=0;
  6.         
  7.         if(SPI1_InitFlag == 0)
  8.         {
  9.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  10.                 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE);
  11.                
  12.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
  13.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
  14.                 GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
  15.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  16.                 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  17.                 GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
  18.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  19.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  20.                 GPIO_Init(GPIOA, &GPIO_InitStructure);
  21.                
  22.                 SPI_I2S_DeInit(SPI1);
  23.                 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工
  24.                 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位数据模式
  25.                 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//空闲模式下SCK为1
  26.                 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据采样从第2个时间边沿开始
  27.                 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS软件管理
  28.                 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//波特率
  29.                 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//大端模式
  30.                 SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC多项式
  31.                 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主机模式
  32.                 SPI_Init(SPI1, &SPI_InitStructure);
  33.                 SPI_Cmd(SPI1, ENABLE);
  34.                 SPI1_InitFlag=1;
  35.         }
  36. }

片选的初始化:
  1. void SPI1_CS2Pin_Init(void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         
  5.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
  6.         
  7.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//NET_CS:PB6
  8.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  9.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  10.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  12.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  13.         GPIO_SetBits(GPIOB, GPIO_Pin_6);//不选中
  14. }






 楼主| 湛只为无双 发表于 2015-2-23 11:06 | 显示全部楼层
本帖最后由 湛只为无双 于 2015-2-23 11:29 编辑



三、W5500的相关配置:
W5500的配置主要包括了对SOCKETFIFOSIZE设置,在这里采用了EmbedNet论坛中所给出的默认配置,即八个SOCKET的收发缓冲全为2KB。具体设置如下:
  1. uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
  2. /* SOCKET缓冲的初始化——使用了memsize中的数据进行发送接收缓冲的初始化 */
  3. if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1)
  4. {
  5.         printf("WIZCHIP Initialized fail.\r\n");
  6.         while(1);
  7. }




第二步是对PHY连接状态的初始化,等待PHY连接成功:
  1. /* PHY的链接状态初始化 */
  2. do
  3. {
  4.         if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
  5.         {
  6.                 printf("Unknown PHY Link stauts.\r\n");
  7.         }
  8. }
  9. while(tmp == PHY_LINK_OFF);


第三步是对本机的设置,包括了本机的MAC,本机的IP、网关、子网掩码、DNS服务器和DHCP状态:
  1. wiz_NetInfo gNETINFO = { .mac = {0x01, 0x23, 0x45,0x67, 0x89, 0xab},
  2.                          .ip = {192, 168, 2, 123},
  3.                          .sn = {255,255,255,0},
  4.                          .gw = {192, 168, 2, 1},
  5.                          .dns = {0,0,0,0},
  6.                          .dhcp = NETINFO_STATIC
  7.                         };
  8. /* 网口的初始化 包括了MAC 本机IP 网关 子网掩码 DNS服务器 和 DHCP状态  */
  9. do
  10. {
  11.         if(network_init() == 0)
  12.         {
  13.                 printf("Net is OK\r\n");
  14.                 break;
  15.         }
  16.         else
  17.         {
  18.                 printf("Net is Error\r\n");
  19.         }
  20.         delay_ms(500);
  21. }while(1);
  22. //当初始换这个后,如果没有错误,实际上就已经可以PING通了



在这个里面的network_init函数如下:
在此可以判断W5500是否已经连接上了:


  1. u8 network_init(void)
  2. {
  3.         wiz_NetInfo lNETINFO={0};
  4.         uint8_t *plNETINFO,*pgNETINFO,i;
  5.         
  6.         ctlnetwork(CN_SET_NETINFO, (void*)&gNETINFO);
  7.         ctlnetwork(CN_GET_NETINFO, (void*)&lNETINFO);
  8.         
  9.         plNETINFO=(uint8_t*)&lNETINFO;
  10.         pgNETINFO=(uint8_t*)&gNETINFO;
  11.         
  12.         for(i=0;i<sizeof(gNETINFO);i++)
  13.         {
  14.                 if(*plNETINFO != *pgNETINFO)
  15.                 {
  16.                         return 1;
  17.                 }
  18.                 plNETINFO++;
  19.                 pgNETINFO++;
  20.         }
  21. }
  22. //当有W5500正常将会返回0,否则返回1。
第四步是可选设置,设置溢出时间和最大重发次数:

  1. setRTR(2000);//设置溢出时间值
  2. setRCR(3);//设置最大重新发送的次数


到了这里W5500的相关配置已经配置完成了,可以通过PING来查看配置是否成功,如图一所示。



如果能够到了这里,说明网络的连接已经完成了,总体的任务完成了一半。


四、W5500UDP设置:


UDP的设置如下,是使用了状态机的形式:
  1. while(1)
  2. {
  3.         if( (ret = udp_ds18b20(SOCK_UDPS, gDATABUF, 3000)) < 0)
  4.         {
  5.                 printf("SOCKET ERROR : %ld\r\n", ret);
  6.         }
  7. }

  8. int32_t udp_ds18b20(uint8_t sn, uint8_t* buf, uint16_t port)
  9. {
  10.         int32_t  ret;
  11.         uint16_t size;
  12.         uint8_t  destip[4];
  13.         uint16_t destport;
  14.         
  15.         switch(getSn_SR(sn))
  16.         {
  17.         case SOCK_UDP :
  18.                 if((size = getSn_RX_RSR(sn)) > 0)
  19.                 {
  20.                         if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
  21.                         ret = recvfrom(sn,buf,size,destip,(uint16_t*)&destport);
  22.                         if(ret <= 0)
  23.                         {
  24.                                 printf("%d: recvfrom error. %ld\r\n",sn,ret);
  25.                                 return ret;
  26.                         }
  27.                         size = (uint16_t) ret;
  28.                         sentsize = 0;
  29.                         //sprintf((char*)buf,"DS18B20:%.1f℃\r\n",DS18B20_Get_Temp());
  30.                         sprintf((char*)buf,"%.1f\r\n",DS18B20_Get_Temp());
  31.                         ret = sendto(sn,buf,strlen((char*)buf),destip,destport);
  32.                         if(ret < 0)
  33.                         {
  34.                                 printf("%d: sendto error. %ld\r\n",sn,ret);
  35.                                 return ret;
  36.                         }
  37.                 }
  38.                 break;
  39.         case SOCK_CLOSED:
  40.                 printf("W5500 UDP%d:Start\r\n",sn);
  41.                 if((ret=socket(sn,Sn_MR_UDP,port,0x00)) != sn)
  42.                         return ret;
  43.                 printf("W5500 UDP%d:Opened, port [%d]\r\n",sn, port);
  44.                 break;
  45.         default :
  46.                 break;
  47.         }
  48.         return 1;
  49. }




在这个里面,在最开始的时候是出于SOCK_CLOSED状态,进行了SOCKET模式的设置,和W5500SOCKET端口号设置,通过串口会打印出相关的信息,包括了配置成功和失败的原因。
通过串口调试助手上电后可以看到如下信息,如图二所示。



通过图二可以看出对W5500所设置的MAC地址、本机IP地址SIP、网关GAR、子网掩码SUBDNS;然后通过读取设置,并与原设置进行比较来判断出来网络是否配置成功。


接着就是开始了W5500UDP,并显示使用的是端口1,如果UDP开启成功后会打印出相关信息和端口号,由图二可以得出端口号为3000


五、实验现象和结论:
最后就是当通过电脑的UDP向端口发送了任何信息,就向相对应的IP端口返回当前的温度值,这是为了使任何电脑都能够与此相连,并获得温度值所设计的,具体的现象如图三所示。



通过图三可以看出循环发送数据后可以返回相对应的温度值,在此可以查看温度传感器DS18B20的灵敏度,通过将数据复制到MATLAB中进行绘图,得到了如下结果,如图四。
通过图四可以看出第一次用手稍微碰到DS18B20后温度迅速上升,当手指离开后温度缓慢下降,接着再次用手指一直捏着传感器,温度开始迅速的上升,一直到了顶峰22度后停止,中间手指稍微松了一下后温度稍有下降,手指离开后温度显示迅速下降一段时间后缓慢下降,这是与周围的环境温度有关的;在最后温度下降太慢了,向传感器吹气使其温度下降也是能够查看出这个细节。总之,通过本设计,可以实现温度的远程监测,并对外界微小的温度变化进行捕捉,并且具有成本控制较好,软件编程简单等特点。


六、附录——DS18B20程序:

在本次设计中,使用了ALIENTEK正点原子所出的探索者STM32F407开发板中的DS18B20程序源码,再次提出感谢。在使用过程中,处于接口的设计,更改了所使用的端口和端口的配置,以及获取温度的部分源码。

①:其中端口由原来的PG9更改为了PB9,端口的更改如下:
将ds18b20.h中的IO端口操作由原来的:
  1. //IO方向设置
  2. #define DS18B20_IO_IN()  {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=0<<9*2;}        //PG9输入模式
  3. #define DS18B20_IO_OUT() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=1<<9*2;}         //PG9输出模式

  4. ////IO操作函数                                                                                          
  5. #define        DS18B20_DQ_OUT PGout(9) //数据端口        PG9
  6. #define        DS18B20_DQ_IN  PGin(9)  //数据端口        PG9
改为了:
  1. //IO方向设置
  2. #define DS18B20_IO_IN()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}        //PB9输入模式
  3. #define DS18B20_IO_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}         //PB9输出模式

  4. ////IO操作函数
  5. #define        DS18B20_DQ_OUT PBout(9) //数据端口        PB9
  6. #define        DS18B20_DQ_IN  PBin(9)  //数据端口        PB9
②:将ds18b20.c中的端口初始化由原来的:
  1. //初始化DS18B20的IO口 DQ 同时检测DS的存在
  2. //返回1:不存在
  3. //返回0:存在
  4. u8 DS18B20_Init(void)
  5. {
  6.         GPIO_InitTypeDef  GPIO_InitStructure;

  7.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟

  8.         //GPIOG9
  9.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  10.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  11.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
  13.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  14.         GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化

  15.         DS18B20_Rst();
  16.         return DS18B20_Check();
  17. }

更改为了:
  1. //初始化DS18B20的IO口 DQ 同时检测DS的存在
  2. //返回1:不存在
  3. //返回0:存在
  4. u8 DS18B20_Init(void)
  5. {
  6.         GPIO_InitTypeDef  GPIO_InitStructure;

  7.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

  8.         //GPIOB9
  9.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  10.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  11.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
  13.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  14.         GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

  15.         DS18B20_Rst();
  16.         return DS18B20_Check();
  17. }


③最后是获取温度的操作,为了能够很好的还原所得到的原始温度,将原来的获取温度函数返回值由整形更改为了浮点型:
具体的操作是由原来的:
  1. //从ds18b20得到温度值
  2. //精度:0.1C
  3. //返回值:温度值 (-550~1250)
  4. short DS18B20_Get_Temp(void)
  5. {
  6.         u8 temp;
  7.         u8 TL,TH;
  8.         short tem;
  9.         DS18B20_Start ();                    // ds1820 start convert
  10.         DS18B20_Rst();
  11.         DS18B20_Check();
  12.         DS18B20_Write_Byte(0xcc);// skip rom
  13.         DS18B20_Write_Byte(0xbe);// convert
  14.         TL=DS18B20_Read_Byte(); // LSB
  15.         TH=DS18B20_Read_Byte(); // MSB
  16.         if(TH>7)
  17.         {
  18.                 TH=~TH;
  19.                 TL=~TL;
  20.                 temp=0;//温度为负
  21.         }
  22.         else temp=1; //温度为正
  23.         tem=TH; //获得高八位
  24.         tem<<=8;
  25.         tem+=TL;//获得底八位
  26.         tem=(double)tem*0.625;//转换
  27.         if(temp)return tem; //返回温度值
  28.         else return -tem;
  29. }

更改为了:

  1. //从ds18b20得到温度值
  2. //精度:0.1C
  3. //返回值:温度值 (-550~1250)
  4. float DS18B20_Get_Temp(void)
  5. {
  6.         u8 temp;
  7.         u8 TL,TH;
  8.         short tem;
  9.         DS18B20_Start ();                    // ds1820 start convert
  10.         DS18B20_Rst();
  11.         DS18B20_Check();
  12.         DS18B20_Write_Byte(0xcc);// skip rom
  13.         DS18B20_Write_Byte(0xbe);// convert
  14.         TL=DS18B20_Read_Byte(); // LSB
  15.         TH=DS18B20_Read_Byte(); // MSB
  16.         if(TH>7)
  17.         {
  18.                 TH=~TH;
  19.                 TL=~TL;
  20.                 temp=0;//温度为负
  21.         }
  22.         else temp=1; //温度为正
  23.         tem=TH; //获得高八位
  24.         tem<<=8;
  25.         tem+=TL;//获得低八位
  26.         if(temp)return (double)tem*0.0625; //返回温度值
  27.         else return -(double)tem*0.0625;
  28. }

并记得更改相对应的ds18b20.h中的函数声明。
  1. short DS18B20_Get_Temp(void);        //获取温度

改为:
  1. float DS18B20_Get_Temp(void);        //获取温度


七、感谢:


在本次设计中,一个人的力量是远远不够的,非常感谢网络上论坛背后那些默默付出的人们,本次设计中参考了EmbedNet论坛飞鸿踏雪所提供的移植教程和相关W5500底层驱动的网络链接,在DS18B20的程序中,使用了ALIENTEK正点原子所出的探索者STM32F407开发板中相关源码,再次对以上两位提出由衷的感谢,特此提出。
最后,感谢21ic网提供的STM32F411RET6的NUCLEO板卡,同样也感谢在寄板卡过程中付出的每一位工作人员,能够有这次机会和广大网友就行分享相关的知识。




















图一 W5500连接后PING通图示

图一 W5500连接后PING通图示

图二 串口返回的调试图示

图二 串口返回的调试图示

图三 网口UDP返回的温度信息

图三 网口UDP返回的温度信息

图四 数据导入至MATLAB后得到的图形

图四 数据导入至MATLAB后得到的图形
 楼主| 湛只为无双 发表于 2015-2-23 11:06 | 显示全部楼层
本帖最后由 湛只为无双 于 2015-2-23 11:32 编辑

老规矩 最后上传相关源码和数据

Nucleo411_W5500_UDP_DS18B20.zip

499.59 KB, 下载次数: 64

源代码以及内部包含了测得的数据的保存

 楼主| 湛只为无双 发表于 2015-2-23 11:18 | 显示全部楼层
本帖最后由 湛只为无双 于 2015-2-23 11:35 编辑

最后 是下一步的W5500上传数据至Yeelink,是下一篇帖子的内容,也是最后一步,做完了就算是完成了当初申请板子所填的申请要求。
另外,天冷了,恳求版主给个裤子穿穿:lol
人民币的幻想 发表于 2015-2-23 12:33 来自手机 | 显示全部楼层
俺感觉还可以,顶一个。咋不加个phy芯片试试?
 楼主| 湛只为无双 发表于 2015-2-23 13:21 来自手机 | 显示全部楼层
*币的幻想 发表于 2015-2-23 12:33
俺感觉还可以,顶一个。咋不加个phy芯片试试?

对于W5500已经有phy了,不用再加了,可以直接用。
zhjerry 发表于 2015-2-23 21:05 来自手机 | 显示全部楼层
407 or 411?
dong_abc 发表于 2015-2-24 10:37 来自手机 | 显示全部楼层
407,411没有集成以太网?
 楼主| 湛只为无双 发表于 2015-2-24 13:53 来自手机 | 显示全部楼层
dong_abc 发表于 2015-2-24 10:37
407,411没有集成以太网?

这个是外部的以太网,用spi接口来实现网络通信,就像enc28j60一样
沉默胜过白金 发表于 2015-2-24 14:49 | 显示全部楼层
keil5 一直用不惯,keil4 没有这个型号。。。
 楼主| 湛只为无双 发表于 2015-2-24 20:45 | 显示全部楼层
沉默胜过白金 发表于 2015-2-24 14:49
keil5 一直用不惯,keil4 没有这个型号。。。

那你是怎么给你收到的板子写程序的?  直接用网页的形式么?
tianhaolan 发表于 2015-2-25 14:25 | 显示全部楼层
不错不错
第三世界 发表于 2015-2-26 17:34 | 显示全部楼层
很详细啊,  就是不是很懂, 硬件怎么显示
powerful1 发表于 2015-2-26 21:39 | 显示全部楼层
很详细啊,谢谢分享
energy1 发表于 2015-2-26 22:59 | 显示全部楼层
不错的资料,很详细,谢谢分享
搞IT的 发表于 2015-2-28 18:30 | 显示全部楼层
由于TCP连接是可靠的连接,需要三次握手释放的时候需要再次进行释放。
ljl342301 发表于 2015-6-29 17:08 | 显示全部楼层
好东西,很详细,最近正在学
xiaopohaixx 发表于 2015-12-17 15:03 | 显示全部楼层
请教一下,UDP部分的内容,为何要做一个先接收再发送温度传感器的值呢,接收这部分的代码的作用是什么呢
sourceInsight 发表于 2015-12-17 15:37 来自手机 | 显示全部楼层
这么多代码,看上去真有点头疼啊!!!!
CallReceiver 发表于 2015-12-17 15:55 来自手机 | 显示全部楼层
不是很清楚源码的移植过程,学习学习了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

171

帖子

9

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