- PA3 -> W5500_RST
- PA4 -> W5500_SCS
- PA5 -> W5500_SCK
- PA6 -> W5500_MISO
- PA7 -> W5500_MOSI
- Niren_W5500模块是一款基于WIZnet W5500芯片的以太网模块,是泥人电子继 Niren_W5100模块后设计的一块性能更好、性价比更高的以太网模块。模块集成硬件化TCP/IP协议:内部32K字节存储器作TX/RX
- 缓存:支持10/100Mbps的传输速率;支持8个独立端口同时运行;同时模块还支持3.3V或5V电源供电,5V供电时还可以输出3.3V电源,方便用户在不同的单片机系统中使用;模块与单片机系统的通讯方式是简单、方便的SPI通信。
void SPI_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO, ENABLE);
/* 初始化SCK、MISO、MOSI引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
/* 初始化CS引脚 */
GPIO_InitStructure.GPIO_Pin = W5500_SCS;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(W5500_SCS_PORT, &GPIO_InitStructure);
GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);
/* 初始化配置STM32 SPI1 */
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex; //SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //设置为主SPI
SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low; //时钟悬空低
SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge; //数据捕获于第1个时钟沿
SPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //NSS由外部管脚管理
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2; //波特率预分频值为2
SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial=7; //CRC多项式为7
SPI_Init(SPI1,&SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPI1寄存器
SPI_Cmd(SPI1,ENABLE); //STM32使能SPI1
}
void set_network(void)
{
uint8 ip[4];
setSHAR(ConfigMsg.mac);/*配置Mac地址*/
setSUBR(ConfigMsg.sub);/*配置子网掩码*/
setGAR(ConfigMsg.gw);/*配置默认网关*/
setSIPR(ConfigMsg.lip);/*配置Ip地址*/
//Init. TX & RX Memory size of w5500
sysinit(txsize, rxsize); /*初始化8个socket*/
setRTR(2000);/*设置溢出时间值*/
setRCR(3);/*设置最大重新发送次数*/
getSIPR (ip);
printf("IP : %d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
getSUBR(ip);
printf("SN : %d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
getGAR(ip);
printf("GW : %d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
}
- lip:本机地址
- sub: 子网掩码
- gw: 默认网关
Modbus RTU(Remote Terminal Unit 远程终端单元):这种方式常采用RS-485做为物理层,一般利用芯片的串口实现数据报文的收发,报文数据采用二进制数据进行通信。
Modbus ASCII :报文使用 ASCII 字符。ASCII 格式使用纵向冗余校验和。Modbus ASCII 报文由冒号 (":")开始 和换行符 (CR/LF) 结尾构成。
Modbus TCP/IP 或 Modbus TCP :这是一种 Modbus 变体版本,使用 TCP/IP 网络进行通信,通过 502 端口进行连接。报文不需要校验和计算,因为以太网底层已经实现了CRC32 数据完整性校验。
Modbus over TCP/IP 或 Modbus over TCP 或 Modbus RTU/IP :这也是一种 Modbus 变体,与 Modbus TCP 的不同之处在于,与 Modbus RTU 一样,校验和包含在报文中。
Modbus UDP:也有在UDP上传输Modbus报文的,不过需要做错误重传机制,这么干的应该不多。
int main(void)
{
unsigned char i;
/* Initialize STM32F103 */
System_Initialization();//系统配置
SysTick_Init();//启动系统滴答定时器 SysTick
/* Config W5500 */
W5500_Configuration();//W5500配置
Delay_ms(200);//延时等待
/* Modbus-TCP Init */
eMBTCPInit(MB_TCP_PORT_USE_DEFAULT); //端口依赖事件模块初始化
Delay_ms(200); //延时等待
/* Enable Modbus-TCP Stack */
eMBEnable();//激活协议栈
printf("\r\nModbus-TCP Start!\r\n");
printf("IP:192.168.1.190\r\n");
while(1)
{
i=Read_SOCK_1_Byte(0,Sn_SR); //读W5500状态
if(i==0)
{
do
{
Delay_ms(100);//延时等待
}while(Socket_Listen(0)==FALSE);//设置“Socket n”为“TCP服务器模式”
}
else if(i==SOCK_ESTABLISHED) //建立TCP连接
{
eMBPoll();//启动modbus侦听
BSP_LED();//线圈控制LED灯
}
}
}
w5500参数配置
/* 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]=1;
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]=1;
array[3]=190;
Write_Bytes(SIPR, array, 4);//设置W5500的IP地址
}
STM32F103C8芯片SPI初始化
void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1 | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
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_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE); //ʹÄÜSPIÍâÉè
}
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
SPI1->CR1&=0XFFC7;
SPI1->CR1|=SPI_BaudRatePrescaler;
SPI_Cmd(SPI1,ENABLE);
}
#ifdef __DEF_IINCHIP_PPP__
#include "md5.h"
#endif
static uint8 I_STATUS[MAX_SOCK_NUM];
static uint16 SSIZE[MAX_SOCK_NUM]; /**< Max Tx buffer size by each channel */
static uint16 RSIZE[MAX_SOCK_NUM]; /**< Max Rx buffer size by each channel */
uint8 getISR(uint8 s)
{
return I_STATUS[s];
}
void putISR(uint8 s, uint8 val)
{
I_STATUS[s] = val;
}
uint16 getIINCHIP_RxMAX(uint8 s)
{
return RSIZE[s];
}
uint16 getIINCHIP_TxMAX(uint8 s)
{
return SSIZE[s];
}
void IINCHIP_CSoff(void)
{
WIZ_CS(LOW);
}
void IINCHIP_CSon(void)
{
WIZ_CS(HIGH);
}
u8 IINCHIP_SpiSendData(uint8 dat)
{
return(SPI2_SendByte(dat));
}
void IINCHIP_WRITE( uint32 addrbsb, uint8 data)
{
IINCHIP_ISR_DISABLE(); // Interrupt Service Routine Disable
IINCHIP_CSoff(); // CS=0, SPI start
IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
IINCHIP_SpiSendData( (addrbsb & 0x000000F8) + 4); // Data write command and Write data length 1
IINCHIP_SpiSendData(data); // Data write (write 1byte data)
IINCHIP_CSon(); // CS=1, SPI end
IINCHIP_ISR_ENABLE(); // Interrupt Service Routine Enable
}
uint8 IINCHIP_READ(uint32 addrbsb)
{
uint8 data = 0;
IINCHIP_ISR_DISABLE(); // Interrupt Service Routine Disable
IINCHIP_CSoff(); // CS=0, SPI start
IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
IINCHIP_SpiSendData( (addrbsb & 0x000000F8)) ;// Data read command and Read data length 1
data = IINCHIP_SpiSendData(0x00); // Data read (read 1byte data)
IINCHIP_CSon(); // CS=1, SPI end
IINCHIP_ISR_ENABLE(); // Interrupt Service Routine Enable
return data;
}
uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len)
{
uint16 idx = 0;
if(len == 0) printf("Unexpected2 length 0\r\n");
IINCHIP_ISR_DISABLE();
IINCHIP_CSoff(); // CS=0, SPI start
IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
IINCHIP_SpiSendData( (addrbsb & 0x000000F8) + 4); // Data write command and Write data length 1
for(idx = 0; idx < len; idx++) // Write data in loop
{
IINCHIP_SpiSendData(buf[idx]);
}
IINCHIP_CSon(); // CS=1, SPI end
IINCHIP_ISR_ENABLE(); // Interrupt Service Routine Enable
return len;
}
uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len)
{
uint16 idx = 0;
if(len == 0)
{
printf("Unexpected2 length 0\r\n");
}
IINCHIP_ISR_DISABLE();
//SPI MODE I/F
IINCHIP_CSoff(); // CS=0, SPI start
IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
IINCHIP_SpiSendData( (addrbsb & 0x000000F8)); // Data write command and Write data length 1
for(idx = 0; idx < len; idx++) // Write data in loop
{
buf[idx] = IINCHIP_SpiSendData(0x00);
}
IINCHIP_CSon(); // CS=1, SPI end
IINCHIP_ISR_ENABLE(); // Interrupt Service Routine Enable
return len;
}
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
}
STM32F103基于W5500实现modbus简单TCP通信
通讯接口应用笔记3:使用W5500实现Modbus TCP服务器
基于w5500实现TCP/IP协议后应用层开发
基于STM32和W5500的Modbus TCP通讯
DHCP 原理以及IP获取过程
STM32 W5500 HTTP Server 微型web服务实现
通讯接口应用笔记3:使用W5500实现Modbus TCP服务器
Modbus协议最基础概念详细介绍
图文详解Modbus-RTU协议