1.W5500简介
W5500 是一款全硬件 TCP/IP 嵌入式以太网控制器,为嵌入式系统提供了更加简易的互联网连接方案。 W5500 集成了 TCP/IP 协议栈, 10/100M 以太网数据链路层(MAC)及物理层(PHY) ,使得用户使用单芯片就能够在他们的应用中拓展网络连接。
久经市场考验的 WIZnet 全硬件 TCP/IP 协议栈支TCP,UDP,IPv4,ICMP,ARP,IGMP 以及 PPPoE 协议。 W5500 内嵌 32K 字节片上缓存以供以太网包处理。如果你使用 W5500,你只需要一些简单的 Socket 编程就能实现以太网应用。这将会比其他嵌入式以太网方案更加快捷、简便。用户可以同时使用 8 个硬件 Socket 独立通讯。
W5500 提供了 SPI(外设串行接口)从而能够更加容易与外设 MCU 整合。而且,W5500 的使用了新的高效 SPI 协议支持 80MHz 速率,从而能够更好的实现高速网络通讯。为了减少系统能耗, W5500 提供了网络唤醒模式(WOL)及掉电模式供客户选择使用。
2.W5500动态获取IP
硬件开发平台:STM32F103C8T6
驱动协议:SPI
开发环境:KEIL5
2.1 接线方式
W5500模块 | STM32核心板 |
片选CS | PB12 |
时钟SCLK | PB13 |
主机输入MISO | PB14 |
主机输出MOSI | PB15 |
INT | PB0 |
RST | PB1 |
2.2 SPI底层接口函数
SPI 协议定义了四种工作模式(模式 0, 1 , 2, 3)。每种模式的区别是根据 SCLK的极性及相位不同定义的。 SPI 的模式 0 和模式 3 唯一不同的就是在非活动状态下,SCLK 信号的极性。
SPI 的模式 0 和 3,数据都是在 SCLK 的上升沿锁存,在下降沿输出。
W5500 支持 SPI 模式 0 及模式 3.MOSI 和 MISO 信号无论是接收或发送,均遵从从最高标志位(MSB)到最低标志位(LSB)的传输序列。
/*硬件配置*/
void W5500_GPIO_Init(void)
{
RCC->APB2ENR|=1<<3;
GPIOB->CRH&=0x0000FFFF;
GPIOB->CRH|=0x38330000;
GPIOB->CRL&=0xFFFFFF00;
GPIOB->CRL|=0x00000038;
W5500_CS=1;
W5500_RST=1;
}
/*SPI读写一个字节*/
u8 SPI_WR_Byte(u8 byte)
{
u8 data_rx=0;
u8 i=0;
for(i=0;i<8;i++)
{
W5500_SCLK=0;
if(byte&0x80)W5500_MOSI=1;
else W5500_MOSI=0;
W5500_SCLK=1;
byte<<=1;
data_rx<<=1;
if(W5500_MISO)data_rx|=0x01;
}
W5500_SCLK=0;
return data_rx;
}
2.3 W5500动态IP获取
/*配置W5500网卡信息*/
void set_w5500_ip(void)
{
/*复制定义的配置信息到配置结构体*/
memcpy(ConfigMsg.mac, mac, 6);//MAC地址
memcpy(ConfigMsg.lip,local_ip,4);//IP
memcpy(ConfigMsg.sub,subnet,4);//子网掩码
memcpy(ConfigMsg.gw,gateway,4);//网关
memcpy(ConfigMsg.dns,dns_server,4);//DNS
if(ip_from == IP_FROM_DHCP)/*动态获取IP*/
{
if(dhcp_ok==1)/*动态获取IP成功*/
{
printf(" IP from DHCP\r\n");
memcpy(ConfigMsg.lip,DHCP_GET.lip, 4);
memcpy(ConfigMsg.sub,DHCP_GET.sub, 4);
memcpy(ConfigMsg.gw,DHCP_GET.gw, 4);
memcpy(ConfigMsg.dns,DHCP_GET.dns,4);
}
}
/*将IP配置信息写入W5500相应寄存器*/
setSUBR(ConfigMsg.sub);
setGAR(ConfigMsg.gw);
setSIPR(ConfigMsg.lip);
/*判断数据是否写入成功*/
getSIPR (local_ip);
printf(" W5500 IP地址 : %d.%d.%d.%d\r\n", local_ip[0],local_ip[1],local_ip[2],local_ip[3]);
getSUBR(subnet);
printf(" W5500 子网掩码 : %d.%d.%d.%d\r\n", subnet[0],subnet[1],subnet[2],subnet[3]);
getGAR(gateway);
printf(" W5500 网关 : %d.%d.%d.%d\r\n", gateway[0],gateway[1],gateway[2],gateway[3]);
}
//配置W5500的MAC地址
void set_w5500_mac(void)
{
memcpy(ConfigMsg.mac, mac, 6);
setSHAR(ConfigMsg.mac);
memcpy(DHCP_GET.mac, mac, 6);
}
2.4效果展示
3.W5500物联网平台连接
#include "stm32f10x.h"
#include "usart.h"
#include "timer.h"
#include "aliyun_mqtt.h"
/*w5500相关头文件*/
#include "w5500api.h"
#include "dhcp.h"
#include "dns.h"
#define SERVER_IP "LA57WTHWL6.iotcloud.tencentdevices.com"//服务器IP
#define SERVER_PORT 1883 //端口号
//客户端ID:{产品ID}{设备名}
#define ClientID "LA57WTHWL6Smart_home"
//用户名和密码可使用密码生成工具完成
#define Username "LA57WTHWL2Smart_home;120310126;HK8V9;1635948714"
#define Password "2a915cae4489b591ce556e71f4e9f1ka21c354a37d12fee7c46f56abee1f048a;hmacsha256"//密文
//订阅题:$thing/down/property/{ProductID}/{DeviceName} ---{ProductID}产品ID,{DeviceName}设备名
#define SET_TOPIC "$thing/down/property/Lb57WTHWL3/Smart_home"//订阅
//发布主题:$thing/up/property/{ProductID}/{DeviceName}
#define POST_TOPIC "$thing/up/property/Lb57WTHWL3/Smart_home"//发布
char mqtt_message[200];//上报数据缓存区
u8 rx_buff[200];
void init_Net(void)
{
u8 try_times=0;
init_W5500();/*W5500初始化*/
init_dhcp_client();//动态分配IP
while(check_DHCP_state(SOCK_DHCP)!=DHCP_RET_UPDATE)
{
try_times++;
if(try_times==255)//超时 重启芯片
{
Reset_W5500();
init_dhcp_client();
try_times=0;
}
delay_ms(10);
}
while(!set_Network());
/*判断数据是否写入成功*/
u8 ipaddr[4];//ip地址
u8 subnet[4];//子网掩码
u8 gateway[4];//网关
getSIPR (ipaddr);
printf(" W5500 IP地址 : %d.%d.%d.%d\r\n", ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);
getSUBR(subnet);
printf(" W5500 子网掩码 : %d.%d.%d.%d\r\n", subnet[0],subnet[1],subnet[2],subnet[3]);
getGAR(gateway);
printf(" W5500 网关 : %d.%d.%d.%d\r\n", gateway[0],gateway[1],gateway[2],gateway[3]);
}
/*连接服务器*/
uint8 TCP_Connect(SOCKET Socket,uint8 *sip,uint16 sport,uint16 lport)
{
static uint8 CONNECT_FLAG = 0;
switch(getSn_SR(Socket))
{
case SOCK_INIT:
CONNECT_FLAG=connect(Socket,sip,sport);/*连接服务器*/
break;
case SOCK_CLOSE_WAIT:
disconnect(Socket);
close(Socket);
break;
case SOCK_CLOSED:
CONNECT_FLAG=0;
socket(Socket,Sn_MR_TCP,lport,Sn_MR_ND);
break;
}
return CONNECT_FLAG;
}
int main()
{
u16 i=0;
u8 stat=0;
u16 time=0,cnt=0;
float temp=10;
u16 rlen;
USART1_Init(115200);
printf("W5500 SPI模拟时序寄存器版,连接腾讯云VER1.0 \r\n");
init_Net();/*W5500硬件初始化,动态分配IP*/
printf("W5500 硬件初始化成功\r\n");
while(!do_dns((u8 *)SERVER_IP)){}/*域名解析*/
while(1)
{
stat=TCP_Connect(MQTT_SOCK,NET_CONFIG.rip,1883,5500);/*连接服务器*/
printf("stat=%d\r\n",stat);
if(stat)break;
delay_ms(1000);
}
printf("腾讯物联网平台连接中....\n");
while(1)
{
if(getSn_SR(MQTT_SOCK)==SOCK_ESTABLISHED)
{
if(getSn_IR(MQTT_SOCK)&Sn_IR_CON)
{
setSn_IR(MQTT_SOCK,Sn_IR_CON);
}
MQTT_Init();
if(MQTT_Connect(ClientID,Username,Password)==0)
{
printf("腾讯云平台连接成功\r\n");
break;
}
}
}
stat=MQTT_SubscribeTopic(SET_TOPIC,0,1);
if(stat)printf("订阅失败\r\n");
while(1)
{
/*接收数据*/
rlen=getSn_RX_RSR(MQTT_SOCK);
if(rlen>0)
{
rlen=recv(MQTT_SOCK,rx_buff,rlen);
printf("len=%d\r\n",rlen);
for(i=0;i<rlen;i++)
{
printf("%c",rx_buff[i]);
}
}
delay_ms(1);
time++;
cnt++;
if(time>=5000)
{
time=0;
MQTT_SentHeart();//发送心跳包
}
if(cnt>=2000)
{
temp+=1.5;
if(temp>=85)temp=-15;
cnt=0;
sprintf(mqtt_message,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"LED1\":1,\"temp\":%.2f,\"L\":356}}",temp);//温度
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
}
}
}