工作中要用,第一次用,学习记录,省得自己忘记,持续更新

一、w5500相关配置

1.1工作模式

首先要配置spi,最重要的就是确定CPOL和CPHA两个参数,还有就是速率,配置的速率不要超过芯片支持的最大速率,买的现成的模块,数据手册里明确写了可以在模式0和模式3下工作

 模式0:起始低电平,上升沿采样

模式3:起始高电平,下降沿采样

1.2 速率

同样是在数据手册里,那么我们就把速率配置为80MHz 

二、STM32CubeMX配置

2.1.1选型 

有了上面的信息,就可以配置stm32了,我用的f103rct6,芯片根据自己的需要选就行

老生常谈的步骤

2.1.2system core

配置SYS-->RCC-->时钟树

2.1.3 USART

配置一路串口用来打印调试 

2.1.4 SPI

我用的不是默认引脚,自己改了引脚,不需要特殊处理就用默认就好,片选引脚自己选,一点要选有上拉电阻的,不然无法通信,模式是GPIO_OUTPUT,我自己改了标签名

2.1.5生成工程

工程名,位置,自己指定,IDE要选MDK-ARM

勾选分文件编程

生成工程即可

三、代码

3.1验证通信

在移植之前,首先确定自己的板子是否能和w5500模块通信

3.1.1 spi片选

我用的是正点原子的mini板,用了教程里的引脚,发现通信不上,因为这个引脚没有上拉电阻

在原理图里找了有上拉电阻的引脚,作为片选

3.1.2 VERSIONR寄存器 

下面验证通信,w5500参考手册里VERSIONR这个寄存器,地址为0x0039,只读寄存器,读它会收到寄存器返回的值: 0x04

3.1.3 测试代码

下面写代码 ,首先是准备工作,构建板级支持包,就是自己的源文件和头文件,我喜欢在工程文件的Drivers下构建,新建一个bsp文件夹,接下来自己写的代码都在这个文件夹里

将文件添加到keil工程里,按照顺序操作

添加头文件

选择文件夹就行,再次点击魔术棒选项,就能看到添加成功了

点第二个红框,把移植的文件加进来,也是一样可以选

选择要添加的文件

添加完以后点击ok保存

可以看到左侧工程栏里有刚才添加的文件

 

代码部分,看参考文档,用VDM模式,也就是数据长度可变模式,前面说过VERSIONR寄存器是只读寄存器,所以采用读访问,发送也就是按顺序发送003900即可

在main.c里添加以下代码

 /* USER CODE BEGIN 2 */
	printf("12345\n");//是我用来测试的,可以不写
	uint8_t ret=0;
	CS_L();
	spi1_read_write_byte(0x00);
	spi1_read_write_byte(0x39);
	ret=spi1_read_write_byte(0x00);
	ret=spi1_read_write_byte(0xff);
	printf("%#x\n",ret);
	CS_H();
  /* USER CODE END 2 */

 bsp_w5500.c

#include "bsp_w5500.h"

uint8_t spi1_read_write_byte(uint8_t txdata){
	uint8_t rec_data;
	HAL_SPI_TransmitReceive(&hspi1,&txdata,&rec_data,1,1000);
	return rec_data;
}

//CS拉低
void  CS_L(void)
{
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
}

//CS拉高
void  CS_H(void)
{
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
}

 bsp_w5500.h

#ifndef _BSP_W5500_H_
#define _BSP_W5500_H_

#include "spi.h"

uint8_t spi1_read_write_byte(uint8_t txdata);
void  CS_L(void);
void  CS_H(void);

#endif



打开串口调试助手,可以看到收到0x4,符合预期,板子和模块的通信没问题

如果没反应的话,可以debug看下,如果程序卡在下面这里,就是没有勾选Mcrolib库

按照下图操作即可

3.2移植

下载地址:github.com

下载完之后根据对应的芯片找驱动

需要复制六个文件将这个六个文件全部移植到自己的工程里,所谓移植,其实就是复制粘贴,我习惯将所有的自己写的代码放到一块,bsp

然后需要在把复制的文件加入到工程,打开工程,按照下面两个步骤添加文件

然后编译,没错就继续,我是出现了头文件未包含的错误。双击error到错误位置,这是因为移植以后文件目录变了,改下就好

把头文件改了,改成 #include "w5500.h"

再次编译,没有错误了,到此移植完成

3.3写代码

3.3.1 注册函数

为了兼容性,库无法假设SPI和临界区的具体实现,需要用户主动把相关驱动函数注册给库使用。wizchip_conf.c文件里给了很多用于注册函数,这些都是默认注册函数,不适用的话默认为空

这些都是需要自己写的函数,依次介绍下


//这些函数要自己写,给下面的回调函数使用
//进入临界区
void 	  wizchip_cris_enter(void)           {}    
//退出临界区  
void 	  wizchip_cris_exit(void)          {}
//片选
void 	wizchip_cs_select(void)            {}
//取消片选
void 	wizchip_cs_deselect(void)          {}
//mod bus模式读
iodata_t wizchip_bus_readdata(uint32_t AddrSel) { return * ((volatile iodata_t *)((ptrdiff_t) AddrSel)); }  
//mod bus模式写 
void 	wizchip_bus_writedata(uint32_t AddrSel, iodata_t wb)  { *((volatile iodata_t*)((ptrdiff_t)AddrSel)) = wb; }
//spi模式读一个字节
uint8_t wizchip_spi_readbyte(void)        {return 0;}
//spi模式写一个字节
void 	wizchip_spi_writebyte(uint8_t wb) {}
//spi模式写多个字节
void 	wizchip_spi_readburst(uint8_t* pBuf, uint16_t len) 	{}
//spi模式写多个字节
void 	wizchip_spi_writeburst(uint8_t* pBuf, uint16_t len) {}


