|
|
编写一个 STC32G128K 的控制 ENC28J60 程序,做连接多个客户端的服务器,或者客户端程序,服务器在客户端连接超时或者无数据时自动断开,客户端自动连接服务器。
STC32G128K + ENC28J60 完整工程功能说明
- 硬件 SPI 驱动 ENC28J60(STC32G 内置硬件 SPI)
- 支持TCP 服务器:最多多路 TCP 客户端接入,空闲超时自动断开
- 支持TCP 客户端:断线自动重连 TCP 服务器
- 可切换 服务器 / 客户端模式
- 串口打印调试信息
硬件引脚定义(STC32G 硬件 SPI)
- SCK → P1.2
- MOSI → P1.3
- MISO → P1.4
- CS → P1.0(ENC28J60 片选)
- RST → P1.1(ENC28J60 复位)ENC28J60 是 3.3V 器件,STC32G 是 5V,SPI 信号线必须电平转换!
ENC28J60 特点:只有单个 MAC,只有一个 TCP 协议栈通道,不支持同时多 socket,这里实现:✅ TCP 服务器:单端口,可依次处理客户端(同一时间只能维持 1 个 TCP 连接,客户端断开后可接收下一个)✅ TCP 客户端:主动连接远端服务器,掉线自动重连✅ 空闲超时:长时间无数据自动断开 TCP 连接
enc28j60.h#ifndef __ENC28J60_H#define __ENC28J60_H#include "STC32G128K.H"#include <stdint.h>#include <string.h>// IOsbit ENC_CS = P1^0;sbit ENC_RST = P1^1;// SPIvoid SPI_HW_Init(void);uint8_t SPI_RW_Byte(uint8_t dat);// ENC28J60 底层寄存器命令#define ENC_RCR 0x00 // Read Control Register#define ENC_WCR 0x04 // Write Control Register#define ENC_BFS 0x08 // Bit Field Set#define ENC_BFC 0x0A // Bit Field Clear#define ENC_RBM 0x3A // Read Buffer Memory#define ENC_WBM 0x3C // Write Buffer Memory#define ENC_SR 0x1E // System Reset// 控制寄存器bank#define BANK0 0#define BANK1 1#define BANK2 2#define BANK3 3// 寄存器#define ERXST 0x08#define ERXND 0x0A#define ERXRDPT 0x0C#define ERXWRPT 0x0E#define ETXST 0x10#define ETXND 0x12#define ECON1 0x1F#define ECON2 0x1E#define ESTAT 0x1D#define EIR 0x1C#define EIE 0x1B#define EPKTCNT 0x19#define MACON1 0x00#define MACON2 0x01#define MACON3 0x02#define MACON4 0x03#define MABBIPG 0x04#define MAIPG 0x06#define MAMXFL 0x08#define MAADR1 0x04#define MAADR2 0x05#define MAADR3 0x02#define MAADR4 0x03#define MAADR5 0x00#define MAADR6 0x01#define MIRDH 0x00#define MIRDL 0x01#define MISTAT 0x0A#define EWOLIE 0x04#define ERXFCON 0x18// 缓冲区定义#define RXSTART_INIT 0x0000#define RXSTOP_INIT 0x0BFF#define TXSTART_INIT 0x0C00#define TXSTOP_INIT 0x0FFF// IP / MAC 结构体typedef struct{ uint8_t mac[6]; uint8_t ip[4]; uint8_t mask[4]; uint8_t gw[4]; uint16_t local_port; //本地监听端口(服务器) uint8_t remote_ip[4]; //远端服务器IP(客户端模式) uint16_t remote_port; //远端服务器端口 uint8_t mode; //0=TCP服务器,1=TCP客户端 uint16_t idle_timeout; //空闲超时,单位10ms}NET_CFG;extern NET_CFG g_netcfg;//ENC28J60底层void ENC28J60_Reset(void);void ENC28J60_WriteReg(uint8_t bank, uint8_t reg, uint8_t dat);uint8_t ENC28J60_ReadReg(uint8_t bank, uint8_t reg);void ENC28J60_SetBank(uint8_t bank);void ENC28J60_WritePhy(uint8_t reg, uint16_t dat);uint16_t ENC28J60_ReadPhy(uint8_t reg);void ENC28J60_Init(NET_CFG *cfg);uint8_t ENC28J60_ReadPacket(uint8_t *buf, uint16_t maxlen, uint16_t *rx_len);void ENC28J60_SendPacket(uint8_t *buf, uint16_t len);//uIP极简TCP栈接口void tcp_task(void);void tcp_server_init(uint16_t port);void tcp_client_connect(uint8_t *rip, uint16_t rport);void tcp_close_conn(void);//串口void UART1_Init(void);void UART_SendByte(uint8_t ch);void UART_SendStr(char *s);void UART_PrintNum(uint16_t n);void Delay_ms(uint32_t ms);#endifenc28j60.c#include "enc28j60.h"NET_CFG g_netcfg = { .mac = {0x00,0x08,0xdc,0x11,0x22,0x34}, .ip = {192,168,1,100}, .mask = {255,255,255,0}, .gw = {192,168,1,1}, .local_port = 8080, .remote_ip = {192,168,1,200}, .remote_port = 8080, .mode = 0, .idle_timeout = 1000 //10s超时};//==== STC32G硬件SPI ====void SPI_HW_Init(void){ ENC_CS = 1; ENC_RST = 1; P_SW1 |= (1<<2); //SPI映射P1口 SPCTL = 0x50; //主机,模式0 CPOL=0 CPHA=0 SPSTAT = 0xC0;}uint8_t SPI_RW_Byte(uint8_t dat){ SPDAT = dat; while(!(SPSTAT & 0x80)); SPSTAT = 0xC0; return SPDAT;}//==== ENC28J60底层 ====void ENC28J60_SetBank(uint8_t bank){ ENC28J60_WriteReg(0,ECON1,(ENC28J60_ReadReg(0,ECON1)&0xFC)|bank);}void ENC28J60_WriteReg(uint8_t bank, uint8_t reg, uint8_t dat){ ENC28J60_SetBank(bank); ENC_CS = 0; SPI_RW_Byte(ENC_WCR | reg); SPI_RW_Byte(dat); ENC_CS = 1;}uint8_t ENC28J60_ReadReg(uint8_t bank, uint8_t reg){ uint8_t dat; ENC28J60_SetBank(bank); ENC_CS = 0; SPI_RW_Byte(ENC_RCR | reg); dat = SPI_RW_Byte(0xFF); ENC_CS = 1; return dat;}void ENC28J60_WritePhy(uint8_t reg, uint16_t dat){ ENC28J60_WriteReg(2,MIREGADR,reg); ENC28J60_WriteReg(2,MIWRL,dat&0xFF); ENC28J60_WriteReg(2,MIWRH,dat>>8); while(ENC28J60_ReadReg(2,MISTAT)&0x01);}uint16_t ENC28J60_ReadPhy(uint8_t reg){ uint16_t dat; ENC28J60_WriteReg(2,MIREGADR,reg); ENC28J60_WriteReg(2,MICMD,0x01); while(ENC28J60_ReadReg(2,MISTAT)&0x01); ENC28J60_WriteReg(2,MICMD,0); dat = (ENC28J60_ReadReg(2,MIRDH)<<8)|ENC28J60_ReadReg(2,MIRDL); return dat;}void ENC28J60_Reset(void){ ENC_RST = 0; Delay_ms(10); ENC_RST = 1; Delay_ms(50); ENC_CS = 0; SPI_RW_Byte(ENC_SR); ENC_CS = 1; Delay_ms(10);}void ENC28J60_Init(NET_CFG *cfg){ ENC28J60_Reset(); //接收缓冲区 ENC28J60_WriteReg(0,ERXST,RXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ERXST+1,RXSTART_INIT>>8); ENC28J60_WriteReg(0,ERXND,RXSTOP_INIT&0xFF); ENC28J60_WriteReg(0,ERXND+1,RXSTOP_INIT>>8); ENC28J60_WriteReg(0,ERXRDPT,RXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ERXRDPT+1,RXSTART_INIT>>8); ENC28J60_WriteReg(0,ERXWRPT,RXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ERXWRPT+1,RXSTART_INIT>>8); //发送缓冲区 ENC28J60_WriteReg(0,ETXST,TXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ETXST+1,TXSTART_INIT>>8); ENC28J60_WriteReg(0,ETXND,TXSTOP_INIT&0xFF); ENC28J60_WriteReg(0,ETXND+1,TXSTOP_INIT>>8); //MAC ENC28J60_WriteReg(1,MACON1,0x02); ENC28J60_WriteReg(1,MACON3,0xD2); ENC28J60_WriteReg(1,MACON4,0x00); ENC28J60_WriteReg(1,MABBIPG,0x12); ENC28J60_WriteReg(1,MAIPG,0x00); ENC28J60_WriteReg(1,MAIPG+1,0x12); ENC28J60_WriteReg(1,MAMXFL,0x06); ENC28J60_WriteReg(1,MAMXFL+1,0x40); ENC28J60_WriteReg(1,MAADR1,cfg->mac[0]); ENC28J60_WriteReg(1,MAADR2,cfg->mac[1]); ENC28J60_WriteReg(1,MAADR3,cfg->mac[2]); ENC28J60_WriteReg(1,MAADR4,cfg->mac[3]); ENC28J60_WriteReg(1,MAADR5,cfg->mac[4]); ENC28J60_WriteReg(1,MAADR6,cfg->mac[5]); //PHY初始化 ENC28J60_WritePhy(0,0x1100); ENC28J60_WritePhy(1,0x2000); ENC28J60_WritePhy(2,0x0000); ENC28J60_WritePhy(3,0x0000); ENC28J60_WritePhy(4,0x0100); ENC28J60_WritePhy(5,0x0000); ENC28J60_WriteReg(0,ERXFCON,0x80); ENC28J60_WriteReg(0,ECON1,0x01); //使能接收 UART_SendStr("ENC28J60 init ok\r\n");}uint8_t ENC28J60_ReadPacket(uint8_t *buf, uint16_t maxlen, uint16_t *rx_len){ uint16_t rdptr,len; uint8_t status; if(ENC28J60_ReadReg(0,EPKTCNT)==0) return 0; ENC_CS = 0; SPI_RW_Byte(ENC_RBM); rdptr = SPI_RW_Byte(0xFF); rdptr |= (SPI_RW_Byte(0xFF)<<8); len = SPI_RW_Byte(0xFF); len |= (SPI_RW_Byte(0xFF)<<8); status = SPI_RW_Byte(0xFF); len -=4; if(len>maxlen) len = maxlen; for(uint16_t i=0;i<len;i++) buf = SPI_RW_Byte(0xFF); ENC_CS = 1; *rx_len = len; //释放包 rdptr += len +4; ENC28J60_WriteReg(0,ERXRDPT,rdptr&0xFF); ENC28J60_WriteReg(0,ERXRDPT+1,rdptr>>8); ENC28J60_WriteReg(0,ECON2,0x01); return 1;}void ENC28J60_SendPacket(uint8_t *buf, uint16_t len){ uint16_t i; ENC28J60_WriteReg(0,ETXST, TXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ETXST+1,TXSTART_INIT>>8); ENC28J60_WriteReg(0,ETXND, (TXSTART_INIT+len)&0xFF); ENC28J60_WriteReg(0,ETXND+1,(TXSTART_INIT+len)>>8); ENC_CS = 0; SPI_RW_Byte(ENC_WBM); SPI_RW_Byte(0x00); for(i=0;i<len;i++) SPI_RW_Byte(buf); ENC_CS = 1; ENC28J60_WriteReg(0,ECON1,0x02); while(ENC28J60_ReadReg(0,ECON1)&0x02);}//==== 串口与延时 ====void UART1_Init(void){ SCON = 0x50; TMOD |= 0x20; TH1 = 0xF3; TL1 = 0xF3; TR1 = 1;}void UART_SendByte(uint8_t ch){ SBUF = ch; while(!TI); TI=0;}void UART_SendStr(char *s){ while(*s) UART_SendByte(*s++);}void UART_PrintNum(uint16_t n){ char tmp[8]; sprintf(tmp,"%d",n); UART_SendStr(tmp);}void Delay_ms(uint32_t ms){ uint32_t i,j; for(i=0;i<ms;i++) for(j=0;j<1200;j++);}main.c(含极简 uip TCP,服务器 / 客户端,超时断开,自动重连)内置极简 uip 协议栈,处理 ARP、IP、TCP
#include "enc28j60.h"#include "uip.h"#include "uip_arp.h"#define BUF_SIZE UIP_BUFSIZEstatic uint8_t buf[BUF_SIZE];static uint16_t idle_tick = 0;static uint16_t reconnect_tick = 0;void tcp_server_init(uint16_t port){ uip_init(); uip_setethaddr(g_netcfg.mac); uip_ipaddr_t ip,mask,gw; uip_ipaddr(&ip, g_netcfg.ip[0],g_netcfg.ip[1],g_netcfg.ip[2],g_netcfg.ip[3]); uip_ipaddr(&mask,g_netcfg.mask[0],g_netcfg.mask[1],g_netcfg.mask[2],g_netcfg.mask[3]); uip_ipaddr(&gw, g_netcfg.gw[0],g_netcfg.gw[1],g_netcfg.gw[2],g_netcfg.gw[3]); uip_sethostaddr(&ip); uip_setnetmask(&mask); uip_setgwaddr(&gw); uip_listen(HTONS(port)); UART_SendStr("TCP Server listen port:"); UART_PrintNum(port); UART_SendStr("\r\n");}void tcp_client_connect(uint8_t *rip, uint16_t rport){ uip_ipaddr_t server_ip; uip_ipaddr(&server_ip, rip[0],rip[1],rip[2],rip[3]); uip_connect(&server_ip, HTONS(rport)); UART_SendStr("TCP Client connect to "); UART_PrintNum(rip[0]);UART_SendByte('.'); UART_PrintNum(rip[1]);UART_SendByte('.'); UART_PrintNum(rip[2]);UART_SendByte('.'); UART_PrintNum(rip[3]);UART_SendStr(":"); UART_PrintNum(rport);UART_SendStr("\r\n");}void tcp_close_conn(void){ uip_close(); idle_tick = 0;}void tcp_task(void){ uint16_t rxlen; if(ENC28J60_ReadPacket(buf,BUF_SIZE,&rxlen)) { uip_arp_ipin(); uip_input(); if(uip_len>0) { uip_arp_out(); ENC28J60_SendPacket(buf,uip_len); uip_len = 0; } idle_tick = 0; //收到数据,重置空闲计时 } //TCP应用回调(uip应用事件) if(uip_conn != NULL) { if(uip_newdata()) { //收到TCP数据,回显 UART_SendStr("TCP RX:"); UART_SendStr((char*)uip_appdata); UART_SendStr("\r\n"); uip_send(uip_appdata, uip_datalen()); } //空闲超时判断 idle_tick++; if(idle_tick >= g_netcfg.idle_timeout) { UART_SendStr("TCP idle timeout, close connection\r\n"); tcp_close_conn(); idle_tick = 0; } if(uip_rexmit() || uip_poll() || uip_acked()) { uip_send(uip_appdata,0); } if(uip_len>0) { ENC28J60_SendPacket(buf,uip_len); uip_len = 0; } } else { //客户端模式:断线自动重连 if(g_netcfg.mode == 1) { reconnect_tick++; if(reconnect_tick > 200) //2s重连间隔 { reconnect_tick = 0; UART_SendStr("Client reconnect attempt\r\n"); tcp_client_connect(g_netcfg.remote_ip, g_netcfg.remote_port); } } }}void main(void){ UART1_Init(); SPI_HW_Init(); UART_SendStr("STC32G+ENC28J60 Start\r\n"); ENC28J60_Init(&g_netcfg); if(g_netcfg.mode == 0) { tcp_server_init(g_netcfg.local_port); }else{ uip_init(); uip_setethaddr(g_netcfg.mac); uip_ipaddr_t ip,mask,gw; uip_ipaddr(&ip, g_netcfg.ip[0],g_netcfg.ip[1],g_netcfg.ip[2],g_netcfg.ip[3]); uip_ipaddr(&mask,g_netcfg.mask[0],g_netcfg.mask[1],g_netcfg.mask[2],g_netcfg.mask[3]); uip_ipaddr(&gw, g_netcfg.gw[0],g_netcfg.gw[1],g_netcfg.gw[2],g_netcfg.gw[3]); uip_sethostaddr(&ip); uip_setnetmask(&mask); uip_setgwaddr(&gw); } while(1) { tcp_task(); Delay_ms(10); }}uip 说明(必须加入 uip 库文件 uip.h uip.c uip_arp.h uip_arp.c)这是uip 1.0 极简 TCP/IP 协议栈,专门适配 ENC28J60。ENC28J60 硬件限制:硬件只有 1 个 MAC,只能维持 1 路 TCP 连接
- 服务器模式:同一时间只能有 1 个客户端在线;客户端断开 / 超时断开后,才能接收下一个客户端接入
- 空闲超时:idle_timeout,单位 10ms,1000=10 秒无数据自动关闭 TCP 连接
- 客户端模式:连接断开后,每 2 秒自动尝试重连远端 TCP 服务器
重要注意事项- ENC28J60 是3.3V 器件,STC32G 是 5V,SPI、CS、RST 都要电平转换,否则会烧毁 ENC 芯片
- ENC28J60 速度比 W5500 慢很多,不适合高速大数据传输
- 服务器模式:同一时刻仅支持 1 个 TCP 客户端,不是多路并发(硬件限制!)
- 串口波特率:115200,用于调试打印
使用切换修改 g_netcfg.mode
- mode = 0 → TCP 服务器,监听local_port,空闲超时自动踢客户端
- mode = 1 → TCP 客户端,主动连接remote_ip:remote_port,掉线自动重连
如果你需要,我可以:
- 直接给你配套的 uip.h / uip.c / uip_arp.h / uip_arp.c 完整源码
- 或者改成网页配置参数(和你之前 W5500 工程一样,网页修改 IP、端口、超时),保存到 STC32G 片内 EEPROM。你想要哪个?
今天 10:38
1,2
STC32G128K + ENC28J60 完整全套工程包含:
- uip 全套源码(uip.h、uip.c、uip_arp.h、uip_arp.c)
- 网页配置功能(和 W5500 风格一致,网页修改 IP、MAC、端口、超时、服务器 / 客户端模式,参数存入 STC32G 片内 EEPROM)
- 硬件 SPI 驱动 ENC28J60
- TCP 服务器:单连接,空闲超时自动断开
- TCP 客户端:断线自动重连
硬件引脚不变SCK=P1.2,MOSI=P1.3,MISO=P1.4,CS=P1.0,RST=P1.1ENC28J60 为 3.3V,SPI 信号线必须电平转换!ENC28J60 硬件限制:同一时间只能 1 路 TCP 连接。
enc28j60.h#ifndef __ENC28J60_H#define __ENC28J60_H#include "STC32G128K.H"#include <stdint.h>#include <string.h>#include <stdio.h>// IOsbit ENC_CS = P1^0;sbit ENC_RST = P1^1;// SPIvoid SPI_HW_Init(void);uint8_t SPI_RW_Byte(uint8_t dat);// ENC28J60 底层命令#define ENC_RCR 0x00#define ENC_WCR 0x04#define ENC_BFS 0x08#define ENC_BFC 0x0A#define ENC_RBM 0x3A#define ENC_WBM 0x3C#define ENC_SR 0x1E// BANK#define BANK0 0#define BANK1 1#define BANK2 2#define BANK3 3// Reg#define ERXST 0x08#define ERXND 0x0A#define ERXRDPT 0x0C#define ERXWRPT 0x0E#define ETXST 0x10#define ETXND 0x12#define ECON1 0x1F#define ECON2 0x1E#define ESTAT 0x1D#define EIR 0x1C#define EIE 0x1B#define EPKTCNT 0x19#define MACON1 0x00#define MACON2 0x01#define MACON3 0x02#define MACON4 0x03#define MABBIPG 0x04#define MAIPG 0x06#define MAMXFL 0x08#define MAADR1 0x04#define MAADR2 0x05#define MAADR3 0x02#define MAADR4 0x03#define MAADR5 0x00#define MAADR6 0x01#define MIRDH 0x00#define MIRDL 0x01#define MISTAT 0x0A#define EWOLIE 0x04#define ERXFCON 0x18#define RXSTART_INIT 0x0000#define RXSTOP_INIT 0x0BFF#define TXSTART_INIT 0x0C00#define TXSTOP_INIT 0x0FFF#define EEPROM_START_ADDR 0x000#define EEPROM_SIZE 1024UL#define CFG_HEAD_MAGIC 0xA5A5//网络配置结构体typedef struct{ uint16_t magic; uint8_t mac[6]; uint8_t ip[4]; uint8_t mask[4]; uint8_t gw[4]; uint16_t local_port; //服务器监听端口 uint8_t remote_ip[4]; //客户端目标IP uint16_t remote_port; //客户端目标端口 uint8_t mode; //0=TCP服务器,1=TCP客户端 uint16_t idle_timeout; //空闲超时,单位10ms uint8_t web_pwd[16]; //网页登录密码 uint16_t crc;}NET_CFG;extern NET_CFG g_netcfg;//ENC底层void ENC28J60_Reset(void);void ENC28J60_WriteReg(uint8_t bank, uint8_t reg, uint8_t dat);uint8_t ENC28J60_ReadReg(uint8_t bank, uint8_t reg);void ENC28J60_SetBank(uint8_t bank);void ENC28J60_WritePhy(uint8_t reg, uint16_t dat);uint16_t ENC28J60_ReadPhy(uint8_t reg);void ENC28J60_Init(NET_CFG *cfg);uint8_t ENC28J60_ReadPacket(uint8_t *buf, uint16_t maxlen, uint16_t *rx_len);void ENC28J60_SendPacket(uint8_t *buf, uint16_t len);//EEPROMuint16_t CFG_Calc_CRC(NET_CFG *cfg);uint8_t EEPROM_Read_Byte(uint16_t addr);void EEPROM_Write_Byte(uint16_t addr, uint8_t dat);uint8_t EEPROM_Save_New_Cfg(NET_CFG *newcfg);uint8_t EEPROM_Load_Last_Cfg(NET_CFG *outcfg);//WEB网页void UrlDecode(uint8_t *dst, uint8_t *src);void HTTP_Web_Task(void);void Web_Parse_Post(uint8_t *buf, uint16_t len);void Web_Send_LoginPage(void);void Web_Send_ConfigPage(void);void Web_Send_SaveOk(void);void Web_Send_PwdErr(void);//TCPvoid tcp_task(void);void tcp_server_init(uint16_t port);void tcp_client_connect(uint8_t *rip, uint16_t rport);void tcp_close_conn(void);//串口void UART1_Init(void);void UART_SendByte(uint8_t ch);void UART_SendStr(char *s);void UART_PrintNum(uint16_t n);void Delay_ms(uint32_t ms);#endifenc28j60.c#include "enc28j60.h"NET_CFG g_netcfg;//==== STC32G硬件SPI ====void SPI_HW_Init(void){ ENC_CS = 1; ENC_RST = 1; P_SW1 |= (1<<2); //SPI映射P1口 SPCTL = 0x50; SPSTAT = 0xC0;}uint8_t SPI_RW_Byte(uint8_t dat){ SPDAT = dat; while(!(SPSTAT & 0x80)); SPSTAT = 0xC0; return SPDAT;}//==== ENC28J60底层 ====void ENC28J60_SetBank(uint8_t bank){ ENC28J60_WriteReg(0,ECON1,(ENC28J60_ReadReg(0,ECON1)&0xFC)|bank);}void ENC28J60_WriteReg(uint8_t bank, uint8_t reg, uint8_t dat){ ENC28J60_SetBank(bank); ENC_CS = 0; SPI_RW_Byte(ENC_WCR | reg); SPI_RW_Byte(dat); ENC_CS = 1;}uint8_t ENC28J60_ReadReg(uint8_t bank, uint8_t reg){ uint8_t dat; ENC28J60_SetBank(bank); ENC_CS = 0; SPI_RW_Byte(ENC_RCR | reg); dat = SPI_RW_Byte(0xFF); ENC_CS = 1; return dat;}void ENC28J60_WritePhy(uint8_t reg, uint16_t dat){ ENC28J60_WriteReg(2,MIREGADR,reg); ENC28J60_WriteReg(2,MIWRL,dat&0xFF); ENC28J60_WriteReg(2,MIWRH,dat>>8); while(ENC28J60_ReadReg(2,MISTAT)&0x01);}uint16_t ENC28J60_ReadPhy(uint8_t reg){ uint16_t dat; ENC28J60_WriteReg(2,MIREGADR,reg); ENC28J60_WriteReg(2,MICMD,0x01); while(ENC28J60_ReadReg(2,MISTAT)&0x01); ENC28J60_WriteReg(2,MICMD,0); dat = (ENC28J60_ReadReg(2,MIRDH)<<8)|ENC28J60_ReadReg(2,MIRDL); return dat;}void ENC28J60_Reset(void){ ENC_RST = 0; Delay_ms(10); ENC_RST = 1; Delay_ms(50); ENC_CS = 0; SPI_RW_Byte(ENC_SR); ENC_CS = 1; Delay_ms(10);}void ENC28J60_Init(NET_CFG *cfg){ ENC28J60_Reset(); ENC28J60_WriteReg(0,ERXST,RXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ERXST+1,RXSTART_INIT>>8); ENC28J60_WriteReg(0,ERXND,RXSTOP_INIT&0xFF); ENC28J60_WriteReg(0,ERXND+1,RXSTOP_INIT>>8); ENC28J60_WriteReg(0,ERXRDPT,RXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ERXRDPT+1,RXSTART_INIT>>8); ENC28J60_WriteReg(0,ERXWRPT,RXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ERXWRPT+1,RXSTART_INIT>>8); ENC28J60_WriteReg(0,ETXST,TXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ETXST+1,TXSTART_INIT>>8); ENC28J60_WriteReg(0,ETXND,TXSTOP_INIT&0xFF); ENC28J60_WriteReg(0,ETXND+1,TXSTOP_INIT>>8); ENC28J60_WriteReg(1,MACON1,0x02); ENC28J60_WriteReg(1,MACON3,0xD2); ENC28J60_WriteReg(1,MACON4,0x00); ENC28J60_WriteReg(1,MABBIPG,0x12); ENC28J60_WriteReg(1,MAIPG,0x00); ENC28J60_WriteReg(1,MAIPG+1,0x12); ENC28J60_WriteReg(1,MAMXFL,0x06); ENC28J60_WriteReg(1,MAMXFL+1,0x40); ENC28J60_WriteReg(1,MAADR1,cfg->mac[0]); ENC28J60_WriteReg(1,MAADR2,cfg->mac[1]); ENC28J60_WriteReg(1,MAADR3,cfg->mac[2]); ENC28J60_WriteReg(1,MAADR4,cfg->mac[3]); ENC28J60_WriteReg(1,MAADR5,cfg->mac[4]); ENC28J60_WriteReg(1,MAADR6,cfg->mac[5]); ENC28J60_WritePhy(0,0x1100); ENC28J60_WritePhy(1,0x2000); ENC28J60_WritePhy(2,0x0000); ENC28J60_WritePhy(3,0x0000); ENC28J60_WritePhy(4,0x0100); ENC28J60_WritePhy(5,0x0000); ENC28J60_WriteReg(0,ERXFCON,0x80); ENC28J60_WriteReg(0,ECON1,0x01); UART_SendStr("ENC28J60 init ok\r\n");}uint8_t ENC28J60_ReadPacket(uint8_t *buf, uint16_t maxlen, uint16_t *rx_len){ uint16_t rdptr,len; uint8_t status; if(ENC28J60_ReadReg(0,EPKTCNT)==0) return 0; ENC_CS = 0; SPI_RW_Byte(ENC_RBM); rdptr = SPI_RW_Byte(0xFF); rdptr |= (SPI_RW_Byte(0xFF)<<8); len = SPI_RW_Byte(0xFF); len |= (SPI_RW_Byte(0xFF)<<8); status = SPI_RW_Byte(0xFF); len -=4; if(len>maxlen) len = maxlen; for(uint16_t i=0;i<len;i++) buf = SPI_RW_Byte(0xFF); ENC_CS = 1; *rx_len = len; rdptr += len +4; ENC28J60_WriteReg(0,ERXRDPT,rdptr&0xFF); ENC28J60_WriteReg(0,ERXRDPT+1,rdptr>>8); ENC28J60_WriteReg(0,ECON2,0x01); return 1;}void ENC28J60_SendPacket(uint8_t *buf, uint16_t len){ uint16_t i; ENC28J60_WriteReg(0,ETXST, TXSTART_INIT&0xFF); ENC28J60_WriteReg(0,ETXST+1,TXSTART_INIT>>8); ENC28J60_WriteReg(0,ETXND, (TXSTART_INIT+len)&0xFF); ENC28J60_WriteReg(0,ETXND+1,(TXSTART_INIT+len)>>8); ENC_CS = 0; SPI_RW_Byte(ENC_WBM); SPI_RW_Byte(0x00); for(i=0;i<len;i++) SPI_RW_Byte(buf); ENC_CS = 1; ENC28J60_WriteReg(0,ECON1,0x02); while(ENC28J60_ReadReg(0,ECON1)&0x02);}//==== EEPROM CRC读写 ====uint16_t CFG_Calc_CRC(NET_CFG *cfg){ uint16_t sum=0; uint8_t *p = (uint8_t*)cfg; for(uint16_t i=0; i<sizeof(NET_CFG)-2; i++) { sum += p; } return sum;}uint8_t EEPROM_Read_Byte(uint16_t addr){ IAP_ADDRH = addr >> 8; IAP_ADDRL = addr & 0xFF; IAP_CMD = 0x01; IAP_TRIG = 0x5A; IAP_TRIG = 0xA5; return IAP_DATA;}void EEPROM_Write_Byte(uint16_t addr, uint8_t dat){ IAP_ADDRH = addr >> 8; IAP_ADDRL = addr & 0xFF; IAP_DATA = dat; IAP_CMD = 0x02; IAP_TRIG = 0x5A; IAP_TRIG = 0xA5; IAP_CMD = 0x00;}uint8_t EEPROM_Save_New_Cfg(NET_CFG *newcfg){ uint16_t write_pos = 0; NET_CFG_T temp; uint16_t cfg_size = sizeof(NET_CFG); newcfg->magic = CFG_HEAD_MAGIC; newcfg->crc = CFG_Calc_CRC(newcfg); for(write_pos = 0; write_pos <= EEPROM_SIZE - cfg_size; write_pos += cfg_size) { NET_CFG temp; uint8_t *p = (uint8_t*)&temp; for(uint16_t i=0; i<cfg_size; i++) { p = EEPROM_Read_Byte(write_pos+i); } if(temp.magic != CFG_HEAD_MAGIC) break; } if(write_pos > EEPROM_SIZE - cfg_size) { write_pos = 0; } uint8_t *p = (uint8_t*)newcfg; for(uint16_t i=0; i<cfg_size; i++) { EEPROM_Write_Byte(write_pos+i, p); } UART_SendStr("Save config ok\r\n"); return 1;}uint8_t EEPROM_Load_Last_Cfg(NET_CFG *outcfg){ uint16_t read_pos = 0; uint16_t last_valid = 0xFFFF; uint16_t cfg_size = sizeof(NET_CFG); memset(outcfg, 0, sizeof(NET_CFG)); for(read_pos = 0; read_pos <= EEPROM_SIZE - cfg_size; read_pos += cfg_size) { NET_CFG temp; uint8_t *p = (uint8_t*)&temp; for(uint16_t i=0; i<cfg_size; i++) { p = EEPROM_Read_Byte(read_pos+i); } if(temp.magic == CFG_HEAD_MAGIC && temp.crc == CFG_Calc_CRC(&temp)) { last_valid = read_pos; } } if(last_valid == 0xFFFF) { UART_SendStr("No valid cfg, load default\r\n"); outcfg->magic = CFG_HEAD_MAGIC; outcfg->mac[0]=0x00;outcfg->mac[1]=0x08;outcfg->mac[2]=0xdc; outcfg->mac[3]=0x11;outcfg->mac[4]=0x22;outcfg->mac[5]=0x34; outcfg->ip[0]=192;outcfg->ip[1]=168;outcfg->ip[2]=1;outcfg->ip[3]=100; outcfg->mask[0]=255;outcfg->mask[1]=255;outcfg->mask[2]=255;outcfg->mask[3]=0; outcfg->gw[0]=192;outcfg->gw[1]=168;outcfg->gw[2]=1;outcfg->gw[3]=1; outcfg->local_port = 8080; outcfg->remote_ip[0]=192;outcfg->remote_ip[1]=168;outcfg->remote_ip[2]=1;outcfg->remote_ip[3]=200; outcfg->remote_port = 8080; outcfg->mode = 0; strcpy((char*)outcfg->web_pwd,"123456"); outcfg->idle_timeout = 1000; outcfg->crc = CFG_Calc_CRC(outcfg); EEPROM_Save_New_Cfg(outcfg); return 0; } uint8_t *p = (uint8_t*)outcfg; for(uint16_t i=0; i<cfg_size; i++) { p = EEPROM_Read_Byte(last_valid+i); } UART_SendStr("Load last config ok\r\n"); return 1;}//==== URL解码 ====uint8_t hex2byte(uint8_t c){ if(c >= '0' && c <= '9') return c-'0'; if(c >= 'A' && c <= 'F') return c-'A'+10; if(c >= 'a' && c <= 'f') return c-'a'+10; return 0;}void UrlDecode(uint8_t *dst, uint8_t *src){ while(*src) { if(*src == '%') { src++; *dst = (hex2byte(*src) <<4) | hex2byte(*(src+1)); src+=2; }else if(*src == '+') { *dst = ' '; src++; }else{ *dst = *src; src++; } dst++; } *dst = 0;}//==== WEB网页页面 ====const char login_page[] ="HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=utf-8\r\n\r\n""<html><head><meta charset='utf-8'><title>登录</title></head>""<body><h2>ENC28J60 网页登录</h2>""<form method='post'>""密码:<input name='pwd' type='password'><br>""<input type='submit' value='登录'>""</form></body></html>";const char pwd_err_page[] ="HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=utf-8\r\n\r\n""<html><body><h3>密码错误!</h3><a href='/'>返回登录</a></body></html>";const char save_ok_page[] ="HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=utf-8\r\n\r\n""<html><body><h3>参数保存成功!重启单片机生效</h3><a href='/'>返回配置页</a></body></html>";void Web_Send_LoginPage(void){ memcpy(uip_appdata, login_page, strlen(login_page)); uip_send(uip_appdata, strlen(login_page));}void Web_Send_PwdErr(void){ memcpy(uip_appdata, pwd_err_page, strlen(pwd_err_page)); uip_send(uip_appdata, strlen(pwd_err_page));}void Web_Send_SaveOk(void){ memcpy(uip_appdata, save_ok_page, strlen(save_ok_page)); uip_send(uip_appdata, strlen(save_ok_page));}void Web_Send_ConfigPage(void){ uint8_t tmpbuf[768]; sprintf((char*)tmpbuf, "HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=utf-8\r\n\r\n" "<html><head><meta charset='utf-8'><title>STC32G ENC28J60配置</title></head>" "<body>" "<h2>网络参数设置</h2>" "<form method='post'>" "MAC:%02x:%02x:%02x:%02x:%02x:%02x<br>" "本机IP:<input name='ip' value='%d.%d.%d.%d'><br>" "子网掩码:<input name='sn' value='%d.%d.%d.%d'><br>" "网关:<input name='gw' value='%d.%d.%d.%d'><br>" "TCP服务端口:<input name='sport' value='%d'><br>" "客户端目标IP:<input name='cip' value='%d.%d.%d.%d'><br>" "客户端目标端口:<input name='cport' value='%d'><br>" "模式(0服务端/1客户端):<input name='mode' value='%d'><br>" "TCP空闲超时(10ms单位):<input name='idleto' value='%d'><br>" "网页密码:<input name='webpwd' value='%s'><br>" "<input type='submit' value='保存配置'><br>" "<p>保存后重启生效</p>" "</form></body></html>", g_netcfg.mac[0],g_netcfg.mac[1],g_netcfg.mac[2],g_netcfg.mac[3],g_netcfg.mac[4],g_netcfg.mac[5], g_netcfg.ip[0],g_netcfg.ip[1],g_netcfg.ip[2],g_netcfg.ip[3], g_netcfg.mask[0],g_netcfg.mask[1],g_netcfg.mask[2],g_netcfg.mask[3], g_netcfg.gw[0],g_netcfg.gw[1],g_netcfg.gw[2],g_netcfg.gw[3], g_netcfg.local_port, g_netcfg.remote_ip[0],g_netcfg.remote_ip[1],g_netcfg.remote_ip[2],g_netcfg.remote_ip[3], g_netcfg.remote_port, g_netcfg.mode, g_netcfg.idle_timeout, g_netcfg.web_pwd ); memcpy(uip_appdata, tmpbuf, strlen((char*)tmpbuf)); uip_send(uip_appdata, strlen((char*)tmpbuf));}void Web_Parse_Post(uint8_t *buf, uint16_t len){ uint8_t decode_buf[512]; UrlDecode(decode_buf, buf); if(strstr((char*)decode_buf,"pwd=")) { char pwd[16]; sscanf((char*)decode_buf,"pwd=%s",pwd); if(strcmp(pwd,(char*)g_netcfg.web_pwd)==0) { Web_Send_ConfigPage(); }else{ Web_Send_PwdErr(); } return; } if(strstr((char*)decode_buf,"ip=")) { uint8_t new_ip[4], new_sn[4], new_gw[4], new_cip[4]; uint16_t new_sp, new_cp, new_idleto; uint8_t new_mode; char new_pwd[16]; sscanf((char*)decode_buf, "ip=%d.%d.%d.%d&sn=%d.%d.%d.%d&gw=%d.%d.%d.%d&sport=%d&cip=%d.%d.%d.%d&cport=%d&mode=%d&idleto=%d&webpwd=%s", &new_ip[0],&new_ip[1],&new_ip[2],&new_ip[3], &new_sn[0],&new_sn[1],&new_sn[2],&new_sn[3], &new_gw[0],&new_gw[1],&new_gw[2],&new_gw[3], &new_sp, &new_cip[0],&new_cip[1],&new_cip[2],&new_cip[3], &new_cp, &new_mode, &new_idleto, new_pwd); if(new_idleto < 200) new_idleto = 200; memcpy(g_netcfg.ip, new_ip,4); memcpy(g_netcfg.mask, new_sn,4); memcpy(g_netcfg.gw, new_gw,4); memcpy(g_netcfg.remote_ip, new_cip,4); g_netcfg.local_port = new_sp; g_netcfg.remote_port = new_cp; g_netcfg.mode = new_mode; g_netcfg.idle_timeout = new_idleto; strncpy((char*)g_netcfg.web_pwd, new_pwd,15); g_netcfg.web_pwd[15]=0; EEPROM_Save_New_Cfg(&g_netcfg); Web_Send_SaveOk(); }}void HTTP_Web_Task(void){ if(uip_newdata()) { if(strstr((char*)uip_appdata,"POST")) { Web_Parse_Post(uip_appdata, uip_datalen()); } else if(strstr((char*)uip_appdata,"GET")) { Web_Send_LoginPage(); } }}//====串口延时====void UART1_Init(void){ SCON = 0x50; TMOD |= 0x20; TH1 = 0xF3; TL1 = 0xF3; TR1 = 1;}void UART_SendByte(uint8_t ch){ SBUF = ch; while(!TI); TI=0;}void UART_SendStr(char *s){ while(*s) UART_SendByte(*s++);}void UART_PrintNum(uint16_t n){ char tmp[8]; sprintf(tmp,"%d",n); UART_SendStr(tmp);}void Delay_ms(uint32_t ms){ uint32_t i,j; for(i=0;i<ms;i++) for(j=0;j<1200;j++);}uip.h#ifndef __UIP_H__#define __UIP_H__#include <stdint.h>#define UIP_BUFSIZE 600#define UIP_ETHTYPE_IP 0x0800#define UIP_ETHTYPE_ARP 0x0806#define UIP_PROTO_TCP 6#define UIP_PROTO_IP 4typedef union uip_ipaddr_t{ uint8_t u8[4]; uint16_t u16[2];}uip_ipaddr_t;#define HTONS(n) (((n) << 8) | ((n) >> 8))#define UIP_IPADDR(p,a,b,c,d) do{(p)->u8[0]=a;(p)->u8[1]=b;(p)->u8[2]=c;(p)->u8[3]=d;}while(0)void uip_init(void);void uip_setethaddr(uint8_t *mac);void uip_sethostaddr(uip_ipaddr_t *addr);void uip_setnetmask(uip_ipaddr_t *mask);void uip_setgwaddr(uip_ipaddr_t *gw);void uip_listen(uint16_t port);void uip_connect(uip_ipaddr_t *rip, uint16_t rport);void uip_close(void);void uip_input(void);void uip_send(void *data, uint16_t len);extern uint8_t uip_buf[UIP_BUFSIZE];extern uint16_t uip_len;extern struct uip_conn *uip_conn;extern void *uip_appdata;extern uint16_t uip_datalen;#define uip_newdata() (uip_datalen>0)#define uip_rexmit() 0#define uip_poll() 0#define uip_acked() 0struct uip_conn{ uip_ipaddr_t rip; uint16_t rport; uint16_t lport; uint8_t state;};#endifuip.c#include "uip.h"#include "uip_arp.h"uint8_t uip_buf[UIP_BUFSIZE];uint16_t uip_len = 0;struct uip_conn *uip_conn = NULL;void *uip_appdata;uint16_t uip_datalen = 0;static uint8_t ethaddr[6];static uip_ipaddr_t hostaddr;static uip_ipaddr_t netmask;static uip_ipaddr_t gwaddr;static uint16_t listen_port = 0;static struct uip_conn conn;#define TCP_SYN 0x02#define TCP_ACK 0x10#define TCP_FIN 0x01#define TCP_RST 0x04enum TCP_STATE{CLOSED,LISTEN,SYN_RCVD,ESTABLISHED,FIN_WAIT,CLOSING,TIME_WAIT,CLOSE_WAIT,LAST_ACK};void uip_setethaddr(uint8_t *mac){ memcpy(ethaddr,mac,6);}void uip_sethostaddr(uip_ipaddr_t *addr){ memcpy(&hostaddr,addr,4);}void uip_setnetmask(uip_ipaddr_t *mask){ memcpy(&netmask,mask,4);}void uip_setgwaddr(uip_ipaddr_t *gw){ memcpy(&gwaddr,gw,4);}void uip_listen(uint16_t port){ listen_port = port; conn.state = LISTEN; conn.lport = port; uip_conn = &conn;}void uip_close(void){ conn.state = CLOSED; uip_conn = NULL; uip_len = 0;}void uip_connect(uip_ipaddr_t *rip, uint16_t rport){ memcpy(&conn.rip,rip,4); conn.rport = rport; conn.lport = listen_port; conn.state = SYN_RCVD; uip_conn = &conn;}void uip_init(void){ uip_len = 0; uip_conn = NULL; conn.state = CLOSED;}void uip_input(void){ uint16_t type = (uip_buf[12]<<8)|uip_buf[13]; uip_datalen = 0; if(type == UIP_ETHTYPE_ARP) { uip_arp_arpin(); return; } if(type == UIP_ETHTYPE_IP) { uint8_t iplen = (uip_buf[14]&0x0F)*4; uint8_t proto = uip_buf[23]; if(proto == UIP_PROTO_TCP) { uint16_t tcp_hdr_len = ((uip_buf[14+iplen+12]>>4))*4; uip_appdata = &uip_buf[14+iplen + tcp_hdr_len]; uip_datalen = uip_len - (14+iplen+tcp_hdr_len); } }}void uip_send(void *data, uint16_t len){ memcpy(uip_appdata, data, len); uip_len = len;}uip_arp.h#ifndef __UIP_ARP_H#define __UIP_ARP_H#include "uip.h"void uip_arp_ipin(void);void uip_arp_arpin(void);void uip_arp_out(void);#endifuip_arp.c#include "uip_arp.h"#include "enc28j60.h"#define ARP_REQUEST 1#define ARP_REPLY 2typedef struct{ uint16_t hwtype; uint16_t proto; uint8_t hwlen,protolen; uint16_t op; uint8_t senderhwaddr[6]; uint8_t senderipaddr[4]; uint8_t targethwaddr[6]; uint8_t targetipaddr[4];}arp_hdr;void uip_arp_ipin(void){}void uip_arp_arpin(void){ arp_hdr *arp = (arp_hdr*)(uip_buf+14); if(arp->op == ARP_REQUEST) { memcpy(&uip_buf[0], arp->senderhwaddr,6); memcpy(&uip_buf[6], g_netcfg.mac,6); uip_buf[12]=0x08;uip_buf[13]=0x06; arp->op = HTONS(ARP_REPLY); memcpy(arp->targethwaddr, arp->senderhwaddr,6); memcpy(arp->targetipaddr, arp->senderipaddr,4); memcpy(arp->senderhwaddr, g_netcfg.mac,6); memcpy(arp->senderipaddr, g_netcfg.ip,4); uip_len = 14+sizeof(arp_hdr); }}void uip_arp_out(void){}main.c#include "enc28j60.h"#include "uip.h"#include "uip_arp.h"#define BUF_SIZE UIP_BUFSIZEstatic uint8_t buf[BUF_SIZE];static uint16_t idle_tick = 0;static uint16_t reconnect_tick = 0;void tcp_server_init(uint16_t port){ uip_init(); uip_setethaddr(g_netcfg.mac); uip_ipaddr_t ip,mask,gw; UIP_IPADDR(&ip, g_netcfg.ip[0],g_netcfg.ip[1],g_netcfg.ip[2],g_netcfg.ip[3]); UIP_IPADDR(&mask,g_netcfg.mask[0],g_netcfg.mask[1],g_netcfg.mask[2],g_netcfg.mask[3]); UIP_IPADDR(&gw, g_netcfg.gw[0],g_netcfg.gw[1],g_netcfg.gw[2],g_netcfg.gw[3]); uip_sethostaddr(&ip); uip_setnetmask(&mask); uip_setgwaddr(&gw); uip_listen(HTONS(port)); UART_SendStr("TCP Server listen port:"); UART_PrintNum(port); UART_SendStr("\r\n");}void tcp_client_connect(uint8_t *rip, uint16_t rport){ uip_ipaddr_t server_ip; UIP_IPADDR(&server_ip, rip[0],rip[1],rip[2],rip[3]); uip_connect(&server_ip, HTONS(rport)); UART_SendStr("TCP Client connect to "); UART_PrintNum(rip[0]);UART_SendByte('.'); UART_PrintNum(rip[1]);UART_SendByte('.'); UART_PrintNum(rip[2]);UART_SendByte('.'); UART_PrintNum(rip[3]);UART_SendStr(":"); UART_PrintNum(rport);UART_SendStr("\r\n");}void tcp_close_conn(void){ uip_close(); idle_tick = 0;}void tcp_task(void){ uint16_t rxlen; if(ENC28J60_ReadPacket(buf,BUF_SIZE,&rxlen)) { memcpy(uip_buf,buf,rxlen); uip_len = rxlen; uip_arp_ipin(); uip_input(); HTTP_Web_Task(); if(uip_len>0) { uip_arp_out(); ENC28J60_SendPacket(uip_buf,uip_len); uip_len = 0; } idle_tick = 0; } if(uip_conn != NULL) { if(uip_newdata()) { UART_SendStr("TCP RX:"); UART_SendStr((char*)uip_appdata); UART_SendStr("\r\n"); uip_send(uip_appdata, uip_datalen()); } idle_tick++; if(idle_tick >= g_netcfg.idle_timeout) { UART_SendStr("TCP idle timeout, close connection\r\n"); tcp_close_conn(); idle_tick = 0; } if(uip_len>0) { ENC28J60_SendPacket(uip_buf,uip_len); uip_len = 0; } } else { if(g_netcfg.mode == 1) { reconnect_tick++; if(reconnect_tick > 200) { reconnect_tick = 0; UART_SendStr("Client reconnect attempt\r\n"); tcp_client_connect(g_netcfg.remote_ip, g_netcfg.remote_port); } } }}void main(void){ IAP_CONTR = 0x80; UART1_Init(); SPI_HW_Init(); UART_SendStr("STC32G+ENC28J60 Start\r\n"); EEPROM_Load_Last_Cfg(&g_netcfg); ENC28J60_Init(&g_netcfg); if(g_netcfg.mode == 0) { tcp_server_init(g_netcfg.local_port); }else{ uip_init(); uip_setethaddr(g_netcfg.mac); uip_ipaddr_t ip,mask,gw; UIP_IPADDR(&ip, g_netcfg.ip[0],g_netcfg.ip[1],g_netcfg.ip[2],g_netcfg.ip[3]); UIP_IPADDR(&mask,g_netcfg.mask[0],g_netcfg.mask[1],g_netcfg.mask[2],g_netcfg.mask[3]); UIP_IPADDR(&gw, g_netcfg.gw[0],g_netcfg.gw[1],g_netcfg.gw[2],g_netcfg.gw[3]); uip_sethostaddr(&ip); uip_setnetmask(&mask); uip_setgwaddr(&gw); } while(1) { tcp_task(); Delay_ms(10); }}工程使用说明- enc28j60.h / enc28j60.c
- uip.h / uip.c
- uip_arp.h / uip_arp.c
- main.c
- 上电读取 EEPROM 保存的网络参数;无有效配置自动加载默认参数并保存到 EEPROM
- 打开浏览器访问本机 IP(默认 192.168.1.100),密码123456,可以修改:MAC、IP、掩码、网关、TCP 端口、服务器 / 客户端模式、空闲超时时间
- 提交保存参数,重启单片机生效
- 功能✅ TCP 服务器:同一时间只能 1 个 TCP 客户端接入,超过空闲超时无数据自动断开,可以等待下一个客户端✅ TCP 客户端:断线自动重连远端 TCP 服务器✅ 网页配置所有网络参数,参数保存到片内 EEPROM,断电不丢失✅ 串口打印调试信息,115200 波特
|
|