学长板子改keil5几个注意事项:
①晶振修改为25M
STM32外部晶振8M更改为25M:
https://blog.csdn.net/a185531353/article/details/78512550?locationNum=1&fps=1
②usart.h中仅保留printf的功能。(不定义该功能而引用printf会导致卡死)
③去除delay.c中的delay相关函数,改成自己的delay函数。(会导致卡死)可再研究下25M的配置。对于跑马灯程序,其定时是准的。。
④定时器配置具体数值还需要再考虑
网口:
学长的板子没有焊接晶振,是用PA8定时器1的 MCO1通道给输出25MHZ(是否为25M需要测试)
https://blog.csdn.net/weixi87/article/details/8309217
74LVC1G17GW:逻辑缓冲器施密特触发器,作用应该是整形
实验55网络通讯实验
http://openedv.com/forum.php?mod=viewthread&tid=43537&highlight=%CD%F8%C2%E7%CD%A8%D0%C5%CA%B5%D1%E9
修改晶振,delay,usart后,运行程序卡死:
My_RTC_Init(); //RTC初始化 会导致程序卡死,已注释
在LAN8720.c中加入MCO1初始化后,橙色灯亮起,程序不再卡死。
void MCO1(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_ClockSecuritySystemCmd(ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_MCO);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //UP
GPIO_Init(GPIOA, &GPIO_InitStructure);
//RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_5);
RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1); //输出25M
}
各网卡、各交换机等网络设备都不一样,一般来讲:绿灯分为亮或不亮(代表网络速度,黄灯分为闪烁或不闪烁(代表是否有数据收发)
绿灯:长亮 代表100M; 不亮 代表10M
黄灯:长亮 代表无数据收发; 闪烁 代表有数据收发
也有些千兆网卡的灯以颜色区分,不亮代表10M / 绿色代表100M / 黄色代表1000M
现在10M的网络基本看不到了,如果一个灯长亮,基本可以说明100M网络或更高,而另一个灯时而闪烁,那代表有数据收发,具体要看你的网络设备了。
甚至有些低等网卡如TP-Link,只有一个灯,亮代表连通,闪烁代表数据收发
https://blog.csdn.net/a827415225/article/details/51945222
正点原子的例程没有用到外部SRAM,因此可以不必修改malloc.c中的函数。实际调用中注意别用SRAMEX即可。
时钟系统:https://www.cnblogs.com/strongerHuang/p/5609969.html
这样看来硬件电路应该是有错的。这里我猜测由于LED2原理图是下拉,模式编程OUT模式。 然后程序上输入25MHz时钟,被等效成25MHz晶振,然后内部倍频,正好能正常工作。。
把PLL_N改为300,MCO1改为PLL时钟3分频(输出50MHZ),程序死在
说明lwip_comm_init()一直不等于0
用举涛学长的程序调通:
举涛学长的程序当我从电脑发送到板子时,单片机会停止发送。原子程序无此bug
LED板子做TCP-SERVER
电脑做TCP-CLIENT
程序修改如下:
我的计算机网络配置:
PING指令:
电脑上网络调试助手:
串口助手:
原本的例程程序是在轮询的时候单片机才能发数据,测试收发频率,电脑发的周期在200ms会出错,250ms可以,电脑收信息周期要在500ms,400ms则会丢信息。但是我需要在收到数据时立刻返回数据,因此需要自定义一个主动发送的函数。
原本轮询发送函数在err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb)中进行,但是这个函数的输入参数是两个复杂的结构体,不知道怎么给,参考了原子论坛的相关说明,定义了两个全局变量,并在tcp_server_accept中赋值,从而实现立即发送数据。盖完之后,在5ms时收发都OK(注意是收发均可)。
struct tcp_server_struct *es_ex; //用于立即发送数据,在tcp_server_accept中赋值
struct tcp_pcb *newpcb_ex; //用于立即发送数据,在tcp_server_accept中赋值
//lwIP tcp_accept()的回调函数
err_t 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,tcp_server_recv); //初始化tcp_recv()的回调函数
tcp_err(newpcb,tcp_server_error); //初始化tcp_err()回调函数
tcp_poll(newpcb,tcp_server_poll,1); //初始化tcp_poll回调函数
tcp_sent(newpcb,tcp_server_sent); //初始化发送回调函数
tcp_server_flag|=1<<5; //标记有客户端连上了
lwipdev.remoteip[0]=newpcb->remote_ip.addr&0xff; //IADDR4
lwipdev.remoteip[1]=(newpcb->remote_ip.addr>>8)&0xff; //IADDR3
lwipdev.remoteip[2]=(newpcb->remote_ip.addr>>16)&0xff; //IADDR2
lwipdev.remoteip[3]=(newpcb->remote_ip.addr>>24)&0xff; //IADDR1
ret_err=ERR_OK;
}else ret_err=ERR_MEM;
//主要是在这里赋值
es_ex = es;
newpcb_ex = newpcb;
return ret_err;
}
//自己参照tcp_server_poll写的发送数据函数,用于立即发数据,而不必等到轮询
void mytcp_server_senddata(char *sendbuf)
{
tcp_server_sendbuf = sendbuf;
es_ex->p=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)tcp_server_sendbuf),PBUF_POOL);//申请内存
pbuf_take(es_ex->p,(char*)tcp_server_sendbuf,strlen((char*)tcp_server_sendbuf));
tcp_server_senddata(newpcb_ex,es_ex); //轮询的时候发送要发送的数据
tcp_server_flag&=~(1<<7); //清除数据发送标志位
tcp_server_sendbuf = NULL; //发送区清空
if(es_ex->p!=NULL)pbuf_free(es_ex->p); //释放内存
}
调用举例:
mytcp_server_senddata("data saved\r\n");
mytcp_server_senddata("hhhh hhhhh\r\n");