ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

STM32+W5500网络通信

2021-12-28 09:06:01  阅读:254  来源: 互联网

标签:网络通信 ch http W5500 STM32 SPI InitStructure GPIO


目录

一.理论概述

  • W5500以太网模块介绍:

Niren_W5500模块是一款基于WIZnet W5500芯片的以太网模块,是泥人电子继 Niren_W5100模块后设计的一块性能更好、性价比更高的以太网模块。模块集成硬件化TCP/IP协议:内部32K字节存储器作TX/RX 缓存:支持10/100Mbps的传输速率;支持8个独立端口同时运行;同时模块还支持3.3V或5V电源供电,5V供电时还可以输出3.3V电源,方便用户在不同的单片机系统中使用;模块与单片机系统的通讯方式是简单、方便的SPI通信。

  • 模块排针功能表:
排针标识功能说明排针标识功能说明
3.3V3.3V电源输入引脚5V5V电源输入引脚
MISOSPI主机输入从机输出引脚GND电源地引脚
MOSISPI主机输出从机输入引脚RSTW5500硬件初始化引脚(低电平有效)
SCSSPI SLAVE选择引脚(低电平有效)INTW5500中断引脚(低电平有效)
SCLKSPI时钟引脚NC悬空
  • Modbus简介

Modbus是Modicon(施耐德)公司于1979年开发的串行通信协议。它最初设计用于公司的可编程逻辑控制器(PLC)。Modbus是一种开放式协议,支持使用RS232/RS485/RS422协议的串行设备,同时还支持调制解调器。它的简单性以及制造商可以免费将其纳入其产品的事实使其成为连接工业电子设备的最流行的方法。
Modbus比其他通信协议使用的更广泛的主要原因有以下几点:
公开发表并且无著作权要求;
易于部署和维护;
对供应商来说,修改移动本地的比特或字节没有很多限制;
Modbus通过设备之间的串行线进行数据传输。最简单的设置是使用一根串行电缆连接两个设备(主设备和从设备)上的串行端口。
数据以称为比特的1和0的序列发送。每个位都作为电压发送。0被发送为正电压,1被发送为负电压。

  • Modbus/TCP协议
功能码作用
01读取线圈状态
02读取输入状态
03读取保持寄存器
04读取输入寄存器
05强置单线圈
06预置单寄存器
07读取异常状态
08回送诊断校验
09编程(只用于484)
0A控询
0B读取事件计数
0C读取通信事件记录
0D编程(184/384/484/584等)
0E探寻
0F强置多线圈
10预置多线圈
11报告多寄存器
12可使主机模拟编程功能
13重置通信链路
14读取通用参数
15写入通用参数
16屏蔽写寄存器
17读/写多个寄存器

查询报文
00 6D 00 00 00 06 01 03 00 00 00 01
00 6D 查询编号
00 00 协议
00 06 数据包长度
01 设备编号
03 功能码
00 00 起始地址
00 01 查询寄存器个数

响应报文
00 6D 00 00 00 05 01 03 02 00 17
00 6D 查询编号
00 00 协议
00 05 数据包长度
01 设备地址
03 功能码
02 数据长度
00 17 数据值

二.TCP数据通信

链接:https://pan.baidu.com/s/1ninW1lpO94fl2GtDWx5csg
提取码:7yqt

调试工具使用该压缩包里面的TCPUDPDebug102_Setup,自行安装.

STM32与W5500接线方法

PC15->W5500_RST(源程序使用的是PC5,这里没有该引脚修改为PC15)

PC4->W5500_INT(使用寄存器查询方式的例程时,此引脚可以不接,其他例程可能涉及修改引脚)

PA4->W5500_SCS

PA5->W5500_SCK

PA6->W5500_MISO

PA7->W5500_MOSI

具体例程的调试过程请参考压缩包中NiRen_W5500模块用户手册(用Adobe Reader打开).pdf文件。

  • 根据自己的IP地址修改工程代码
    UDP:在这里插入图片描述
    在这里插入图片描述
    服务端:
    在这里插入图片描述
    在这里插入图片描述
    客户端:
    在这里插入图片描述
    在这里插入图片描述

这里我调试了查询寄存器方式中的UDP模式,服务端模式和客户端模式例程,调试结果如下:
UDP:
在这里插入图片描述
客户端:
在这里插入图片描述
服务器:
在这里插入图片描述

三.STM32+W5500+modbus协议编程

  • 初始化从机网络:
