如何移植使用W5500官方提供的最新Socket库_w5500官方库-程序员宅基地

技术标签: # w5500  

转载地址:https://blog.csdn.net/wiznet2012/article/details/41279113

(此论坛为一个WIZnet用户开设的,论坛积累了大量的W5500相关应用及例程,具有很大的参考价值。)

官方提供了W5500的最新驱动库,下载地址如下:
http://wizwiki.net/wiki/doku.php?id=products:w5500:driver
下面简单介绍下如何使用这套库
首先下载库源码,文件目录如下所示:

我们主要用到Ethernet文件夹下面的文件,将这些文件加入到自己的工程中,然后编译,若编译出现类似于如下错误
..\User\Ethernet\wizchip_conf.c(113): error:  #29: expected an expression
.id                  = _WIZCHIP_ID_,
..\User\Ethernet\wizchip_conf.c(114): error:  #29: expected an expression
.if_mode             = _WIZCHIP_IO_MODE_,
..\User\Ethernet\wizchip_conf.c(115): error:  #29: expected an expression
.CRIS._enter         = wizchip_cris_enter,
..\User\Ethernet\wizchip_conf.c(116): error:  #29: expected an expression
.CRIS._exit          = wizchip_cris_exit,
..\User\Ethernet\wizchip_conf.c(117): error:  #29: expected an expression
.CS._select          = wizchip_cs_select,
..\User\Ethernet\wizchip_conf.c(118): error:  #29: expected an expression
.CS._deselect        = wizchip_cs_deselect,
..\User\Ethernet\wizchip_conf.c(119): error:  #29: expected an expression
.IF.BUS._read_byte   = wizchip_bus_readbyte,
..\User\Ethernet\wizchip_conf.c(120): error:  #29: expected an expression
.IF.BUS._write_byte  = wizchip_bus_writebyte
..\User\Ethernet\wizchip_conf.c(123): warning:  #12-D: parsing restarts here after previous syntax error
};
..\User\Ethernet\wizchip_conf.c: 1 warning, 8 errors
则需要根据自己的编译器做下设置,keil MDK设置如下所示:

主要原因是Keil MDK默认设置不支持按照结构体名称初始化结构体的原因导致。

W5500和MCU是通过SPI接口通信的,库是利用如下结构体中的相关函数指针实现SPI通信和其他功能。

_WIZCHIP WIZCHIP = { .id = _WIZCHIP_ID_,

.if_mode = _WIZCHIP_IO_MODE_,

.CRIS._enter = wizchip_cris_enter,

.CRIS._exit = wizchip_cris_exit,

.CS._select = wizchip_cs_select,

.CS._deselect = wizchip_cs_deselect,

.IF.BUS._read_byte = wizchip_bus_readbyte,

.IF.BUS._write_byte = wizchip_bus_writebyte

// .IF.SPI._read_byte = wizchip_spi_readbyte,

// .IF.SPI._write_byte = wizchip_spi_writebyte

};

根据函数名字和库中的注释,我们这里也对要实现的函数做个简单的说明
wizchip_cris_enter :进入临界区的函数,可以不管
wizchip_cris_exit :退出临界区的函数,也可以不管
wizchip_cs_select :输出有效片选信号的函数,也就是控制CS输出低电平的函数,必须实现
wizchip_cs_deselect :控制CS输出高电平的函数,必须实现
wizchip_bus_readbyte :SPI总线读取一字节数据函数,必须实现
wizchip_bus_writebyte :SPI总线写一字节数据函数,必须实现

根据以上可知,只要实现了SPI的基本操作,移植基本完成,是不是很简单

下面我们就新建一个spi.c的文件来实现这几个函数,当然这些函数名字可以不和这个结构体里面的函数名字一样,到时候可以调用相关的函数注册下即可

