stm32f103zet6+enc28j60上移植lwip,建立TCP客户端通信

      是时候写一波了,调了一个星期的裸机以太网通信。最终成功在stm32f103zet6+enc28j60上移植lwip,成功建立裸机端的TCP客户端,和PC端的TCP服务器进行通信。

      开头说点虚的。      

      1、人生可能本身就是平淡无趣的,习惯于此,无大喜也无大悲。但追求的那点意义莫不过不甘心如此的碌碌无为,强行经历更大的痛苦、纠结、甚至无望,浪费时间和精力,在最终实现目标的时刻,豁然开怀,万分感谢这一切的浪费和投入都如此值得,安心而去。      

      2、起点和终点是很重要的。就像是盗梦空间里的小李子,不管深入多少层的梦境,记得紧握那个让你清醒来路和去向的陀螺。也许你一开始的出发还目标明确,但走得越来越远之后,便不知自己所云。就像是你写了好几层 的函数调用,突然发现自己不知道应该返回什么。      

      3、成熟的标志真的是从一个小本开始吗?你知道很多东西不可能一蹴而就,开始谨慎计划和执行,尊重现实的取舍。      

      虚的结束。      

      说一下关键步骤吧:      

      第一步:配置好单片机stm32和以太网控制器enc28j60的通信。enc28j60自带SPI接口,应该明确你的stm32的板子哪些引脚和enc28j60的引脚相连,所使用SPIx中的x是多少。比如我的事SPI2,硬件连接如下:

* PD2——ENC28J60-INT (未使用)

* PB14-SPI2-MISO——ENC28J60-SO

* PB15-SPI2-MOSI——ENC28J60-SI 

* PB13-SPI2-SCK——ENC28J60-SCK 

* PG8-SPI1-NSS——ENC28J60-CS 

* PG6——ENC2860-RST(未使用) 

void SPI_Enc28j60_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef  SPI_InitStructure;	
	
	                 
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		  
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	   
        GPIO_Init(GPIOG, &GPIO_InitStructure);						  
	GPIO_SetBits(GPIOG, GPIO_Pin_8);										 


 

	


        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//È«Ë«¹¤Ä£Ê½
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//×÷ΪÖ÷»ú
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//Êý¾Ý³¤¶ÈΪ8
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//ʱÖÓÏàλÉèÖÃ
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//Èí¼þÉèÖÃNSS¹¦ÄÜ
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI2, &SPI_InitStructure);
	
	
	SPI_Cmd(SPI2, ENABLE); 
	
}


unsigned char	SPI2_ReadWrite(unsigned char writedat)
{
	/* Loop while DR register in not emplty */
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET);
	
	/* Send byte through the SPI2 peripheral */
	SPI_I2S_SendData(SPI2, writedat);
	
	/* Wait to receive a byte */
	while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
	
	/* Return the byte read from the SPI bus */
	return SPI_I2S_ReceiveData(SPI2);
}

      第二步:初始化ENC28J60,书写发送和接收函数 

      注意这里:

ENC28J60_CSL();
 这里需要更改,这里我很长时间才发现,有点坑。  
#define  ENC28J60_CSL()    (GPIOG->ODR &= ~(1<<8))
#define  ENC28J60_CSH()    (GPIOG->ODR |= 1<<8)

      第三步:初始IP协议栈和建立TCP客户端

void tcp_client_init(void)
{

  struct tcp_pcb *pcb;
  struct ip_addr ipaddr;
  IP4_ADDR(&ipaddr,169,254,42,250); 
	
  pcb = tcp_new();                           
  
  tcp_bind(pcb,IP_ADDR_ANY,23);             
 
  
  if(pcb!=NULL)

 {	                       
        
     tcp_connect(pcb,&ipaddr,18060,tcp_client_connect);

} 
err_t tcp_client_connect(void *arg,struct tcp_pcb *tpcb,err_t err)
 {
                 tcp_recv(tpcb, tcp_client_recv);       
                 tcp_poll(tpcb, tcp_client_poll, 1); //250ms      
                 return ERR_OK;
 }
static err_t tcp_client_recv(void *arg, struct tcp_pcb *pcb,struct pbuf *p,err_t err)
{

	if(err==ERR_OK&&p!=NULL)   
  {
	  printf("%s",p->payload);
	  pbuf_free(p);
  }
	
	tcp_recved(pcb, p->tot_len);
	return ERR_OK;
	
	
}
static err_t tcp_client_poll(void *arg, struct tcp_pcb *tpcb)
{

	if(usart2_received ==1) //发送准备好标志
  {
	  tcp_write(tpcb,sendbuffer,sendbuffer_len,0);
		tcp_output(tpcb);
	  usart2_received =0;
	}
	return ERR_OK;
}	

    第四步:主函数编写,设置轮询函数

    while (1)
	{	
 
		LwIP_Periodic_Handle(LocalTime);//轮询函数		
         }
void LwIP_Periodic_Handle(__IO uint32_t localtime)
{
	//err_t  err;
	
	if(localtime - INPUT_Timer >= INPUT_TMR_INTERVAL)
		{
		    /* Read a received packet from the Ethernet buffers and send it to the lwIP for handling */
			ethernetif_input(&enc28j60); 			//检查是否收到数据
			//	err = ethernetif_input(&enc28j60); //

			//		if (err !=ERR_OK  ) 
			//		{
			//			
			//
			//			}
		}
          Delay_s(0xfffff); //这里很关键,必要的延时!!!!!没有它,接收会出现问题
	  /* TCP periodic process every 250 ms */
	  if (localtime - TCPTimer >= TCP_TMR_INTERVAL)
	  {
	    TCPTimer =  localtime;
	    tcp_tmr();		 //
	  }
	  /* ARP periodic process every 5s */
	  if (localtime - ARPTimer >= ARP_TMR_INTERVAL)
	  {
	    ARPTimer =  localtime;
	    etharp_tmr();	  //
	  }
#if LWIP_DHCP
	  /* Fine DHCP periodic process every 500ms */
	  if (localtime - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
	  {
	    DHCPfineTimer =  localtime;
	    dhcp_fine_tmr();
	  }
	  /* DHCP Coarse periodic process every 60s */
	  if (localtime - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)
	  {
	    DHCPcoarseTimer =  localtime;
	    dhcp_coarse_tmr();
	  }
#endif

}




你可能感兴趣的:(stm32f103zet6+enc28j60上移植lwip,建立TCP客户端通信)