STM32高级 以太网通讯案例1:网络搭建(register代码)
需求描述
驱动W5500芯片,设置好IP,测试网络是否连通。
思考:
驱动W5500芯片是通过spi协议,所以和spi相关的有四个引脚,MOSI(主出从入)MISO(主入从出)SCK(时钟线)CS(片选线)。RST(复位引脚,对于32来说是输出)INT(中断引脚对于32来说是输入)。
W5500-RST:重置硬件,重置(Reset)低电平有效;该引脚需要保持低电平至少500us,才能重置W5500;(正常使用应该高电平,需要重置芯片的时候置为低电平不少500us)。连接的是PG7。
W5500-INT:中断输出(Interrupt output),低电平有效。低电平,W5500的中断生效;高电平,无中断。连接的是PG6。
W5500-CS片选引脚。连接的是PD3
W5500与STM32使用SPI协议进行通讯,连接的是STM32的SPI2外设。
第一步:导入文件(官方库、SPI、自己驱动的主文件)
W5500有官方库:导入以太网文件夹下的W5500、socket.c、socket.h、wizchip_conf.c、wizchip_conf.h文件, 放入Interface下的Ethernet文件下。
SPI:spi.c和spi.h(之前的spi文件) 文件放入Handware(驱动层)下。
自己驱动的主文件:新建eth.c和eth.h 放入Interface下的Ethernet文件下。
第二步:配置spi.h文件
宏定义的高低引脚要换成PD3
第三步:配置wizchip_conf.h文件
75行----改变当前使用芯片信号
153行---选择VDM,选择可变长度模式
61行---引入spi.h
第四步:配置wizchip_conf.c文件
里面许多函数的空实现
名词:
Cris:Critical region临界区-指的是共享的资源
enter:进入
exit:退出
select:选择
83行:片选使能 CS_LOW
91行:取消片选 CS_HIGH
最后一行自定义函数,注册spi操作的回调函数,记得.h引入原型
void user_register_function(void)
{
reg_wizchip_cris_cbfunc(wizchip_cris_enter,wizchip_cris_exit);
reg_wizchip_cs_cbfunc(wizchip_cs_select,wizchip_cs_deselect);
reg_wizchip_spi_cbfunc(wizchip_spi_readbyte,wizchip_spi_writebyte);
}
第五步:配置spi.c文件
按照上面思考的图片修改初始化函数中的各种引脚。
第六步:书写eth.h和eth.c文件
eth.h
#ifndef __ETH_H__
#define __ETH_H__
#include "w5500.h"
//初始化
void ETH_Init(void);
#endif /* __ETH_H__ */
eth.c
#include "eth.h"
#include "delay.h"
// 定义W5500的IP地址、MAC地址、子网掩码和网关地址
uint8_t ip[4] = {192,168,44,250};
uint8_t mac[6] = {78,11,22,33,44,55};
uint8_t submask[4] = {255,255,255,0};
uint8_t gateway[4] = {192,168,44,1};
// 复位W5500
static void ETH_Reset(void);
// 设置 MAC 地址
static void ETH_SetMac(void);
// 设置 IP 地址(包括网关和子网掩码)
static void ETH_SetIP(void);
// 初始化
void ETH_Init(void)
{
// 0. SPI 初始化
SPI_Init();
// 1. 注册自定义回调函数
user_register_function();
// 2. 复位W5500
ETH_Reset();
// 3. 设置 MAC 地址
ETH_SetMac();
// 4. 设置 IP 地址(包括网关和子网掩码)
ETH_SetIP();
}
// 复位W5500
static void ETH_Reset(void)
{
// 1. 配置RST引脚-PG7
// 1.1 开启时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPGEN;
// 1.2 设置工作模式:通用推挽输出,MODE - 11,CNF - 00
GPIOG->CRL |= GPIO_CRL_MODE7;
GPIOG->CRL &= ~GPIO_CRL_CNF7;
// 2. 拉低RST,保持500us以上
GPIOG->ODR &= ~GPIO_ODR_ODR7;
Delay_us(800);
GPIOG->ODR |= GPIO_ODR_ODR7;
printf("W5500 复位完成!\n");
}
// 设置 MAC 地址
static void ETH_SetMac(void)
{
printf("开始设置 MAC 地址:\n");
setSHAR(mac);
printf("MAC 地址设置完成: %X-%X-%X-%X-%X-%X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
// 设置 IP 地址(包括网关和子网掩码)
static void ETH_SetIP(void)
{
printf("开始设置 IP 地址:\n");
// 设置IP
setSIPR(ip);
// 设置子网掩码
setSUBR(submask);
// 设置网关地址
setGAR(gateway);
printf("IP 地址设置完成: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
}
spi.h
#ifndef __SPI_H__
#define __SPI_H__
#include "stm32f10x.h"
#define CS_HIGH (GPIOD->ODR |= GPIO_ODR_ODR3)
#define CS_LOW (GPIOD->ODR &= ~ GPIO_ODR_ODR3)
void SPI_Init(void);
void SPI_Start(void);
void SPI_Stop(void);
uint8_t SPI_SwapByte(uint8_t byte);
#endif /* __SPI_H__ */
spi.c
#include "spi.h"
void SPI_Init(void){
// 1. GPIOB
// 1.1 先放时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
// 1.2 PA5 时钟 复用推挽
GPIOB->CRH &= ~GPIO_CRH_CNF13;
GPIOB->CRH |= GPIO_CRH_CNF13_1;
GPIOB->CRH |= GPIO_CRH_MODE13;
// 1.3 PA6 输入信号 浮空输入
GPIOB->CRH &= ~GPIO_CRH_CNF14_1;
GPIOB->CRH |= GPIO_CRH_CNF14_0;
GPIOB->CRH &= ~GPIO_CRH_MODE14;
// 1.4 PA7 数据输出 复用推挽
GPIOB->CRH &= ~GPIO_CRH_CNF15_0;
GPIOB->CRH |= GPIO_CRH_CNF15_1;
GPIOB->CRH |= GPIO_CRH_MODE15;
// 2. GPIOC
// 2.1 放GPIOD的时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPDEN;
CS_HIGH;
// 2.2. PC13 片选使能信号 通用推挽
GPIOD->CRL &= ~GPIO_CRL_CNF3;
GPIOD->CRL |= GPIO_CRL_MODE3;
//配置硬件SPI
//0.1放时钟
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
//0.2 设置DFF位来定义8位或者16位数据格式 当前8位
SPI2->CR1 &= ~SPI_CR1_DFF;
//0.3 设置高位优先
SPI2->CR1 &= ~SPI_CR1_LSBFIRST;
//0.4 工作模式为主模式
SPI2->CR1 |= SPI_CR1_MSTR;
//0.5 波特率的配置 APB2 72M 如果是 000 就是2分频 36M
SPI2->CR1 &= ~SPI_CR1_BR;
//0.6 mode0 模式
SPI2->CR1 &= ~SPI_CR1_CPOL;
SPI2->CR1 &= ~SPI_CR1_CPHA;
//0.7 SSOE 配0 这样的话 会关闭SS引脚的输出 同时 会被迫进入
//多主模式(NSS 会变成一个输入引脚)
SPI2->CR2 &= ~SPI_CR2_SSOE;
//0.8 NSS 进入软件模式
// SSM 配1 那就是NSS信号 由SSI位来决定
SPI2->CR1 |= SPI_CR1_SSM;
// SSI 配1 再多主模式里 一直处于可通讯状态
SPI2->CR1 |= SPI_CR1_SSI;
// 使能位
SPI2->CR1 |= SPI_CR1_SPE;
}
void SPI_Start(void){
CS_LOW;
}
void SPI_Stop(void){
CS_HIGH;
}
uint8_t SPI_SwapByte(uint8_t byte){
while (!(SPI2->SR & SPI_SR_TXE))
{
}
SPI2->DR = byte;
while (!(SPI2->SR & SPI_SR_RXNE))
{
}
uint8_t receive_byte = SPI2->DR;
return receive_byte;
}
main.c
#include "usart1.h"
#include "eth.h"
int main(void)
{
// 1. 初始化
Usart1_Init();
printf("尚硅谷以太网实验:测试网络搭建\n");
ETH_Init();
printf("\n以太网初始化完成!\n");
while (1)
{
}
}