/**
   ******************************************************************************
   * @file    spi.c
   * $Author: 飞鸿踏雪 $
   * $Revision: 17 $
   * $Date:: 2014-10-25 11:16:48 +0800 #$
   * @brief   SPI驱动函数实现.
   ******************************************************************************
   * @attention
   *
   *<h3><center> Copyright 2009-2012, EmbedNet</center>
   *<center><a href="http:\\[url]www.embed-net.com[/url]">[url]http://www.embed-net.com[/url]</a></center>
   *<center>All Rights Reserved</center></h3>
   *
   ******************************************************************************
   */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
   * @brief  使能SPI时钟
   * @retval None
   */
static  void  SPI_RCC_Configuration( void )
{
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1,ENABLE);
}
/**
   * @brief  配置指定SPI的引脚
   * @retval None
   */
static  void  SPI_GPIO_Configuration( void )
{
     GPIO_InitTypeDef GPIO_InitStruct;
     //PA4->CS,PA5->SCK,PA6->MISO,PA7->MOSI                          
     GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_5 | GPIO_Pin_6|GPIO_Pin_7;
     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
     GPIO_Init(GPIOA, &GPIO_InitStruct);
     //初始化片选输出引脚
     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
     GPIO_Init(GPIOA, &GPIO_InitStruct);
     GPIO_SetBits(GPIOA,GPIO_Pin_4);
}
/**
   * @brief  根据外部SPI设备配置SPI相关参数
   * @retval None
   */
void  SPI_Configuration( void )
{
     SPI_InitTypeDef SPI_InitStruct;
     SPI_RCC_Configuration();
     SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
     SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
     SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
     SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
     SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
     SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
     SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
     SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
     SPI_InitStruct.SPI_CRCPolynomial = 7;
     SPI_Init(SPI1,&SPI_InitStruct);
    
     SPI_GPIO_Configuration();
     SPI_SSOutputCmd(SPI1, ENABLE);
     SPI_Cmd(SPI1, ENABLE);
}
/**
   * @brief  写1字节数据到SPI总线
   * @param  TxData 写到总线的数据
   * @retval None
   */
void  SPI_WriteByte(uint8_t TxData)
{               
     while ((SPI1->SR&SPI_I2S_FLAG_TXE)==0);    //等待发送区空         
     SPI1->DR=TxData;                                          //发送一个byte
     while ((SPI1->SR&SPI_I2S_FLAG_RXNE)==0);  //等待接收完一个byte 
     SPI1->DR;       
}
/**
   * @brief  从SPI总线读取1字节数据
   * @retval 读到的数据
   */
uint8_t SPI_ReadByte( void )
{           
     while ((SPI1->SR&SPI_I2S_FLAG_TXE)==0);    //等待发送区空             
     SPI1->DR=0xFF;                                                //发送一个空数据产生输入数据的时钟
     while ((SPI1->SR&SPI_I2S_FLAG_RXNE)==0);  //等待接收完一个byte 
     return  SPI1->DR;                            
}
/**
   * @brief  进入临界区
   * @retval None
   */
void  SPI_CrisEnter( void )
{
     __set_PRIMASK(1);
}
/**
   * @brief  退出临界区
   * @retval None
   */
void  SPI_CrisExit( void )
{
     __set_PRIMASK(0);
}
/**
   * @brief  片选信号输出低电平
   * @retval None
   */
void  SPI_CS_Select( void )
{
     GPIO_ResetBits(GPIOA,GPIO_Pin_4);
}
/**
   * @brief  片选信号输出高电平
   * @retval None
   */
void  SPI_CS_Deselect( void )
{
     GPIO_SetBits(GPIOA,GPIO_Pin_4);
}
/*********************************END OF FILE**********************************/
到这里,移植基本上完成。
但是这些SPI的接口函数如何跟这套库衔接呢?不用怕,库提供有这样的函数来注册,只要在主函数中调用下就可以了,具体程序如下
  // First of all, Should register SPI callback functions implemented by user for accessing WIZCHIP
     /* Critical section callback */
     reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);    //注册临界区函数
     /* Chip selection call back */
#if   _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_
     reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect); //注册SPI片选信号函数
#elif _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_FDM_
     reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);   // CS must be tried with LOW.
#else
    #if (_WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_SIP_) != _WIZCHIP_IO_MODE_SIP_
       #error "Unknown _WIZCHIP_IO_MODE_"
    #else
       reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
    #endif
