单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
一、客户端
主函数
void lwip_test_ui(uint8_t mode)
{
uint8_t speed;
uint8_t buf[30];
if(mode & 1<< 0)
{
lcd_show_string(6, 10, 200, 32, 32, "STM32", DARKBLUE);
lcd_show_string(6, 40, lcddev.width, 24, 24, "lwIP TCPClient Test", DARKBLUE);
lcd_show_string(6, 70, 200, 16, 16, "ATOM@ALIENTEK", DARKBLUE);
}
if(mode & 1 << 1)
{
lcd_show_string(6, 110, 200, 16, 16, "lwIP Init Successed", MAGENTA);
if(g_lwipdev.dhcpstatus == 2)
{
sprintf((char*)buf,"DHCP IP:%d.%d.%d.%d",g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]); /* 显示动态IP地址 */
}
else
{
sprintf((char*)buf,"Static IP:%d.%d.%d.%d",g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]); /* 打印静态IP地址 */
}
lcd_show_string(6, 130, 200, 16, 16, (char*)buf, MAGENTA);
speed = ethernet_chip_get_speed(); /* 得到网速 */
if(speed)
{
lcd_show_string(6, 150, 200, 16, 16, "Ethernet Speed:100M", MAGENTA);
}
else
{
lcd_show_string(6, 150, 200, 16, 16, "Ethernet Speed:10M", MAGENTA);
}
}
}
int main(void)
{
uint8_t key;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
usmart_dev.init(84); /* 初始化USMART */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
key_init(); /* 初始化按键 */
my_mem_init(SRAMIN); /* 初始化内部SRAM内存池 */
my_mem_init(SRAMCCM); /* 初始化内部SRAMCCM内存池 */
lwip_test_ui(1); /* 加载前半部分UI */
lcd_show_string(6, 110, 200, 16, 16, "lwIP Init !!", BLUE);
while (lwip_comm_init() != 0)
{
lcd_show_string(6, 110, 200, 16, 16, "lwIP Init failed!!", BLUE);
delay_ms(500);
lcd_fill(6, 50, 200 + 30, 50 + 16, WHITE);
lcd_show_string(6, 110, 200, 16, 16, "Retrying... ", BLUE);
delay_ms(500);
LED1_TOGGLE();
}
while (!ethernet_read_phy(PHY_SR)) /* 检查MCU与PHY芯片是否通信成功 */
{
printf("MCU与PHY芯片通信失败,请检查电路或者源码!!!!\r\n");
}
#if LWIP_DHCP
lcd_show_string(6, 130, 200, 16, 16, "DHCP IP configing... ", BLUE); /* 开始DHCP */
while ((g_lwipdev.dhcpstatus != 2)&&(g_lwipdev.dhcpstatus != 0XFF)) /* 等待DHCP获取成功/超时溢出 */
{
lwip_periodic_handle();
}
#endif
lwip_demo(); /* lwIP程序入口 */
lwip_test_ui(2); /* 加载后半部分UI */
while(1)
{
lwip_periodic_handle(); /* LWIP轮询任务 */
key = key_scan(0);
if (key == KEY1_PRES)
{
if((g_lwip_send_flag & 1 << 5))
{
printf("连接已经建立,不能重复连接\r\n"); /* 如果连接成功,不做任何处理 */
}
else
{
lwip_demo(); /* 当断开连接后,调用lwip_demo()函数 */
}
}
delay_ms(10);
}
}
void lwip_demo(void)
{
struct tcp_pcb *tcppcb; /* 定义一个TCP客户端控制块 */
ip_addr_t rmtipaddr; /* 远端ip地址 */
char *tbuf;
uint8_t key;
uint8_t res = 0;
uint8_t t = 0;
lwip_tcp_client_set_remoteip(); /* 先选择IP */
lcd_clear(WHITE); /* 清屏 */
g_point_color = RED;
lcd_show_string(5, 30, 200, 16, 16, "STM32", g_point_color);
lcd_show_string(5, 50, 200, 16, 16, "TCP Client Test", g_point_color);
lcd_show_string(5, 70, 200, 16, 16, "ATOM@ALIENTEK", g_point_color);
lcd_show_string(5, 90, 200, 16, 16, "KEY0:Send data", g_point_color);
lcd_show_string(5, 110, 200, 16, 16, "KEY1:Quit", g_point_color);
tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */
if (tbuf == NULL)return ; /* 内存申请失败了,直接退出 */
sprintf((char *)tbuf, "Local IP:%d.%d.%d.%d", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); /* 服务器IP */
lcd_show_string(5, 130, 210, 16, 16, tbuf, g_point_color);
sprintf((char *)tbuf, "Remote IP:%d.%d.%d.%d", g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]); /* 远端IP */
lcd_show_string(5, 150, 210, 16, 16, tbuf, g_point_color);
sprintf((char *)tbuf, "Remote Port:%d", LWIP_DEMO_PORT); /* 客户端端口号 */
lcd_show_string(5, 170, 210, 16, 16, tbuf, g_point_color);
g_point_color = BLUE;
lcd_show_string(5, 190, 210, 16, 16, "STATUS:Disconnected", g_point_color);
tcppcb = tcp_new(); /* 创建一个新的pcb */
if (tcppcb) /* 创建成功 */
{
IP4_ADDR(&rmtipaddr, g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]);
tcp_connect(tcppcb, &rmtipaddr, LWIP_DEMO_PORT, lwip_tcp_client_connected); /* 连接到目的地址的指定端口上,当连接成功后回调lwip_tcp_client_connected()函数 */
}
else res = 1;
while (res == 0)
{
key = key_scan(0);
if (key == KEY1_PRES)break;
if (key == KEY0_PRES) /* KEY0按下了,发送数据 */
{
lwip_tcp_client_usersent(tcppcb); /* 发送数据 */
}
if (g_lwip_send_flag & 1 << 6) /* 是否收到数据 */
{
lcd_fill(5, 230, lcddev.width - 1, lcddev.height - 1, WHITE); /* 清上一次数据 */
lcd_show_string(5, 230, lcddev.width - 30, lcddev.height - 230, 16, (char *)g_lwip_demo_recvbuf, g_point_color); /* 显示接收到的数据 */
g_lwip_send_flag &= ~(1 << 6); /* 标记数据已经被处理了 */
}
if (g_lwip_send_flag & 1 << 5) /* 是否连接上 */
{
lcd_show_string(5, 190, lcddev.width - 30, lcddev.height - 190, 16, "STATUS:Connected ", g_point_color); /* 提示消息 */
g_point_color = RED;
lcd_show_string(5, 210, lcddev.width - 30, lcddev.height - 190, 16, "Receive Data:", g_point_color); /* 提示消息 */
g_point_color = BLUE;
}
else if ((g_lwip_send_flag & 1 << 5) == 0)
{
lcd_show_string(5, 190, 190, 16, 16, "STATUS:Disconnected", g_point_color);
lcd_fill(5, 210, lcddev.width - 1, lcddev.height - 1, WHITE); /* 清屏 */
}
lwip_periodic_handle(); /* LWIP轮询任务 */
delay_ms(2);
t++;
if (t == 200)
{
if ((g_lwip_send_flag & 1 << 5) == 0) /* 未连接上,则尝试重连 */
{
lwip_tcp_client_connection_close(tcppcb, 0); /* 关闭连接 */
tcppcb = tcp_new(); /* 创建一个新的pcb */
if (tcppcb) /* 创建成功 */
{
tcp_connect(tcppcb, &rmtipaddr, LWIP_DEMO_PORT, lwip_tcp_client_connected); /* 连接到目的地址的指定端口上,当连接成功后回调lwip_tcp_client_connected()函数 */
}
}
t = 0;
LED0_TOGGLE();
}
}
lwip_tcp_client_connection_close(tcppcb, 0); /* 关闭TCP Client连接 */
lcd_clear(WHITE); /* 清屏 */
g_point_color = DARKBLUE;
lcd_show_string(5, 30, 200, 16, 16, "STM32", g_point_color);
lcd_show_string(5, 50, 200, 16, 16, "TCPclient Test", g_point_color);
lcd_show_string(5, 70, 200, 16, 16, "ATOM@ALIENTEK", g_point_color);
lcd_show_string(5, 90, 200, 16, 16, "KEY1:Connect", g_point_color);
lcd_show_string(5, 190, 210, 16, 16, "STATUS:Disconnected", g_point_color);
myfree(SRAMIN, tbuf);
}
测试结果:


二、服务器
/* tcp服务器连接状态 */
enum tcp_server_states
{
ES_TCPSERVER_NONE = 0, /* 初始化 */
ES_TCPSERVER_ACCEPTED, /* 连接状态 */
ES_TCPSERVER_CLOSING, /* 关闭连接状态 */
};
/* LWIP回调函数使用的结构体 */
struct tcp_server_struct
{
uint8_t state; /* 当前状态 */
struct tcp_pcb *pcb; /* 指向TCP控制块 */
struct pbuf *p; /* 指向接收/传输的pbuf */
};
err_t lwip_tcp_server_accept(void *arg,struct tcp_pcb *newpcb,err_t err);
err_t lwip_tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
void lwip_tcp_server_error(void *arg,err_t err);
err_t lwip_tcp_server_usersent(struct tcp_pcb *tpcb);
err_t lwip_tcp_server_poll(void *arg, struct tcp_pcb *tpcb);
err_t lwip_tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
void lwip_tcp_server_senddata(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
void lwip_tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_struct *es);
void lwip_tcp_server_remove_timewait(void);
/**
* @brief lwip_demo 测试
* @param 无
* @retval 无
*/
void lwip_demo(void)
{
err_t err;
struct tcp_pcb *tcppcbnew; /* 定义一个TCP服务器控制块 */
struct tcp_pcb *tcppcbconn; /* 定义一个TCP服务器控制块 */
char *tbuf;
uint8_t key;
uint8_t res = 0;
uint8_t t = 0;
lcd_clear(WHITE); /* 清屏 */
g_point_color = RED;
lcd_show_string(5, 30, 200, 16, 16, "STM32", g_point_color);
lcd_show_string(5, 50, 200, 16, 16, "TCP Server Test", g_point_color);
lcd_show_string(5, 70, 200, 16, 16, "ATOM@ALIENTEK", g_point_color);
lcd_show_string(5, 90, 200, 16, 16, "KEY0:Send data", g_point_color);
tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */
if (tbuf == NULL)return ; /* 内存申请失败了,直接退出 */
sprintf((char *)tbuf, "Server IP:%d.%d.%d.%d", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]); /* 服务器IP */
lcd_show_string(5, 130, 210, 16, 16, tbuf, g_point_color);
sprintf((char *)tbuf, "Server Port:%d", LWIP_DEMO_PORT); /* 服务器端口号 */
lcd_show_string(5, 150, 210, 16, 16, tbuf, g_point_color);
tcppcbnew = tcp_new(); /* 创建一个新的pcb */
if (tcppcbnew) /* 创建成功 */
{
err = tcp_bind(tcppcbnew, IP_ADDR_ANY, LWIP_DEMO_PORT); /* 将本地IP与指定的端口号绑定在一起,IP_ADDR_ANY为绑定本地所有的IP地址 */
if (err == ERR_OK) /* 绑定完成 */
{
tcppcbconn = tcp_listen(tcppcbnew); /* 设置tcppcb进入监听状态 */
tcp_accept(tcppcbconn, lwip_tcp_server_accept); /* 初始化LWIP的tcp_accept的回调函数 */
}
else res = 1;
}
else res = 1;
g_point_color = BLUE;
while (res == 0)
{
key = key_scan(0);
if (key == KEY0_PRES) /* KEY0按下了,发送数据 */
{
lwip_tcp_server_usersent(tcppcbnew); /* 发送数据 */
}
if (g_lwip_send_flag & 1 << 6) /* 是否收到数据 */
{
lcd_fill(5, 210, lcddev.width - 1, lcddev.height - 1, WHITE); /* 清上一次数据 */
lcd_show_string(5, 210, lcddev.width - 30, lcddev.height - 210, 16, (char *)g_lwip_demo_recvbuf, g_point_color); /* 显示接收到的数据 */
g_lwip_send_flag &= ~(1 << 6); /* 标记数据已经被处理了 */
}
if (g_lwip_send_flag & 1 << 5) /* 是否连接上 */
{
sprintf((char *)tbuf, "Client IP:%d.%d.%d.%d", g_lwipdev.remoteip[0], g_lwipdev.remoteip[1], g_lwipdev.remoteip[2], g_lwipdev.remoteip[3]); /* 客户端IP */
lcd_show_string(5, 170, 230, 16, 16, tbuf, g_point_color);
g_point_color = RED;
lcd_show_string(5, 190, lcddev.width - 30, lcddev.height - 190, 16, "Receive Data:", g_point_color); /* 提示消息 */
g_point_color = BLUE;
}
else if (g_lwip_send_flag & 1 << 5)
{
lcd_fill(5, 170, lcddev.width - 1, lcddev.height - 1, WHITE); /* 清屏 */
}
lwip_periodic_handle();
delay_ms(2);
t++;
if (t == 200)
{
t = 0;
LED0_TOGGLE();
}
}
}
/**
* @brief lwIP tcp_accept()的回调函数
* @param arg :传入的参数
* @param newpcb:TCP控制块
* @param err :错误码
* @retval 返回 ret_err
*/
err_t lwip_tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcp_server_struct *es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
tcp_setprio(newpcb, TCP_PRIO_MIN); /* 设置新创建的pcb优先级 */
es = (struct tcp_server_struct *)mem_malloc(sizeof(struct tcp_server_struct)); /* 分配内存 */
if (es != NULL) /* 内存分配成功 */
{
es->state = ES_TCPSERVER_ACCEPTED; /* 接收连接 */
es->pcb = newpcb;
es->p = NULL;
tcp_arg(newpcb, es);
tcp_recv(newpcb, lwip_tcp_server_recv); /* 初始化tcp_recv()的回调函数 */
tcp_err(newpcb, lwip_tcp_server_error); /* 初始化tcp_err()回调函数 */
tcp_poll(newpcb, lwip_tcp_server_poll, 1); /* 初始化tcp_poll回调函数 */
tcp_sent(newpcb, lwip_tcp_server_sent); /* 初始化发送回调函数 */
g_lwip_send_flag |= 1 << 5; /* 标记有客户端连上了 */
g_lwipdev.remoteip[0] = newpcb->remote_ip.addr & 0xff; /* IADDR4 */
g_lwipdev.remoteip[1] = (newpcb->remote_ip.addr >> 8) & 0xff; /* IADDR3 */
g_lwipdev.remoteip[2] = (newpcb->remote_ip.addr >> 16) & 0xff; /* IADDR2 */
g_lwipdev.remoteip[3] = (newpcb->remote_ip.addr >> 24) & 0xff; /* IADDR1 */
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err;
}
/**
* @brief lwIP tcp_recv()函数的回调函数
* @param arg :传入的参数
* @param tpcb:TCP控制块
* @param p :网络数据包
* @param err :错误码
* @retval 返回 ret_err
*/
err_t lwip_tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
uint32_t data_len = 0;
struct pbuf *q;
struct tcp_server_struct *es;
LWIP_ASSERT("arg != NULL", arg != NULL);
es = (struct tcp_server_struct *)arg;
if (p == NULL) /* 从客户端接收到空数据 */
{
es->state = ES_TCPSERVER_CLOSING; /* 需要关闭TCP 连接了 */
es->p = p;
ret_err = ERR_OK;
}
else if (err != ERR_OK) /* 从客户端接收到一个非空数据,但是由于某种原因err!=ERR_OK */
{
if (p)pbuf_free(p); /* 释放接收pbuf */
ret_err = err;
}
else if (es->state == ES_TCPSERVER_ACCEPTED) /* 处于连接状态 */
{
if (p != NULL) /* 当处于连接状态并且接收到的数据不为空时将其打印出来 */
{
memset(g_lwip_demo_recvbuf, 0, LWIP_DEMO_RX_BUFSIZE); /* 数据接收缓冲区清零 */
for (q = p; q != NULL; q = q->next) /* 遍历完整个pbuf链表 */
{
/* 判断要拷贝到LWIP_DEMO_RX_BUFSIZE中的数据是否大于LWIP_DEMO_RX_BUFSIZE的剩余空间,如果大于 */
/* 的话就只拷贝LWIP_DEMO_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据 */
if (q->len > (LWIP_DEMO_RX_BUFSIZE - data_len)) memcpy(g_lwip_demo_recvbuf + data_len, q->payload, (LWIP_DEMO_RX_BUFSIZE - data_len)); /* 拷贝数据 */
else memcpy(g_lwip_demo_recvbuf + data_len, q->payload, q->len);
data_len += q->len;
if (data_len > LWIP_DEMO_RX_BUFSIZE) break; /* 超出TCP客户端接收数组,跳出 */
}
g_lwip_send_flag |= 1 << 6; /* 标记接收到数据了 */
g_lwipdev.remoteip[0] = tpcb->remote_ip.addr & 0xff; /* IADDR4 */
g_lwipdev.remoteip[1] = (tpcb->remote_ip.addr >> 8) & 0xff; /* IADDR3 */
g_lwipdev.remoteip[2] = (tpcb->remote_ip.addr >> 16) & 0xff; /* IADDR2 */
g_lwipdev.remoteip[3] = (tpcb->remote_ip.addr >> 24) & 0xff; /* IADDR1 */
tcp_recved(tpcb, p->tot_len); /* 用于获取接收数据,通知LWIP可以获取更多数据 */
pbuf_free(p); /* 释放内存 */
ret_err = ERR_OK;
}
}
else /* 服务器关闭了 */
{
tcp_recved(tpcb, p->tot_len); /* 用于获取接收数据,通知LWIP可以获取更多数据 */
es->p = NULL;
pbuf_free(p); /* 释放内存 */
ret_err = ERR_OK;
}
return ret_err;
}
/**
* @brief lwIP tcp_err函数的回调函数
* @param arg :传入的参数
* @param err :错误码
* @retval 无
*/
void lwip_tcp_server_error(void *arg, err_t err)
{
LWIP_UNUSED_ARG(err);
printf("tcp error:%x\r\n", (uint32_t)arg);
if (arg != NULL)mem_free(arg); /* 释放内存 */
}
/**
* @brief lwIP数据发送,用户应用程序调用此函数来发送数据
* @param tpcb :TCP控制块
* @retval 返回值:0,成功;其他,失败
*/
err_t lwip_tcp_server_usersent(struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_server_struct *es;
es = tpcb->callback_arg;
if (es != NULL) /* 连接处于空闲可以发送数据 */
{
es->p = pbuf_alloc(PBUF_TRANSPORT, strlen((char *)g_lwip_demo_sendbuf), PBUF_POOL); /* 申请内存 */
pbuf_take(es->p, (char *)g_lwip_demo_sendbuf, strlen((char *)g_lwip_demo_sendbuf)); /* 将lwip_tcp_server_sentbuf[]中的数据拷贝到es->p_tx中 */
lwip_tcp_server_senddata(tpcb, es); /* 将lwip_tcp_server_sentbuf[]里面复制给pbuf的数据发送出去 */
g_lwip_send_flag &= ~(1 << 7); /* 清除数据发送标志 */
if (es->p != NULL)pbuf_free(es->p); /* 释放内存 */
ret_err = ERR_OK;
}
else
{
tcp_abort(tpcb); /* 终止连接,删除pcb控制块 */
ret_err = ERR_ABRT;
}
return ret_err;
}
测试结果:
