文章目录
参考文章
注意: SPI的CS RST脚这些都是通过cubeMX自定义的可以自行修改。用的是SPI1
项目地址
//MyTcpClient.h
#ifndef MYTCPCLIENT_H
#define MYTCPCLIENT_H
#include "main.h"
#include "w5500.h"
#include "socket.h"
#include "wizchip_conf.h"
#include "spi.h"
#include <string.h> // memcmp
#define SOCK_TCPS 0
extern uint8_t buff[128]; //定义缓冲区
extern uint8_t TCP_send_buff[128]; //定义UDP发送缓冲区
extern uint8_t remote_ip[4]; //远程IP地址
extern uint16_t remote_port; //远程端口号
void TcpClientInit(void);
void do_tcp_client(void);
void Analysis(uint8_t *buf);
#endif // MYTCPCLIENT_H
//MyTcpClient.c
#include "MyTcpClient.h"
#include "main.h"
#include "w5500.h"
#include "socket.h"
#include "wizchip_conf.h"
#include "spi.h"
#include <string.h> // memcmp
uint8_t buff[128];
uint8_t TCP_send_buff[128];
//需配置
uint8_t remote_ip[4] = {192, 168, 6, 151}; //远程IP地址
uint16_t remote_port = 8080; //远程端口号
//片选
void W5500_Select(void) {
HAL_GPIO_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_RESET);
}
void W5500_Unselect(void) {
HAL_GPIO_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_SET);
}
void W5500_Restart(void) {
HAL_GPIO_WritePin(W5500_RST_GPIO_Port, W5500_RST_Pin, GPIO_PIN_RESET);
HAL_Delay(1); // delay 1ms
HAL_GPIO_WritePin(W5500_RST_GPIO_Port, W5500_RST_Pin, GPIO_PIN_SET);
HAL_Delay(1600); // delay 1600ms
}
void W5500_ReadBuff(uint8_t* buff, uint16_t len) {
HAL_SPI_Receive(&hspi1, buff, len, HAL_MAX_DELAY);
}
void W5500_WriteBuff(uint8_t* buff, uint16_t len) {
HAL_SPI_Transmit(&hspi1, buff, len, HAL_MAX_DELAY);
}
uint8_t W5500_ReadByte(void) {
uint8_t byte;
W5500_ReadBuff(&byte, sizeof(byte));
return byte;
}
void W5500_WriteByte(uint8_t byte) {
W5500_WriteBuff(&byte, sizeof(byte));
}
//配置W5500网络信息(需配置)
wiz_NetInfo gSetNetInfo = {
.mac = {0x00, 0x08, 0xdc, 0x11, 0x11, 0x11},
.ip = {192, 168, 6, 15},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 6, 1},
.dns = {8,8,8,8},
.dhcp = NETINFO_STATIC};
wiz_NetInfo gGetNetInfo;
enum Status
{
Failed = 0,
Success = 1
};
/**
* @brief valid the result of set net info
* @return 1: Success
* 0: Failed
*/
uint8_t validSetNetInfoResult(wiz_NetInfo* _set, wiz_NetInfo* _get)
{
return (!memcmp(_set, _get, sizeof(wiz_NetInfo))); // if same, memcmp return 0
}
//进入临界区
void SPI_CrisEnter(void)
{
__set_PRIMASK(1);
}
//退出临界区
void SPI_CrisExit(void)
{
__set_PRIMASK(0);
}
void SPI_CS_Select(void)
{
HAL_GPIO_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_RESET);
}
void SPI_CS_Deselect(void)
{
HAL_GPIO_WritePin(W5500_CS_GPIO_Port, W5500_CS_Pin, GPIO_PIN_SET);
}
void TcpClientInit(void)
{
reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit); //注册临界区函数
reg_wizchip_cs_cbfunc(W5500_Select, W5500_Unselect);
reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte);
W5500_Restart(); // hardware restart through RESET pin
ctlnetwork(CN_SET_NETINFO, (void*)&gSetNetInfo); // set net info
// maybe need delay
ctlnetwork(CN_GET_NETINFO, (void*)&gGetNetInfo); // get net info
// W5500 has 8 channel, 32k buffer, 2 means 2KBytes
uint8_t buffer_size_8channel_tx_rx[16] = {2, 2, 2, 2, 2, 2, 2, 2, // 8 channel tx
2, 2, 2, 2, 2, 2, 2, 2}; // 8 channel rx
if(ctlwizchip(CW_INIT_WIZCHIP,(void*)buffer_size_8channel_tx_rx))
{
// failed
}
uint8_t sta = getSn_SR(SOCK_TCPS);
if(sta == SOCK_CLOSED)
{
socket(SOCK_TCPS, Sn_MR_TCP, 5001, 0x00);
}
HAL_Delay(100);
}
void do_tcp_client(void)
{
uint16_t len=0;
switch(getSn_SR(SOCK_TCPS)) // 获取socket0的状态
{
case SOCK_INIT: // Socket处于初始化完成(打开)状态
connect(SOCK_TCPS,remote_ip,remote_port);
break;
case SOCK_ESTABLISHED: // Socket处于连接建立状态
if(getSn_IR(SOCK_TCPS) & Sn_IR_CON)
{
setSn_IR(SOCK_TCPS, Sn_IR_CON); // Sn_IR的CON位置1,通知W5500连接已建立
}
// 数据回环测试程序:数据从上位机服务器发给W5500,W5500接收到数据后再回给服务器
len=getSn_RX_RSR(SOCK_TCPS); // len=Socket0接收缓存中已接收和保存的数据大小
if(len)
{
recv(SOCK_TCPS,buff,len);
send(SOCK_TCPS,buff,len);
}
break;
case SOCK_CLOSE_WAIT: // Socket处于等待关闭状态
disconnect(SOCK_TCPS);
break;
case SOCK_CLOSED: // Socket处于关闭状态
socket(SOCK_TCPS,Sn_MR_TCP,5001,0x00); // 打开Socket0,打开一个本地端口
break;
}
}
//分析数据
void Analysis(uint8_t *buf)
{
}
主函数(我用的是freeRTOS以线程的方式)
//freertos.c
/* USER CODE BEGIN Includes */
#include "MyTcpClient.h" //添加头文件
/* USER CODE END Includes */
//freertos.c
void W5500_Task_TCP(void const * argument)
{
/* USER CODE BEGIN W5500_Task_TCP */
TcpClientInit();
/* Infinite loop */
for(;;)
{
do_tcp_client();
//osDelay(1);
}
/* USER CODE END W5500_Task_TCP */
}
大伙注意的是参考文章中没提到的
//MyTcpClient.c
//进入临界区
void SPI_CrisEnter(void)
{
__set_PRIMASK(1);
}
//退出临界区
void SPI_CrisExit(void)
{
__set_PRIMASK(0);
}
还有就是
本地和远程IP连接的配置(重点)
//配置W5500网络信息(需配置)
wiz_NetInfo gSetNetInfo = {
.mac = {0x00, 0x08, 0xdc, 0x11, 0x11, 0x11},
.ip = {192, 168, 6, 15},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 6, 1},
.dns = {8,8,8,8},
.dhcp = NETINFO_STATIC};
这些是w5500的配置和
//需配置
uint8_t remote_ip[4] = {192, 168, 6, 151}; //远程IP地址
uint16_t remote_port = 8080; //远程端口号
需要大伙额外注意
TCP发送
//MyTcpClient.c
void TCP_SendData(uint8_t *data, uint16_t len) {
// 创建Socket
socket(SOCKET_ID, Sn_MR_TCP, local_port, 0); // 本地端口(local_port:5001)
// 连接服务器
//uint8_t dest_ip[4] = {192, 168, 6, 151}; // 服务器IP
if (connect(SOCKET_ID, remote_ip, SERVER_PORT) != SOCK_OK) {
// 连接失败处理
return;
}
// 等待连接成功(可选)
while(getSn_SR(SOCKET_ID) != SOCK_ESTABLISHED) {
HAL_Delay(10);
}
// 发送数据
send(SOCKET_ID, data, len);
// 关闭Socket(非必需,可保持连接)
disconnect(SOCKET_ID);
close(SOCKET_ID);
}
应用线程函数
//freertos.c
/* USER CODE END Header_W5500_Task_01 */
//发送的数据体
uint8_t msg1[] = "Hello TCP Server!";
void W5500_Task_01(void const * argument)
{
/* USER CODE BEGIN W5500_Task_01 */
TcpClientInit();
/* Infinite loop */
for(;;)
{
do_tcp_client();
TCP_SendData(msg1,strlen((char*)msg1));
osDelay(3000);
}
/* USER CODE END W5500_Task_01 */
}