#endif
     /* SPI Read & Write callback function */
     reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);     //注册读写函数
到这里,移植工程基本完成,下面我们就将官方提供的一个loopback的测试程序移植到我们自己的工程中来,基本上也没做什么修改,下面是测试工程用到的几个测试函数
/**
   * @brief  Intialize the network information to be used in WIZCHIP
   * @retval None
   */
void  network_init( void )
{
    uint8_t tmpstr[6];
     ctlnetwork(CN_SET_NETINFO, ( void *)&gWIZNETINFO);
     ctlnetwork(CN_GET_NETINFO, ( void *)&gWIZNETINFO);
     // Display Network Information
     ctlwizchip(CW_GET_ID,( void *)tmpstr);
     printf ( "\r\n=== %s NET CONF ===\r\n" ,( char *)tmpstr);
     printf ( "MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n" ,gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
           gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);
     printf ( "SIP: %d.%d.%d.%d\r\n" , gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
     printf ( "GAR: %d.%d.%d.%d\r\n" , gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
     printf ( "SUB: %d.%d.%d.%d\r\n" , gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
     printf ( "DNS: %d.%d.%d.%d\r\n" , gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
     printf ( "======================\r\n" );
}
/**
   * @brief  Loopback Test Example Code using ioLibrary_BSD 
   * @retval None
   */
int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port)
{
    int32_t ret;
    uint16_t size = 0, sentsize=0;
    switch (getSn_SR(sn))
    {
       case  SOCK_ESTABLISHED :
          if (getSn_IR(sn) & Sn_IR_CON)
          {
             printf ( "%d:Connected\r\n" ,sn);
             setSn_IR(sn,Sn_IR_CON);
          }
          if ((size = getSn_RX_RSR(sn)) > 0)
          {
             if (size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
             ret = recv(sn,buf,size);
             if (ret <= 0)  return  ret;
             sentsize = 0;
             while (size != sentsize)
             {
                ret = send(sn,buf+sentsize,size-sentsize);
                if (ret < 0)
                {
                   close(sn);
                   return  ret;
                }
                sentsize += ret;  // Don't care SOCKERR_BUSY, because it is zero.
             }
          }
          break ;
       case  SOCK_CLOSE_WAIT :
          printf ( "%d:CloseWait\r\n" ,sn);
          if ((ret=disconnect(sn)) != SOCK_OK)  return  ret;
          printf ( "%d:Closed\r\n" ,sn);
          break ;
       case  SOCK_INIT :
           printf ( "%d:Listen, port [%d]\r\n" ,sn, port);
          if ( (ret = listen(sn)) != SOCK_OK)  return  ret;
          break ;
       case  SOCK_CLOSED:
          printf ( "%d:LBTStart\r\n" ,sn);
          if ((ret=socket(sn,Sn_MR_TCP,port,0x00)) != sn)
             return  ret;
          printf ( "%d:Opened\r\n" ,sn);
          break ;
       default :
          break ;
    }
    return  1;
}
/**
   * @brief  Loopback Test Example Code using ioLibrary_BSD 
   * @retval None
   */
int32_t loopback_udps(uint8_t sn, uint8_t* buf, uint16_t port)
{
    int32_t  ret;
    uint16_t size, sentsize;
    uint8_t  destip[4];
    uint16_t destport;
    //uint8_t  packinfo = 0;
    switch (getSn_SR(sn))
    {
       case  SOCK_UDP :
          if ((size = getSn_RX_RSR(sn)) > 0)
          {
             if (size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
             ret = recvfrom(sn,buf,size,destip,(uint16_t*)&destport);
             if (ret <= 0)
             {
                printf ( "%d: recvfrom error. %ld\r\n" ,sn,ret);
                return  ret;
             }
             size = (uint16_t) ret;
             sentsize = 0;
             while (sentsize != size)
             {
                ret = sendto(sn,buf+sentsize,size-sentsize,destip,destport);
                if (ret < 0)
                {
                   printf ( "%d: sendto error. %ld\r\n" ,sn,ret);
                   return  ret;
                }
                sentsize += ret;  // Don't care SOCKERR_BUSY, because it is zero.
             }
          }
          break ;
       case  SOCK_CLOSED:
          printf ( "%d:LBUStart\r\n" ,sn);
          if ((ret=socket(sn,Sn_MR_UDP,port,0x00)) != sn)
             return  ret;
          printf ( "%d:Opened, port [%d]\r\n" ,sn, port);
          break ;
       default  :
          break ;
    }
    return  1;
}
/**
   * @brief  Loopback Test Example Code using ioLibrary_BSD 
   * @retval None
   */
void  platform_init( void )
{
     SystemInit(); //系统时钟初始化
     USART_Configuration(); //串口1初始化
     printf ( "\x0c" ); printf ( "\x0c" ); //超级终端清屏
     printf ( "\033[1;40;32m" ); //设置超级终端背景为黑色,字符为绿色
     printf ( "\r\n*******************************************************************************" );
     printf ( "\r\n************************ Copyright 2009-2014, EmbedNet ************************" );
     printf ( "\r\n*************************** [url]http://www.embed-net.com[/url] **************************" );
     printf ( "\r\n***************************** All Rights Reserved *****************************" );
     printf ( "\r\n*******************************************************************************" );
     printf ( "\r\n" );
     //Config SPI
     SPI_Configuration();
     //延时初始化
     delay_init();
}
我们自己在工程中加了串口打印程序,程序运行后串口输出信息如下:
我们ping下程序里面的IP试试

能ping通,看来没什么大问题了

程序源码下载:请参考文章上方原文链接。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/kunkliu/article/details/80582597

智能推荐

【史上最易懂】马尔科夫链-蒙特卡洛方法:基于马尔科夫链的采样方法,从概率分布中随机抽取样本,从而得到分布的近似_马尔科夫链期望怎么求-程序员宅基地

文章浏览阅读1.3k次,点赞40次,收藏19次。虽然你不能直接计算每个房间的人数,但通过马尔科夫链的蒙特卡洛方法,你可以从任意状态(房间)开始采样,并最终收敛到目标分布(人数分布)。然后,根据一个规则(假设转移概率是基于房间的人数,人数较多的房间具有较高的转移概率),你随机选择一个相邻的房间作为下一个状态。比如在巨大城堡,里面有很多房间,找到每个房间里的人数分布情况(每个房间被访问的次数),但是你不能一次进入所有的房间并计数。但是,当你重复这个过程很多次时,你会发现你更有可能停留在人数更多的房间,而在人数较少的房间停留的次数较少。_马尔科夫链期望怎么求

linux以root登陆命令,su命令和sudo命令,以及限制root用户登录-程序员宅基地

文章浏览阅读3.9k次。一、su命令su命令用于切换当前用户身份到其他用户身份,变更时须输入所要变更的用户帐号与密码。命令su的格式为:su [-] username1、后面可以跟 ‘-‘ 也可以不跟,普通用户su不加username时就是切换到root用户,当然root用户同样可以su到普通用户。 ‘-‘ 这个字符的作用是,加上后会初始化当前用户的各种环境变量。下面看下加‘-’和不加‘-’的区别:root用户切换到普通..._限制su root登陆

精通VC与Matlab联合编程(六)_精通vc和matlab联合编程 六-程序员宅基地

文章浏览阅读1.2k次。精通VC与Matlab联合编程(六)作者:邓科下载源代码浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程浅析VC与MATLAB联合编程  Matlab C/C++函数库是Matlab扩展功能重要的组成部分,包含了大量的用C/C++语言重新编写的Matlab函数,主要包括初等数学函数、线形代数函数、矩阵操作函数、数值计算函数_精通vc和matlab联合编程 六

Asp.Net MVC2中扩展ModelMetadata的DescriptionAttribute。-程序员宅基地

文章浏览阅读128次。在MVC2中默认并没有实现DescriptionAttribute(虽然可以找到这个属性,通过阅读MVC源码,发现并没有实现方法),这很不方便,特别是我们使用EditorForModel的时候,我们需要对字段进行简要的介绍,下面来扩展这个属性。新建类 DescriptionMetadataProvider然后重写DataAnnotationsModelMetadataPro..._asp.net mvc 模型description

领域模型架构 eShopOnWeb项目分析 上-程序员宅基地

文章浏览阅读1.3k次。一.概述  本篇继续探讨web应用架构,讲基于DDD风格下最初的领域模型架构,不同于DDD风格下CQRS架构,二者架构主要区别是领域层的变化。 架构的演变是从领域模型到C..._eshoponweb

Springboot中使用kafka_springboot kafka-程序员宅基地

文章浏览阅读2.6w次,点赞23次,收藏85次。首先说明,本人之前没用过zookeeper、kafka等,尚硅谷十几个小时的教程实在没有耐心看,现在我也不知道分区、副本之类的概念。用kafka只是听说他比RabbitMQ快,我也是昨天晚上刚使用,下文中若有讲错的地方或者我的理解与它的本质有偏差的地方请包涵。此文背景的环境是windows,linux流程也差不多。 官网下载kafka,选择Binary downloads Apache Kafka 解压在D盘下或者什么地方,注意不要放在桌面等绝对路径太长的地方 打开conf_springboot kafka

随便推点

VS2008+水晶报表 发布后可能无法打印的解决办法_水晶报表 不能打印-程序员宅基地

文章浏览阅读1k次。编好水晶报表代码,用的是ActiveX模式,在本机运行,第一次运行提示安装ActiveX控件,安装后,一切正常,能正常打印,但发布到网站那边运行,可能是一闪而过,连提示安装ActiveX控件也没有,甚至相关的功能图标都不能正常显示,再点"打印图标"也是没反应解决方法是: 1.先下载"PrintControl.cab" http://support.businessobjects.c_水晶报表 不能打印

一. UC/OS-Ⅱ简介_ucos-程序员宅基地

文章浏览阅读1.3k次。绝大部分UC/OS-II的源码是用移植性很强的ANSI C写的。也就是说某产品可以只使用很少几个UC/OS-II调用,而另一个产品则使用了几乎所有UC/OS-II的功能,这样可以减少产品中的UC/OS-II所需的存储器空间(RAM和ROM)。UC/OS-II是为嵌入式应用而设计的,这就意味着,只要用户有固化手段(C编译、连接、下载和固化), UC/OS-II可以嵌入到用户的产品中成为产品的一部分。1998年uC/OS-II,目前的版本uC/OS -II V2.61,2.72。1.UC/OS-Ⅱ简介。_ucos

python自动化运维要学什么,python自动化运维项目_运维学python该学些什么-程序员宅基地

文章浏览阅读614次,点赞22次,收藏11次。大家好,本文将围绕python自动化运维需要掌握的技能展开说明,python自动化运维从入门到精通是一个很多人都想弄明白的事情,想搞清楚python自动化运维快速入门 pdf需要先了解以下几个事情。这篇文章主要介绍了一个有趣的事情,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。_运维学python该学些什么

解决IISASP调用XmlHTTP出现msxml3.dll (0x80070005) 拒绝访问的错误-程序员宅基地

文章浏览阅读524次。2019独角兽企业重金招聘Python工程师标准>>> ..._hotfix for msxml 4.0 service pack 2 - kb832414

python和易语言的脚本哪门更实用?_易语言还是python适合辅助-程序员宅基地

文章浏览阅读546次。python和易语言的脚本哪门更实用?_易语言还是python适合辅助

redis watch使用场景_详解redis中的锁以及使用场景-程序员宅基地

文章浏览阅读134次。详解redis中的锁以及使用场景,指令,事务,分布式,命令,时间详解redis中的锁以及使用场景易采站长站,站长之家为您整理了详解redis中的锁以及使用场景的相关内容。分布式锁什么是分布式锁?分布式锁是控制分布式系统之间同步访问共享资源的一种方式。为什么要使用分布式锁?​ 为了保证共享资源的数据一致性。什么场景下使用分布式锁?​ 数据重要且要保证一致性如何实现分布式锁?主要介绍使用redis来实..._redis setnx watch