/* W5500 configuration */
void W5500_Configuration()
{
	unsigned char array[6];

	GPIO_SetBits(GPIO_W5500_RST_PORT, GPIO_W5500_RST_Pin);//上拉
	Delay_ms(100);    /*delay 100ms 使用systick 1ms时基的延时*/
    //等待以太网链路
	while((Read_1_Byte(PHYCFGR)&LINK)==0); 		/* Waiting for Ethernet Link */

	Write_1_Byte(MR, RST);//写入W5500普通寄存器一个字节
	Delay_ms(20);		/*delay 20ms */

	/* Set Gateway IP as: 192.168.1.1 */
	array[0]=192;
	array[1]=168;
	array[2]=0;
	array[3]=1;
	Write_Bytes(GAR, array, 4);//设置网关IP

	/* Set Subnet Mask as: 255.255.255.0 */
	array[0]=255;
	array[1]=255;
	array[2]=255;
	array[3]=0;
	Write_Bytes(SUBR, array, 4);//设置子网掩码

	/* Set MAC Address as: 0x48,0x53,0x00,0x57,0x55,0x00 */
	array[0]=0x48;
	array[1]=0x53;
	array[2]=0x00;
	array[3]=0x57;
	array[4]=0x55;
	array[5]=0x00;
	Write_Bytes(SHAR, array, 6);//设置MAC地址

	/* Set W5500 IP as: 192.168.1.128 */
	array[0]=192;
	array[1]=168;
	array[2]=0;
	array[3]=199;
	Write_Bytes(SIPR, array, 4);//设置W5500的IP地址
}

简单响应函数:

void Process_Socket_Data(SOCKET s)
{
	int len;
	unsigned char msg[11]={0x00,0x00,0x00 ,0x00, 0x00, 0x05, 0x01, 0x03, 0x02, 0x00, 0x70};
	len=sizeof(msg);
	unsigned short size;
	size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
	memcpy(Tx_Buffer, Rx_Buffer, size);
	
	//打印查询报文
	for (int j=0;j<size;j++){
		 printf("0x%02X ",Tx_Buffer[j]);
	}

	//写响应报文
	//检验码
	msg[0]=Tx_Buffer[0];
	msg[1]=Tx_Buffer[1];
	
	//协议
	msg[2]=0x00;
	msg[3]=0x00;
	
	//数据包长度
	msg[4]=0x00;
	msg[5]=0x05;
	
	//设备编号
	msg[6]=Tx_Buffer[6];
	//功能码
	msg[7]=Tx_Buffer[7];
	//数据长度
	msg[8]=0x02;
	
	//低八位
	msg[10]=data&0XFF;
	//高八位
	msg[9]=data>>8;
	
	memcpy(Tx_Buffer, msg, len);	
	//发送响应报文
	Write_SOCK_Data_Buffer(0, Tx_Buffer, len);
	data++;
}


  • main函数等待循环:
 while (1)
  {
		W5500_Socket_Set();//W5500端口初始化配置

		W5500_Interrupt_Process();//W5500中断处理程序框架
		
		if((S0_Data & S_RECEIVE) == S_RECEIVE)//如果Socket0接收到数据
		{
			S0_Data&=~S_RECEIVE;
			Process_Socket_Data(0);//W5500接收并发送接收到的数据
		}
		//从机状态标志
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);

  }


四.STM32+W5500的web服务

main函数:

int main(void)
{
	Systick_Init(72);//系统时钟初始化
	GPIO_Configuration(); //GPIO configuration
	USART1_Init(); //串口初始化:115200@8-n-1
	printf("W5500 EVB initialization over.\r\n");
	Reset_W5500();
	WIZ_SPI_Init();//W5500相关引脚配置
	printf("W5500 initialized!\r\n");
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
	{
		DefaultSet();//出厂值
	}
	else
	{
 		get_config();//read config data from flash
	}
	printf("Firmware ver%d.%d\r\n",ConfigMsg.sw_ver[0],ConfigMsg.sw_ver[1]);
	if(ConfigMsg.debug==0) ConfigMsg.debug=1;

	set_network();//配置网络信息
	printf("Network is ready.\r\n");
	while(1)
	{
		if(ConfigMsg.JTXD_Control == 0)
		  	do_http();//开启http服务
		else
		  	JTXD_do_http();
		if(reboot_flag)
			NVIC_SystemReset();//发起系统复位请求复位单片机
//        reboot();
        
	}
}

GPIO初始化函数:

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO , ENABLE);
  // Port A output
  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_1| GPIO_Pin_2 |GPIO_Pin_3; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  // Port B output;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB, GPIO_Pin_9);
  // Port C input
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//控制flash
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB, GPIO_Pin_7);	
}