//注册 W5500 临界区 (Critical Section) 保护的回调函数
void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void))

// 注册 W5500 的片选 (Chip Select, CS) 控制回调函数
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void))

//W5500在总线模式 (BUS Mode) 下的 读写回调函数注册
void reg_wizchip_bus_cbfunc(iodata_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb))

//一下两个函数区别仅在于传输字节不同
// W5500在SPI模式下的 读写回调函数注册,适用于逐字节 (Byte-by-Byte) SPI 读写
void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb))

// W5500 在 SPI 模式 下的 批量(Burst)数据传输回调函数注册,适用于批量 (Burst) SPI 传输
void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len))

3.3.2 初始化

配置缓冲区,两个函数均可以实现此功能

 int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg);

参数,直接跳转过去,可以看到.h文件里控制命令的所有类型,注释写的很清楚了,我们用来初始化缓冲区,用这个CW_INIT_WIZCHIP类型

uint8_t txrx_mem[2][8] = {
    {2, 2, 2, 2, 2, 2, 2, 2},  // TX Buffer 配置(每个 Socket 2KB)
    {2, 2, 2, 2, 2, 2, 2, 2}   // RX Buffer 配置(每个 Socket 2KB)
};

if(ctlwizchip(CW_INIT_WIZCHIP, txrx_mem) == 0) {
    printf("W5500 缓冲区配置成功\n");
} else {
    printf("W5500 缓冲区配置失败\n");
}

当选择类型为CW_GET_ID时,可以读芯片ID,也可以用来检测通信,会读到W5500

char id[6];
ctlwizchip(CW_GET_ID,(void *)id);

int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize)

这个函数可以实现和上面的函数一样的功能,但是这个函数的用途更专一,专门用于初始化 W5500 的 发送(TX)接收(RX) 缓冲区配置。

// 定义缓冲区大小(每个 Socket 分配 2KB)
uint8_t tx_size[8] = {2, 2, 2, 2, 2, 2, 2, 2};
uint8_t rx_size[8] = {2, 2, 2, 2, 2, 2, 2, 2};

if(wizchip_init(tx_size, rx_size) == 0) {
    printf("W5500 缓冲区配置成功\n");
} else {
    printf("W5500 缓冲区配置失败\n");
}

3.3.3 网络配置

同样也是两个函数可以实现

int8_t ctlnetwork(ctlnetwork_type cntype, void* arg);

函数的作用是对W5500网络芯片的网络配置进行设置或读取操作。通过不同的参数cntype,实现对芯片网络信息(如IP、MAC、子网掩码、网关等)的操作。设置网络用CN_SET_NETINFO,获取信息用CN_GET_NETINFO

1.设置网络:

    ctlnetwork(CN_SET_NETINFO, (void *)&conf);

  • 将用户定义的网络配置信息(如MAC地址、IP地址、子网掩码、网关、DNS服务器、DHCP模式)写入到W5500芯片内部。
  • 函数的第二个参数 (void *)&conf 是一个指针,指向结构体 wiz_NetInfo,该结构体包含了网络参数,结构体如下:
typedef struct wiz_NetInfo_t {
   uint8_t mac[6];    // MAC地址
   uint8_t ip[4];     // IP地址
   uint8_t sn[4];     // 子网掩码
   uint8_t gw[4];     // 网关地址
   uint8_t dns[4];    // DNS服务器地址
   dhcp_mode dhcp;    // DHCP模式(静态IP或动态DHCP)
} wiz_NetInfo;

        也就是说在配置网络之前,需要我们填写以上结构体的信息,需要根据自己的网络情况配置

    wiz_NetInfo conf = {
        .mac = {0x00,0x0e,0xc6,0x2e,0x0b,0xe0},   //MAC地址
        .ip = {192,254,252,11},                    //IP地址
        .sn = {255,255,255,0},                    //子网掩码
        .gw = {192,254,252,1},                      //网关
        .dns = {8,8,8,8},                         // DNS服务器地址
        .dhcp = NETINFO_STATIC                    // 使用静态IP
    };
    
    // 将以上网络配置信息设置到W5500芯片中
    ctlnetwork(CN_SET_NETINFO, (void *)&conf);

    2.获取信息:

    ctlnetwork(CN_GET_NETINFO, (void *)&conf);

    用来检验ctlnetwork(CN_SET_NETINFO, (void *)&conf);配置是否生效

    wiz_NetInfo conf;  // 定义一个网络配置结构体
    
    // 获取W5500当前的网络信息
    if(ctlnetwork(CN_GET_NETINFO, (void *)&conf) == 0) {
        printf("当前IP地址: %d.%d.%d.%d\n", conf.ip[0], conf.ip[1], conf.ip[2], conf.ip[3]);
        printf("当前MAC地址: %02X:%02X:%02X:%02X:%02X:%02X\n", 
                conf.mac[0], conf.mac[1], conf.mac[2], 
                conf.mac[3], conf.mac[4], conf.mac[5]);
        // 继续打印其他网络参数...
    }
    else {
        printf("获取网络信息失败!\n");
    }

    Logo

    有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

    更多推荐