本帖最后由 湛只为无双 于 2015-2-23 11:29 编辑
三、W5500的相关配置: W5500的配置主要包括了对SOCKET中FIFO的SIZE设置,在这里采用了EmbedNet论坛中所给出的默认配置,即八个SOCKET的收发缓冲全为2KB。具体设置如下:
uint8_t memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
/* SOCKET缓冲的初始化——使用了memsize中的数据进行发送接收缓冲的初始化 */
if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1)
{
printf("WIZCHIP Initialized fail.\r\n");
while(1);
}
第二步是对PHY连接状态的初始化,等待PHY连接成功:
/* PHY的链接状态初始化 */
do
{
if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
{
printf("Unknown PHY Link stauts.\r\n");
}
}
while(tmp == PHY_LINK_OFF);
第三步是对本机的设置,包括了本机的MAC,本机的IP、网关、子网掩码、DNS服务器和DHCP状态:
wiz_NetInfo gNETINFO = { .mac = {0x01, 0x23, 0x45,0x67, 0x89, 0xab},
.ip = {192, 168, 2, 123},
.sn = {255,255,255,0},
.gw = {192, 168, 2, 1},
.dns = {0,0,0,0},
.dhcp = NETINFO_STATIC
};
/* 网口的初始化 包括了MAC 本机IP 网关 子网掩码 DNS服务器 和 DHCP状态 */
do
{
if(network_init() == 0)
{
printf("Net is OK\r\n");
break;
}
else
{
printf("Net is Error\r\n");
}
delay_ms(500);
}while(1);
//当初始换这个后,如果没有错误,实际上就已经可以PING通了
在这个里面的network_init函数如下:
在此可以判断W5500是否已经连接上了:
u8 network_init(void)
{
wiz_NetInfo lNETINFO={0};
uint8_t *plNETINFO,*pgNETINFO,i;
ctlnetwork(CN_SET_NETINFO, (void*)&gNETINFO);
ctlnetwork(CN_GET_NETINFO, (void*)&lNETINFO);
plNETINFO=(uint8_t*)&lNETINFO;
pgNETINFO=(uint8_t*)&gNETINFO;
for(i=0;i<sizeof(gNETINFO);i++)
{
if(*plNETINFO != *pgNETINFO)
{
return 1;
}
plNETINFO++;
pgNETINFO++;
}
}
//当有W5500正常将会返回0,否则返回1。
第四步是可选设置,设置溢出时间和最大重发次数:
setRTR(2000);//设置溢出时间值
setRCR(3);//设置最大重新发送的次数
到了这里W5500的相关配置已经配置完成了,可以通过PING来查看配置是否成功,如图一所示。
如果能够到了这里,说明网络的连接已经完成了,总体的任务完成了一半。
四、W5500的UDP设置:
UDP的设置如下,是使用了状态机的形式: while(1)
{
if( (ret = udp_ds18b20(SOCK_UDPS, gDATABUF, 3000)) < 0)
{
printf("SOCKET ERROR : %ld\r\n", ret);
}
}
int32_t udp_ds18b20(uint8_t sn, uint8_t* buf, uint16_t port)
{
int32_t ret;
uint16_t size;
uint8_t destip[4];
uint16_t destport;
switch(getSn_SR(sn))
{
case SOCK_UDP :
if((size = getSn_RX_RSR(sn)) > 0)
{
if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
ret = recvfrom(sn,buf,size,destip,(uint16_t*)&destport);
if(ret <= 0)
{
printf("%d: recvfrom error. %ld\r\n",sn,ret);
return ret;
}
size = (uint16_t) ret;
sentsize = 0;
//sprintf((char*)buf,"DS18B20:%.1f℃\r\n",DS18B20_Get_Temp());
sprintf((char*)buf,"%.1f\r\n",DS18B20_Get_Temp());
ret = sendto(sn,buf,strlen((char*)buf),destip,destport);
if(ret < 0)
{
printf("%d: sendto error. %ld\r\n",sn,ret);
return ret;
}
}
break;
case SOCK_CLOSED:
printf("W5500 UDP%d:Start\r\n",sn);
if((ret=socket(sn,Sn_MR_UDP,port,0x00)) != sn)
return ret;
printf("W5500 UDP%d:Opened, port [%d]\r\n",sn, port);
break;
default :
break;
}
return 1;
}
在这个里面,在最开始的时候是出于SOCK_CLOSED状态,进行了SOCKET模式的设置,和W5500的SOCKET端口号设置,通过串口会打印出相关的信息,包括了配置成功和失败的原因。 通过串口调试助手上电后可以看到如下信息,如图二所示。
通过图二可以看出对W5500所设置的MAC地址、本机IP地址SIP、网关GAR、子网掩码SUB和DNS;然后通过读取设置,并与原设置进行比较来判断出来网络是否配置成功。
接着就是开始了W5500的UDP,并显示使用的是端口1,如果UDP开启成功后会打印出相关信息和端口号,由图二可以得出端口号为3000。
五、实验现象和结论: 最后就是当通过电脑的UDP向端口发送了任何信息,就向相对应的IP端口返回当前的温度值,这是为了使任何电脑都能够与此相连,并获得温度值所设计的,具体的现象如图三所示。
通过图三可以看出循环发送数据后可以返回相对应的温度值,在此可以查看温度传感器DS18B20的灵敏度,通过将数据复制到MATLAB中进行绘图,得到了如下结果,如图四。 通过图四可以看出第一次用手稍微碰到DS18B20后温度迅速上升,当手指离开后温度缓慢下降,接着再次用手指一直捏着传感器,温度开始迅速的上升,一直到了顶峰22度后停止,中间手指稍微松了一下后温度稍有下降,手指离开后温度显示迅速下降一段时间后缓慢下降,这是与周围的环境温度有关的;在最后温度下降太慢了,向传感器吹气使其温度下降也是能够查看出这个细节。总之,通过本设计,可以实现温度的远程监测,并对外界微小的温度变化进行捕捉,并且具有成本控制较好,软件编程简单等特点。
六、附录——DS18B20程序:
在本次设计中,使用了ALIENTEK正点原子所出的探索者STM32F407开发板中的DS18B20程序源码,再次提出感谢。在使用过程中,处于接口的设计,更改了所使用的端口和端口的配置,以及获取温度的部分源码。
①:其中端口由原来的PG9更改为了PB9,端口的更改如下: 将ds18b20.h中的IO端口操作由原来的: //IO方向设置
#define DS18B20_IO_IN() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=0<<9*2;} //PG9输入模式
#define DS18B20_IO_OUT() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=1<<9*2;} //PG9输出模式
////IO操作函数
#define DS18B20_DQ_OUT PGout(9) //数据端口 PG9
#define DS18B20_DQ_IN PGin(9) //数据端口 PG9
改为了:
//IO方向设置
#define DS18B20_IO_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式
#define DS18B20_IO_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
////IO操作函数
#define DS18B20_DQ_OUT PBout(9) //数据端口 PB9
#define DS18B20_DQ_IN PBin(9) //数据端口 PB9
②:将ds18b20.c中的端口初始化由原来的:
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟
//GPIOG9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
DS18B20_Rst();
return DS18B20_Check();
}
更改为了: //初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
//GPIOB9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
DS18B20_Rst();
return DS18B20_Check();
}
③最后是获取温度的操作,为了能够很好的还原所得到的原始温度,将原来的获取温度函数返回值由整形更改为了浮点型: 具体的操作是由原来的:
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}
else temp=1; //温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得底八位
tem=(double)tem*0.625;//转换
if(temp)return tem; //返回温度值
else return -tem;
}
更改为了:
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
float DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//温度为负
}
else temp=1; //温度为正
tem=TH; //获得高八位
tem<<=8;
tem+=TL;//获得低八位
if(temp)return (double)tem*0.0625; //返回温度值
else return -(double)tem*0.0625;
}
并记得更改相对应的ds18b20.h中的函数声明。 short DS18B20_Get_Temp(void); //获取温度
改为: float DS18B20_Get_Temp(void); //获取温度
七、感谢:
在本次设计中,一个人的力量是远远不够的,非常感谢网络上论坛背后那些默默付出的人们,本次设计中参考了EmbedNet论坛飞鸿踏雪所提供的移植教程和相关W5500底层驱动的网络链接,在DS18B20的程序中,使用了ALIENTEK正点原子所出的探索者STM32F407开发板中相关源码,再次对以上两位提出由衷的感谢,特此提出。 最后,感谢21ic网提供的STM32F411RET6的NUCLEO板卡,同样也感谢在寄板卡过程中付出的每一位工作人员,能够有这次机会和广大网友就行分享相关的知识。
|