W5500相关配置:

void WIZ_SPI_Init(void)
{
	SPI_InitTypeDef   SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO , ENABLE);	
  // Port B output
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB, GPIO_Pin_12);
  /* Configure SPIy pins: SCK, MISO and MOSI */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	  /* SPI Config -------------------------------------------------------------*/
	  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
	  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	  SPI_InitStructure.SPI_CRCPolynomial = 7;

	  SPI_Init(SPI2, &SPI_InitStructure);
	  SPI_Cmd(SPI2, ENABLE);
}

http请求:

void do_http(void)
{
  uint8 ch=SOCK_HTTP;
  uint16 len;

  st_http_request *http_request;
  memset(rx_buf,0x00,MAX_URI_SIZE);
  http_request = (st_http_request*)rx_buf;		// struct of http request  
  /* http service start */
  switch(getSn_SR(ch))
  {
    case SOCK_INIT:
      listen(ch);
      break;
    case SOCK_LISTEN:
      break;
    case SOCK_ESTABLISHED:
    //case SOCK_CLOSE_WAIT:
      if(getSn_IR(ch) & Sn_IR_CON)
      {
        setSn_IR(ch, Sn_IR_CON);
      }
      if ((len = getSn_RX_RSR(ch)) > 0)		
      {
        len = recv(ch, (uint8*)http_request, len); 
        *(((uint8*)http_request)+len) = 0;
        proc_http(ch, (uint8*)http_request); // request is processed
        disconnect(ch);
      }
      break;
    case SOCK_CLOSE_WAIT:   
      if ((len = getSn_RX_RSR(ch)) > 0)
      {
        //printf("close wait: %d\r\n",len);
        len = recv(ch, (uint8*)http_request, len);       
        *(((uint8*)http_request)+len) = 0;
        proc_http(ch, (uint8*)http_request); // request is processed
      }
      disconnect(ch);
      break;
    case SOCK_CLOSED:
      socket(ch, Sn_MR_TCP, 80, 0x00);    /* reinitialize the socket */
      break;
    default:
    break;
  }// end of switch
}

void JTXD_do_http(void)
{
  uint8 ch=SOCK_HTTP;
  uint16 len;

  st_http_request *http_request;
  memset(rx_buf,0x00,MAX_URI_SIZE);
  http_request = (st_http_request*)rx_buf;		// struct of http request
  
  /* http service start */
  switch(getSn_SR(ch))
  {
    case SOCK_INIT:
      listen(ch);
      break;
    case SOCK_LISTEN:

      break;
    case SOCK_ESTABLISHED:
    //case SOCK_CLOSE_WAIT:
      if(getSn_IR(ch) & Sn_IR_CON)
      {
        setSn_IR(ch, Sn_IR_CON);
      }
      if ((len = getSn_RX_RSR(ch)) > 0)		
      {
        len = recv(ch, (uint8*)http_request, len); 
        *(((uint8*)http_request)+len) = 0;
        JTXD_proc_http(ch, (uint8*)http_request); // request is processed
        disconnect(ch);
      }
      break;
    case SOCK_CLOSE_WAIT:   
      if ((len = getSn_RX_RSR(ch)) > 0)
      {
        //printf("close wait: %d\r\n",len);
        len = recv(ch, (uint8*)http_request, len);       
        *(((uint8*)http_request)+len) = 0;
        JTXD_proc_http(ch, (uint8*)http_request); // request is processed
      }
      disconnect(ch);
      break;
    case SOCK_CLOSED:                   
      socket(ch, Sn_MR_TCP, 80, 0x00);    /* reinitialize the socket */
      break;
    default:
    break;
  }// end of switch
}

说明:

初始IP地址是192.168.0.199,通过对PB7的操作来实现缺省值和flash之间的切换,设置好的参数写入flash,w5500接的是SPI2,单片机是stm32f103c8t6。
第一个网页没有任何修改权限,只有输入登录密码(初始密码:123456
或者万能密码:765997)进入修改页面,可以修改参数,包括登录密码都可以修改。
浏览器用的是IE。

五.参考链接

STM32+W5500网络通信
STM32+W5500以太网模块
STM32+W5500+Freemodbus Modbus-TCP协议功能实现,工程文件下载
基于STM32_DM9000_UIP_FreeModbus的Modbus-TCP功能实现工程下载
STM32F103 W5500做的web服务

标签:网络通信,ch,http,W5500,STM32,SPI,InitStructure,GPIO
来源: https://blog.csdn.net/qq_61682562/article/details/122122950

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有