HAL库配置w5500使用STM32CubeMX
工作中要用,第一次用,学习记录,省得自己忘记,持续更新。
工作中要用,第一次用,学习记录,省得自己忘记,持续更新
一、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"); }
更多推荐







所有评论(0)