STM32驱动W5100实现udp通信

STM32驱动W5100实现udp通信


本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.


环境:

主机:WIN7

开发环境:MDK4.72

MCU:STM32F103ZE


源代码:

驱动层代码:

drv_w5100.h

/*********************************************************************
*						  		w5100驱动层头文件
*							  (c)copyright 2013,jdh
*						  		All Right Reserved
*文件名:drv_w5100.h
*程序员:jdh
*修改日期:2013/10/22
*		  2013/10/23
*		  2013/10/24
**********************************************************************/
/*********************************************************************
硬件连接说明
电路标号			单片机引脚		特殊功能
W5100_MISO			PB4				SPI3_MISO
W5100_MOSI			PB5				SPI3_MOSI
W5100_CS			PA15			SPI3_NSS
W5100_SCLK			PB3				SPI3_SCK
/RESET				PD3	
/INT				PD6
**********************************************************************/

#ifndef _DRV_W5100_H_
#define _DRV_W5100_H_

/*********************************************************************
*							头文件
**********************************************************************/

#include "stm32f10x.h"
#include "stm32f10x_spi.h"

/*********************************************************************
*							宏定义
**********************************************************************/

/*********************************************************************
*							读写操作
**********************************************************************/

//写操作
#define WRITE_COMMAND   		0xf0   
//读操作
#define READ_COMMAND    		0x0f    

/*********************************************************************
*							基地址
**********************************************************************/

#define	COMMON_BASE	0x0000			

/*********************************************************************
*							寄存器
**********************************************************************/

//-----------------------------------------------------------------------------
//                               Common register
//-----------------------------------------------------------------------------
//Mode register, R/W, Default=0x00
#define SOCKET0       0
#define SOCKET1       1
#define SOCKET2       2
#define SOCKET3       3

#define TCP_SERVER    0
#define TCP_CLIENT    1
#define UDP           2

#define W5100_MODE	COMMON_BASE
	#define MODE_RST	0x80		//Software reset
	#define MODE_PB		0x10		//Ping block mode
	#define MODE_PPPOE	0x08		//PPOE mode
	#define MODE_AI		0x02		//Address auto increment in indirect bus I/F
	#define MODE_IND	0x01		//Indirect bus I/F mode

//Gateway address register, R/W, default=0x00
#define	W5100_GAR	COMMON_BASE+0x01

//Subnet mask address, R/W, default=0x00
#define	W5100_SUBR	COMMON_BASE+0x05

//Source hardware address, R/W, default=0x00
#define	W5100_SHAR	COMMON_BASE+0x09

//Source IP address, R/W, default=0x00
#define	W5100_SIPR	COMMON_BASE+0x0f

//Interrupt and interrupt mask register
#define	W5100_IR	COMMON_BASE+0x15	//RO, Default=0x00
	#define IR_CONFLICT	0x80		//IP conflict
	#define IR_UNREACH	0x40		//Destination unreachable
	#define IR_PPPOE	0x20		//PPOE close
	#define IR_S3_INT	0x08		//Occurrence of socket 3 socket interrupt
	#define IR_S2_INT	0x04		//Occurrence of socket 2 socket interrupt
	#define IR_S1_INT	0x02		//Occurrence of socket 1 socket interrupt
	#define IR_S0_INT	0x01		//Occurrence of socket 0 socket interrupt

#define	W5100_IMR	COMMON_BASE+0x16	//R/W, Default=0x00
	#define IMR_CONFLICT	0x80		//IP conflict
	#define IMR_UNREACH	0x40		//Destination unreachable
	#define IMR_PPPOE	0x20		//PPOE close
	#define IMR_S3_INT	0x08		//Occurrence of socket 3 socket interrupt
	#define IMR_S2_INT	0x04		//Occurrence of socket 2 socket interrupt
	#define IMR_S1_INT	0x02		//Occurrence of socket 1 socket interrupt
	#define IMR_S0_INT	0x01		//Occurrence of socket 0 socket interrupt

//Retry time value. Value 1 means 100us, R/W, default=0x07D0
#define W5100_RTR	COMMON_BASE+0x17

//Retry count, R/W, Default=0x08
#define W5100_RCR	COMMON_BASE+0X19

//RX memory size register, R/W, default=0x55
//--------------------------------------------------------    S1      S0      Memory size
//  Socket3    |  Socket2    |  Socket1    |  Socket0    |    0       0           1KB
//-------------|-------------|-------------|-------------|    0       1           2KB
//S1       S0  |S1       S0  |S1       S0  |S1       S0  |    1       0           4KB
//--------------------------------------------------------    1       1           8KB
#define W5100_RMSR	COMMON_BASE+0x1a

//TX memory size register, R/W, default=0x55
#define W5100_TMSR	COMMON_BASE+0x1b

//Authentication type in PPPOE mode, R, default=0x0000
#define W5100_PATR	COMMON_BASE+0x1c

//PPP LCP request timer register, R/W, default=0x28
//Value 1 is about 25ms
#define W5100_PTIMER	COMMON_BASE+0x28

//PPP LCP magic number register, R/W, default=0x00
#define W5100_PMAGIC	COMMON_BASE+0x29

//Unreachable IP address, RO, default=0x00
#define W5100_UIPR	COMMON_BASE+0x2a

//Unreachable port register, RO, default=0x0000
#define W5100_UPORT	COMMON_BASE+0x2e


//-----------------------------------------------------------------------------
//                                  Socket register
//-----------------------------------------------------------------------------
//Socket mode register, R/W, default=0x00
#define W5100_S0_MR	COMMON_BASE+0x0400		//Socket 0
#define W5100_S1_MR	COMMON_BASE+0x0500		//Socket 1
#define W5100_S2_MR	COMMON_BASE+0x0600		//Socket 2
#define W5100_S3_MR	COMMON_BASE+0x0700		//Socket 3
	#define S_MR_MULTI	0x80			//Multcasting
	#define S_MR_MC		0x20			//Multcast

										//  P3   P2   P1   P0     Meaning
	#define S_MR_CLOSED		0x00		//  0    0    0    0      Closed
	#define S_MR_TCP		0x01		//  0    0    0    1      TCP
	#define S_MR_UDP		0x02		//  0    0    1    0      UDP
	#define S_MR_IPRAW		0x03		//  0    0    1    1      IPRAW
	#define S_MR_MACRAW		0x04		//  0    1    0    0      MACRAW
	#define S_MR_PPPOE		0x05		//  0    1    0    1      PPPOE

//Socket command register, R/W, default=0x00
#define W5100_S0_CR	COMMON_BASE+0x0401		//Socket 0
#define W5100_S1_CR	COMMON_BASE+0x0501		//Socket 1
#define W5100_S2_CR	COMMON_BASE+0x0601		//Socket 2
#define W5100_S3_CR	COMMON_BASE+0x0701		//Socket 3
	#define S_CR_OPEN		0x01		//It is used to initialize the socket
	#define S_CR_LISTEN		0x02		//In TCP mode, it waits for a connection request from any remote peer(Client)
	#define S_CR_CONNECT	0x04		//In TCP mode, it sends a connection request to remote peer(SERVER)
	#define S_CR_DISCON		0x08		//In TCP mode, it sends a connection termination request
	#define S_CR_CLOSE		0x10		//Used to close the socket
	#define S_CR_SEND		0x20		//It transmit the data as much as the increase size of write pointer
	#define S_CR_SEND_MAC	0x21		//In UDP mode, same as SEND
	#define S_CR_SEND_KEEP	0x22		//In TCP mode
	#define S_CR_RECV		0x40		//Receiving is processed including the value of socket RX read
										//pointer register

	/* Definition for PPPOE */
	#define S_CR_PCON	0x23		//Start of ADSL connection
	#define S_CR_PDISCON	0x24		//End of ADSL connection
	#define S_CR_PCR	0x25		//Send REQ message ineach phase
	#define S_CR_PCN	0x26		//Send NAK message in each phase
	#define S_CR_PCJ	0x27		//Senf REJECT message in each phase

//Socket interrup register, RO, default=0x00
#define W5100_S0_IR	COMMON_BASE+0x0402		//Socket 0
#define W5100_S1_IR	COMMON_BASE+0x0502		//Socket 1
#define W5100_S2_IR	COMMON_BASE+0x0602		//Socket 2
#define W5100_S3_IR	COMMON_BASE+0x0702		//Socket 3
	#define S_IR_SENDOK		0x10		//Send data complete
	#define S_IR_TIMEOUT	0x08		//Set if timeout occurs during connection or termination
										//or data transmission
	#define S_IR_RECV		0x04		//Set if data is received
	#define S_IR_DISCON		0x02		//Set if receiv connection termination request
	#define S_IR_CON		0x01		//Set if connetion is established

	/* Definition for PPPOE */
	#define S_IR_PRECV	0x80		//Indicate receiving no support option data
	#define S_IR_PFAIL	0x40		//Indicate PAP Authentication fail
	#define S_IR_PNEXT	0x20		//Go next phase

//Socket status register, RO, default=0x00
#define W5100_S0_SSR	COMMON_BASE+0x0403		//Socket 0
#define W5100_S1_SSR	COMMON_BASE+0x0503		//Socket 1
#define W5100_S2_SSR	COMMON_BASE+0x0603		//Socket 2
#define W5100_S3_SSR	COMMON_BASE+0x0703		//Socket 3
	#define S_SSR_CLOSED	0x00		//In case that OPEN command are given to Sn_CR, Timeout interrupt
						//is asserted or connection is terminated
	#define S_SSR_INIT	0x13		//In case that Sn_MR is set as TCP and OPEN commands are given to Sn_CR
	#define S_SSR_LISTEN	0x14		//In case that under the SOCK_INIT status, LISTEN commands
						//are given to Sn_CR
	#define S_SSR_ESTABLISHED	0x17	//In case that connection is established
	#define S_SSR_CLOSE_WAIT	0x1c	//In case that connection temination request is received
	#define S_SSR_UDP	0x22		//In case that OPEN command is given to Sn_CR when Sn_MR is set as UDP
	#define S_SSR_IPRAW	0x32		//In case that OPEN command is given to Sn_CR when Sn_MR is set as IPRAW
	#define S_SSR_MACRAW	0x42		//In case that OPEN command is given to S0_CR when S0_MR is set as MACRAW
	#define S_SSR_PPPOE	0x5f		//In case that OPEN command is given to S0_CR when S0_MR is set as PPPOE
	//Below is shown in the status change, and does not need much attention
	#define S_SSR_SYNSEND	0x15
	#define S_SSR_SYNRECV	0x16
	#define S_SSR_FIN_WAIT	0x18
	#define S_SSR_CLOSING	0x1a
	#define S_SSR_TIME_WAIT	0x1b
	#define S_SSR_LAST_ACK	0x1d
	#define S_SSR_ARP0	0x11
	#define S_SSR_ARP1	0x21
	#define S_SSR_ARP2	0x31

//Socket Source port register, R/W, default=0x00
#define W5100_S0_PORT	COMMON_BASE+0x0404		//Socket 0
#define W5100_S1_PORT	COMMON_BASE+0x0504		//Socket 1
#define W5100_S2_PORT	COMMON_BASE+0x0604		//Socket 2
#define W5100_S3_PORT	COMMON_BASE+0x0704		//Socket 3

//Socket destination hardware address register, R/W, default=0x00
#define W5100_S0_DHAR	COMMON_BASE+0x0406		//Socket 0
#define W5100_S1_DHAR	COMMON_BASE+0x0506		//Socket 1
#define W5100_S2_DHAR	COMMON_BASE+0x0606		//Socket 2
#define W5100_S3_DHAR	COMMON_BASE+0x0706		//Socket 3

//Socket destination IP address register, R/W, default=0x00
#define W5100_S0_DIPR	COMMON_BASE+0x040c		//Socket 0
#define W5100_S1_DIPR	COMMON_BASE+0x050c		//Socket 1
#define W5100_S2_DIPR	COMMON_BASE+0x060c		//Socket 2
#define W5100_S3_DIPR	COMMON_BASE+0x070c		//Socket 3

//Socket destionation port register, R/W, default=0x00
#define W5100_S0_DPORT	COMMON_BASE+0x0410		//Socket 0
#define W5100_S1_DPORT	COMMON_BASE+0x0510		//Socket 1
#define W5100_S2_DPORT	COMMON_BASE+0x0610		//Socket 2
#define W5100_S3_DPORT	COMMON_BASE+0x0710		//Socket 3

//Socket maximum segment size register, R/W, default=0x00
#define W5100_S0_MSS	COMMON_BASE+0x0412		//Socket 0
#define W5100_S1_MSS	COMMON_BASE+0x0512		//Socket 1
#define W5100_S2_MSS	COMMON_BASE+0x0612		//Socket 2
#define W5100_S3_MSS	COMMON_BASE+0x0712		//Socket 3

//Socket IP protocol register, R/W, default=0x00
//See http://www.iana.org/assignments/protocol-number
#define W5100_S0_PROTO	COMMON_BASE+0x0414		//Socket 0
#define W5100_S1_PROTO	COMMON_BASE+0x0514		//Socket 1
#define W5100_S2_PROTO	COMMON_BASE+0x0614		//Socket 2
#define W5100_S3_PROTO	COMMON_BASE+0x0714		//Socket 3

//Socket IP type of servce register, R/W, default=0x00
#define W5100_S0_TOS	COMMON_BASE+0x0415		//Socket 0
#define W5100_S1_TOS	COMMON_BASE+0x0515		//Socket 1
#define W5100_S2_TOS	COMMON_BASE+0x0615		//Socket 2
#define W5100_S3_TOS	COMMON_BASE+0x0715		//Socket 3

//Socket IP time to live register, R/W, default=0x80
#define W5100_S0_TTL	COMMON_BASE+0x0416		//Socket 0
#define W5100_S1_TTL	COMMON_BASE+0x0516		//Socket 1
#define W5100_S2_TTL	COMMON_BASE+0x0616		//Socket 2
#define W5100_S3_TTL	COMMON_BASE+0x0716		//Socket 3

//Socket TX free size register, RO, default=0x0800
//should read upper byte first and lower byte later
#define W5100_S0_TX_FSR		COMMON_BASE+0x0420		//Socket 0
#define W5100_S1_TX_FSR		COMMON_BASE+0x0520		//Socket 1
#define W5100_S2_TX_FSR		COMMON_BASE+0x0620		//Socket 2
#define W5100_S3_TX_FSR		COMMON_BASE+0x0720		//Socket 3

//Socket TX read pointer register, RO, default=0x0000
//should read upper byte first and lower byte later
#define W5100_S0_TX_RR		COMMON_BASE+0x0422		//Socket 0
#define W5100_S1_TX_RR		COMMON_BASE+0x0522		//Socket 1
#define W5100_S2_TX_RR		COMMON_BASE+0x0622		//Socket 2
#define W5100_S3_TX_RR		COMMON_BASE+0x0722		//Socket 3

//Socket TX write pointer register, R/W, default=0x0000
//should read upper byte first and lower byte later
#define W5100_S0_TX_WR		COMMON_BASE+0x0424		//Socket 0
#define W5100_S1_TX_WR		COMMON_BASE+0x0524		//Socket 1
#define W5100_S2_TX_WR		COMMON_BASE+0x0624		//Socket 2
#define W5100_S3_TX_WR		COMMON_BASE+0x0724		//Socket 3

//Socket RX size register, RO, default=0x0000
//should read upper byte first and lower byte later
#define W5100_S0_RX_RSR		COMMON_BASE+0x0426		//Socket 0
#define W5100_S1_RX_RSR		COMMON_BASE+0x0526		//Socket 1
#define W5100_S2_RX_RSR		COMMON_BASE+0x0626		//Socket 2
#define W5100_S3_RX_RSR		COMMON_BASE+0x0726		//Socket 3

//Socket RX read pointer register, R/W, default=0x0000
//should read upper byte first and lower byte later
#define W5100_S0_RX_RR		COMMON_BASE+0x0428		//Socket 0
#define W5100_S1_RX_RR		COMMON_BASE+0x0528		//Socket 1
#define W5100_S2_RX_RR		COMMON_BASE+0x0628		//Socket 2
#define W5100_S3_RX_RR		COMMON_BASE+0x0728		//Socket 3

//Socket RX read pointer register, R/W, default=0x0000
//should read upper byte first and lower byte later
#define W5100_S0_RX_WR		COMMON_BASE+0x042A		//Socket 0
#define W5100_S1_RX_WR		COMMON_BASE+0x052A		//Socket 1
#define W5100_S2_RX_WR		COMMON_BASE+0x062A		//Socket 2
#define W5100_S3_RX_WR		COMMON_BASE+0x072A		//Socket 3

//TX memory
#define W5100_TX	COMMON_BASE+0x4000

//RX memory
#define W5100_RX	COMMON_BASE+0x6000

/*********************************************************************
*							数据结构
**********************************************************************/

/*********************************************************************
*							缓冲区结构
**********************************************************************/

struct _W5100_Buf
{
	//缓冲区大小,单位字节
	uint16_t size;
	//基地址
	uint16_t base_addr;
	//屏蔽地址
	uint16_t mask_addr;
};

/*********************************************************************
*							全局变量声明
**********************************************************************/

/*********************************************************************
*							发送缓存区参数
**********************************************************************/

extern struct _W5100_Buf W5100_Tx_Buf[4];

/*********************************************************************
*							接收缓存区参数
**********************************************************************/

extern struct _W5100_Buf W5100_Rx_Buf[4];

/*********************************************************************
*							函数
**********************************************************************/

/*********************************************************************
*							初始化w5100
*参数:ip:本机ip,4字节
*	  mac:本机mac,6字节
*	  submask:掩码:4字节
*	  gateway:网关,4字节
*	  socket_tx_size:socket发送缓存大小,4字节
*	  socket_rx_size:socket接收缓存大小,4字节
**********************************************************************/

void drv_w5100_init(uint8_t *ip,uint8_t *mac,uint8_t *submask,uint8_t *gateway,\
					uint8_t *socket_tx_size,uint8_t *socket_rx_size);

/*********************************************************************
*							初始化io
*说明:初始化/INT和/RESET引脚
**********************************************************************/

void drv_w5100_init_io(void);

/*********************************************************************
*							初始化spi
**********************************************************************/

void drv_w5100_init_spi(void);

/*********************************************************************
*							初始化中断
**********************************************************************/

void drv_w5100_init_irq(void);

/*********************************************************************
*							复位w5100
**********************************************************************/

void drv_w5100_reset(void);

/*********************************************************************
*							使能芯片
*参数:enable:1使能,0关闭
**********************************************************************/

void drv_w5100_enable(uint8_t enable);

/*********************************************************************
*							spi口发送一个字节
*参数:byte:发送的字节
*返回:收到的字节
**********************************************************************/

uint8_t drv_w5100_spi_tx_byte(uint8_t byte);

/*********************************************************************
*							w5100写入一个字节
*参数:addr:地址
*     byte:字节
**********************************************************************/

void drv_w5100_tx_byte(uint16_t addr,uint8_t byte);

/*********************************************************************
*							w5100写缓存
*参数:addr:w5100缓存开始地址
*     buf:缓存区地址
*	  len:缓存长度
**********************************************************************/

void drv_w5100_tx_buf(uint16_t addr,uint8_t *buf,uint16_t len);

/*********************************************************************
*							w5100读取一个字节
*参数:addr:地址
*返回:读取的字节
**********************************************************************/

uint8_t drv_w5100_rx_byte(uint16_t addr);

/*********************************************************************
*							w5100读取缓存
*参数:addr:w5100缓存开始地址
*     buf:读取存放的缓存区地址
*	  len:读取长度
**********************************************************************/

void drv_w5100_rx_buf(uint16_t addr,uint8_t *buf,uint16_t len);

/*********************************************************************
*							w5100设置网关
*参数:addr:需要设置的网关,4字节
**********************************************************************/

void drv_w5100_set_gateway(uint8_t *addr);

/*********************************************************************
*							读取w5100网关
*参数:addr:读取的网关存放地址,4字节长度
**********************************************************************/

void drv_w5100_get_gateway(uint8_t *addr);

/*********************************************************************
*							w5100设置子网掩码
*参数:addr:需要设置的子网掩码,4字节
**********************************************************************/

void drv_w5100_set_submask(uint8_t *addr);

/*********************************************************************
*							读取w5100子网掩码
*参数:addr:读取的子网掩码,4字节
**********************************************************************/

void drv_w5100_get_submask(uint8_t *addr);

/*********************************************************************
*							w5100设置mac地址
*参数:mac:需要设置的mac,6字节
**********************************************************************/

void drv_w5100_set_mac(uint8_t *mac);

/*********************************************************************
*							读取w5100的mac地址
*参数:addr:读取mac地址,6字节
**********************************************************************/

void drv_w5100_get_mac(uint8_t *mac);

/*********************************************************************
*							w5100设置本机ip
*参数:ip:需要设置的ip,4字节
**********************************************************************/

void drv_w5100_set_ip(uint8_t *ip);

/*********************************************************************
*							读取w5100的ip地址
*参数:addr:读取ip地址,4字节
**********************************************************************/

void drv_w5100_get_ip(uint8_t *ip);

/*********************************************************************
*							w5100设置端口的端口号
*参数:socket:端口:0-3
*     port:端口号
**********************************************************************/

void drv_w5100_set_socket_port(uint8_t socket,uint16_t port);

/*********************************************************************
*							读取w5100端口的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t drv_w5100_get_socket_port(uint8_t socket);

/*********************************************************************
*							w5100设置端口的目的mac地址
*参数:socket:端口:0-3
*     mac:需要设置的mac,6字节
**********************************************************************/

void drv_w5100_set_socket_mac(uint8_t socket,uint8_t *mac);

/*********************************************************************
*							读取w5100端口的目的mac地址
*参数:socket:端口:0-3
*     mac:读取的目的mac,6字节
**********************************************************************/

void drv_w5100_get_socket_mac(uint8_t socket,uint8_t *mac);

/*********************************************************************
*							w5100设置端口的目的ip地址
*参数:socket:端口:0-3
*     ip:需要设置的ip,4字节
**********************************************************************/

void drv_w5100_set_socket_dst_ip(uint8_t socket,uint8_t *ip);

/*********************************************************************
*							读取w5100端口的目的ip地址
*参数:socket:端口:0-3
*     ip:读取的目的ip,4字节
**********************************************************************/

void drv_w5100_get_socket_dst_ip(uint8_t socket,uint8_t *ip);

/*********************************************************************
*							w5100设置端口的目的端口号
*参数:socket:端口:0-3
*     port:目的端口号
**********************************************************************/

void drv_w5100_set_socket_dst_port(uint8_t socket,uint16_t port);

/*********************************************************************
*							读取w5100端口的目的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t drv_w5100_get_socket_dst_port(uint8_t socket);

/*********************************************************************
*							设置w5100端口缓存大小
*说明:4个端口发送总缓存为8KB,接收总缓存为8KB
*参数:tx_size:发送缓存大小数组,4字节长度,值只能取1,2,4,8这4个.单位为KB
*     rx_size:发送缓存大小数组,4字节长度,值只能取1,2,4,8这4个.单位为KB
**********************************************************************/

void drv_w5100_set_socket_buf_size(uint8_t *tx_size,uint8_t *rx_size);

/*********************************************************************
*							读取w5100端口的发送存储器剩余空间寄存器
*参数:socket:端口:0-3
*返回:发送存储器剩余空间
**********************************************************************/

uint16_t drv_w5100_get_socket_tx_fsr(uint8_t socket);

/*********************************************************************
*							读取w5100端口的接收数据字节数寄存器
*参数:socket:端口:0-3
*返回:接收数据字节数
**********************************************************************/

uint16_t drv_w5100_get_socket_rx_rsr(uint8_t socket);

/*********************************************************************
*							读取w5100端口接收的数据
*参数:socket:端口:0-3
*     buf:接收的数据存放的缓存
*     len:读取接收数据长度
**********************************************************************/

//void drv_w5100_socket_rx(uint8_t socket,uint8_t *buf,uint16_t len);

/*********************************************************************
*							读取w5100端口接收的数据
*参数:socket:端口:0-3
*     buf:接收的数据存放的缓存
*     len:读取接收数据长度
*	  ip:接收数据的ip
*     port:接收数据的端口
**********************************************************************/

void drv_w5100_socket_rx(uint8_t socket,uint8_t *buf,uint16_t len,uint8_t *ip,uint16_t *port);

/*********************************************************************
*							w5100端口发送数据
*参数:socket:端口:0-3
*     buf:发送的数据存放的缓存
*     len:发送数据长度
**********************************************************************/

void drv_w5100_socket_tx(uint8_t socket,uint8_t *buf,uint16_t len);

#endif


drv_w5100.c

/*********************************************************************
*						  		w5100驱动层文件
*							  (c)copyright 2013,jdh
*						  		All Right Reserved
*文件名:drv_w5100.c
*程序员:jdh
*修改日期:2013/10/22
*		  2013/10/23
*		  2013/10/24
**********************************************************************/

/*********************************************************************
*							头文件
**********************************************************************/

#include "drv_w5100.h"
#include "drv_delay.h"

/*********************************************************************
*							全局变量定义
**********************************************************************/

/*********************************************************************
*							发送缓存区参数
**********************************************************************/

struct _W5100_Buf W5100_Tx_Buf[4];

/*********************************************************************
*							接收缓存区参数
**********************************************************************/

struct _W5100_Buf W5100_Rx_Buf[4];

/*********************************************************************
*							函数
**********************************************************************/

/*********************************************************************
*							初始化w5100
*参数:ip:本机ip,4字节
*	  mac:本机mac,6字节
*	  submask:掩码:4字节
*	  gateway:网关,4字节
*	  socket_tx_size:socket发送缓存大小,4字节
*	  socket_rx_size:socket接收缓存大小,4字节
**********************************************************************/

void drv_w5100_init(uint8_t *ip,uint8_t *mac,uint8_t *submask,uint8_t *gateway,\
					uint8_t *socket_tx_size,uint8_t *socket_rx_size)
{
	uint8_t value = 0;
	
	//初始化IO
	drv_w5100_init_io();
	//SPI初始化
	drv_w5100_init_spi();
	//中断初始化
	drv_w5100_init_irq();
	
	//复位w5100
	drv_w5100_reset();
	//软复位
	drv_w5100_tx_byte(W5100_MODE,MODE_RST);
	drv_delay_ms(300);
	
	//设置ip
	drv_w5100_set_ip(ip);
	//设置mac
	drv_w5100_set_mac(mac);
	//设置掩码
	drv_w5100_set_submask(submask);
	//设置网关
	drv_w5100_set_gateway(gateway);
	//端口缓存设置
	drv_w5100_set_socket_buf_size(socket_tx_size,socket_rx_size);
	
	//设置中断
	value = drv_w5100_rx_byte(W5100_IMR);
	value |= IMR_CONFLICT | IMR_UNREACH | \
			 IMR_S0_INT | IMR_S1_INT | IMR_S2_INT | IMR_S3_INT;
	drv_w5100_tx_byte(W5100_IMR,value);
}

/*********************************************************************
*							初始化io
*说明:初始化/INT和/RESET引脚
**********************************************************************/

void drv_w5100_init_io(void)
{
	//定义IO初始化结构体
	GPIO_InitTypeDef GPIO_InitStructure;

	//初始化时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
	//管脚初始化  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	//选择GPIO响应速度
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
	//设置为输出           
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
	//初始化    			
    GPIO_Init(GPIOD, &GPIO_InitStructure);  
	
	//初始化时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
	//管脚初始化  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	//选择GPIO响应速度
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
	//设置为输入         
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
	//初始化    			
    GPIO_Init(GPIOD, &GPIO_InitStructure);  
}

/*********************************************************************
*							初始化spi
**********************************************************************/

void drv_w5100_init_spi(void)
{
	//定义IO初始化结构体
	GPIO_InitTypeDef GPIO_InitStructure ;
	//定义SPI初始化结构体
	SPI_InitTypeDef  SPI_InitStructure ;

	//配置其他引脚
	//配置CS
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE ) ;
	//配置SPI引脚CSN
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init( GPIOA, &GPIO_InitStructure );
	//PA15默认是JTDI脚,重映射关闭JTDI功能
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	//关闭w5100
	drv_w5100_enable(0);
	drv_w5100_enable(1);
	drv_w5100_enable(0);

	//初始化SPI
	//关闭SPI
	SPI_Cmd(SPI3,DISABLE);
	//初始化SPI时钟	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3,ENABLE);
	//设置IO口时钟      
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); 
	//配置SPI3引脚:SCK, MISO and MOSI
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init( GPIOB, &GPIO_InitStructure );
	// SPI配置
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b ;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low ;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge ;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;
	//SPI波特率分频设置:72M-18M,64M-16M
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4 ;
	//SPI设置成LSB模式
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ;
	SPI_InitStructure.SPI_CRCPolynomial = 7 ;
	SPI_Init( SPI3, &SPI_InitStructure ) ;

	//启动SPI
	SPI_Cmd(SPI3,ENABLE);
}

/*********************************************************************
*							初始化中断
**********************************************************************/

void drv_w5100_init_irq(void)
{
	//定义中断结构体
	NVIC_InitTypeDef NVIC_InitStructure ;
	//定义外部中断结构体
	EXTI_InitTypeDef EXTI_InitStructure;

	//初始化中断脚PD6时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	//配置中断源为PD6
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource6);
	// 配置EXTI_Line6下降沿触发
	EXTI_ClearITPendingBit(EXTI_Line6);
	EXTI_InitStructure.EXTI_Line = EXTI_Line6;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	//打开NTRX中断
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;				//通道设置为外部中断线
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 		//中断抢占先等级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;           	//中断响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           		//打开中断
	NVIC_Init(&NVIC_InitStructure);                                 //初始化
	
	//清中断
	//EXTI_ClearITPendingBit(EXTI9_5_IRQn);
	//EXTI_Line0中断允许
	//EXTI_GenerateSWInterrupt(EXTI_Line6);
}

/*********************************************************************
*							复位w5100
**********************************************************************/

void drv_w5100_reset(void)
{
	GPIO_ResetBits(GPIOD,GPIO_Pin_3); 
	drv_delay_ms(20);   
	GPIO_SetBits(GPIOD,GPIO_Pin_3);                  
}

/*********************************************************************
*							使能芯片
*参数:enable:1使能,0关闭
**********************************************************************/

void drv_w5100_enable(uint8_t enable)
{
	if (enable)
	{
		//使能
		GPIO_ResetBits(GPIOA,GPIO_Pin_15); 
	}
	else
	{
		//关闭
		GPIO_SetBits(GPIOA,GPIO_Pin_15);
	}
}

/*********************************************************************
*							spi口发送一个字节
*参数:byte:发送的字节
*返回:收到的字节
**********************************************************************/

uint8_t drv_w5100_spi_tx_byte(uint8_t byte)
{
	while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);
	SPI_I2S_SendData(SPI3,byte); 	

	while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);
	return SPI_I2S_ReceiveData(SPI3);   
}

/*********************************************************************
*							w5100写入一个字节
*参数:addr:地址
*     byte:字节
**********************************************************************/

void drv_w5100_tx_byte(uint16_t addr,uint8_t byte)
{	
	//使能w5100
	drv_w5100_enable(1);
  
	drv_w5100_spi_tx_byte(WRITE_COMMAND);
	drv_w5100_spi_tx_byte(addr / 256);	    
	drv_w5100_spi_tx_byte(addr % 256);		
	drv_w5100_spi_tx_byte(byte);			
  
	//关闭w5100
	drv_w5100_enable(0);
}

/*********************************************************************
*							w5100写缓存
*参数:addr:w5100缓存开始地址
*     buf:缓存区地址
*	  len:缓存长度
**********************************************************************/

void drv_w5100_tx_buf(uint16_t addr,uint8_t *buf,uint16_t len)
{
	uint16_t i;

	for (i = 0; i < len; i++)
	{
		drv_w5100_tx_byte(addr + i,*buf++);
	}	
}

/*********************************************************************
*							w5100读取一个字节
*参数:addr:地址
*返回:读取的字节
**********************************************************************/

uint8_t drv_w5100_rx_byte(uint16_t addr)
{
	uint8_t byte = 0;
	
	//使能w5100
	drv_w5100_enable(1);
	
	drv_w5100_spi_tx_byte(READ_COMMAND);
	drv_w5100_spi_tx_byte(addr / 256);	    
	drv_w5100_spi_tx_byte(addr % 256);		
	byte = drv_w5100_spi_tx_byte(0);			
  
	//关闭w5100
	drv_w5100_enable(0);
  
	return byte;
}

/*********************************************************************
*							w5100读取缓存
*参数:addr:w5100缓存开始地址
*     buf:读取存放的缓存区地址
*	  len:读取长度
**********************************************************************/

void drv_w5100_rx_buf(uint16_t addr,uint8_t *buf,uint16_t len)
{
	uint16_t i;

	for (i = 0; i < len; i++)
	{
		*buf++ = drv_w5100_rx_byte(addr++);
	}	
} 

/*********************************************************************
*							w5100设置网关
*参数:addr:需要设置的网关,4字节
**********************************************************************/

void drv_w5100_set_gateway(uint8_t *addr)
{	
	uint8_t i = 0;
	
	for (i = 0;i < 4;i++)
	{
		drv_w5100_tx_byte(W5100_GAR + i,addr[i]);
	}
}

/*********************************************************************
*							读取w5100网关
*参数:addr:读取的网关存放地址,4字节长度
**********************************************************************/

void drv_w5100_get_gateway(uint8_t *addr)
{
	uint8_t i = 0;
	
	for (i = 0;i < 4;i++)
	{
		addr[i] = drv_w5100_rx_byte(W5100_GAR + i);
	}
}

/*********************************************************************
*							w5100设置子网掩码
*参数:addr:需要设置的子网掩码,4字节
**********************************************************************/

void drv_w5100_set_submask(uint8_t *addr)
{
	uint8_t i = 0;
	
	for (i = 0;i < 4;i++)
	{
		drv_w5100_tx_byte(W5100_SUBR + i,addr[i]);
	}
}

/*********************************************************************
*							读取w5100子网掩码
*参数:addr:读取的子网掩码,4字节
**********************************************************************/

void drv_w5100_get_submask(uint8_t *addr)
{	
	uint8_t i = 0;
	
	for (i = 0;i < 4;i++)
	{
		addr[i] = drv_w5100_rx_byte(W5100_SUBR + i);
	}
}

/*********************************************************************
*							w5100设置mac地址
*参数:mac:需要设置的mac,6字节
**********************************************************************/

void drv_w5100_set_mac(uint8_t *mac)
{
	uint8_t i = 0;
	
	for (i = 0;i < 6;i++)
	{
		drv_w5100_tx_byte(W5100_SHAR + i,mac[i]);
	}
}

/*********************************************************************
*							读取w5100的mac地址
*参数:addr:读取mac地址,6字节
**********************************************************************/

void drv_w5100_get_mac(uint8_t *mac)
{	
	uint8_t i = 0;
	
	for (i = 0;i < 6;i++)
	{
		mac[i] = drv_w5100_rx_byte(W5100_SHAR + i);
	}
}

/*********************************************************************
*							w5100设置本机ip
*参数:ip:需要设置的ip,4字节
**********************************************************************/

void drv_w5100_set_ip(uint8_t *ip)
{
	uint8_t i = 0;
	
	for (i = 0;i < 4;i++)
	{
		drv_w5100_tx_byte(W5100_SIPR + i,ip[i]);
	}
}

/*********************************************************************
*							读取w5100的ip地址
*参数:addr:读取ip地址,4字节
**********************************************************************/

void drv_w5100_get_ip(uint8_t *ip)
{	
	uint8_t i = 0;
	
	for (i = 0;i < 4;i++)
	{
		ip[i] = drv_w5100_rx_byte(W5100_SIPR + i);
	}
}

/*********************************************************************
*							w5100设置端口的端口号
*参数:socket:端口:0-3
*     port:端口号
**********************************************************************/

void drv_w5100_set_socket_port(uint8_t socket,uint16_t port)
{
	uint16_t reg = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_PORT + socket * 0x100;
	//设置端口号
	drv_w5100_tx_byte(reg,(port >> 8) & 0xff);
	drv_w5100_tx_byte(reg + 1,port & 0xff);
}

/*********************************************************************
*							读取w5100端口的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t drv_w5100_get_socket_port(uint8_t socket)
{
	uint16_t reg = 0;
	uint16_t port = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_PORT + socket * 0x100;
	//设置端口号
	port = drv_w5100_rx_byte(reg);
	port = (port << 8) + drv_w5100_rx_byte(reg + 1);
	
	return port;
}

/*********************************************************************
*							w5100设置端口的目的mac地址
*参数:socket:端口:0-3
*     mac:需要设置的mac,6字节
**********************************************************************/

void drv_w5100_set_socket_mac(uint8_t socket,uint8_t *mac)
{
	uint8_t i = 0;
	uint16_t reg = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_DHAR + socket * 0x100;
	//设置mac
	for (i = 0;i < 6;i++)
	{
		drv_w5100_tx_byte(reg + i,mac[i]);
	}
}

/*********************************************************************
*							读取w5100端口的目的mac地址
*参数:socket:端口:0-3
*     mac:读取的目的mac,6字节
**********************************************************************/

void drv_w5100_get_socket_mac(uint8_t socket,uint8_t *mac)
{
	uint8_t i = 0;
	uint16_t reg = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_DHAR + socket * 0x100;
	//设置mac
	for (i = 0;i < 6;i++)
	{
		mac[i] = drv_w5100_rx_byte(reg + i);
	}
}

/*********************************************************************
*							w5100设置端口的目的ip地址
*参数:socket:端口:0-3
*     ip:需要设置的ip,4字节
**********************************************************************/

void drv_w5100_set_socket_dst_ip(uint8_t socket,uint8_t *ip)
{
	uint8_t i = 0;
	uint16_t reg = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_DIPR + socket * 0x100;
	//设置ip
	for (i = 0;i < 4;i++)
	{
		drv_w5100_tx_byte(reg + i,ip[i]);
	}
}

/*********************************************************************
*							读取w5100端口的目的ip地址
*参数:socket:端口:0-3
*     ip:读取的目的ip,4字节
**********************************************************************/

void drv_w5100_get_socket_dst_ip(uint8_t socket,uint8_t *ip)
{
	uint8_t i = 0;
	uint16_t reg = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_DIPR + socket * 0x100;
	//读取ip
	for (i = 0;i < 4;i++)
	{
		ip[i] = drv_w5100_rx_byte(reg + i);
	}
}

/*********************************************************************
*							w5100设置端口的目的端口号
*参数:socket:端口:0-3
*     port:目的端口号
**********************************************************************/

void drv_w5100_set_socket_dst_port(uint8_t socket,uint16_t port)
{
	uint16_t reg = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_DPORT + socket * 0x100;
	//设置端口号
	drv_w5100_tx_byte(reg,(port >> 8) & 0xff);
	drv_w5100_tx_byte(reg + 1,port & 0xff);
}

/*********************************************************************
*							读取w5100端口的目的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t drv_w5100_get_socket_dst_port(uint8_t socket)
{
	uint16_t reg = 0;
	uint16_t port = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_DPORT + socket * 0x100;
	//设置端口号
	port = drv_w5100_rx_byte(reg);
	port = (port << 8) + drv_w5100_rx_byte(reg + 1);
	
	return port;
}

/*********************************************************************
*							设置w5100端口缓存大小
*说明:4个端口发送总缓存为8KB,接收总缓存为8KB
*参数:tx_size:发送缓存大小数组,4字节长度,值只能取1,2,4,8这4个.单位为KB
*     rx_size:发送缓存大小数组,4字节长度,值只能取1,2,4,8这4个.单位为KB
**********************************************************************/

void drv_w5100_set_socket_buf_size(uint8_t *tx_size,uint8_t *rx_size)
{
	uint8_t value = 0;
	uint8_t i = 0;
	uint8_t tx_reg[4] = {0};
	uint8_t rx_reg[4] = {0};
	
	for (i = 0;i < 4;i++)
	{
		switch (tx_size[i])
		{
		case 1:
			{
				tx_reg[i] = 0;
				break;
			}
		case 2:
			{
				tx_reg[i] = 1;
				break;
			}
		case 4:
			{
				tx_reg[i] = 2;
				break;
			}
		case 8:
			{
				tx_reg[i] = 3;
				break;
			}
		}
		
		switch (rx_size[i])
		{
		case 1:
			{
				rx_reg[i] = 0;
				break;
			}
		case 2:
			{
				rx_reg[i] = 1;
				break;
			}
		case 4:
			{
				rx_reg[i] = 2;
				break;
			}
		case 8:
			{
				rx_reg[i] = 3;
				break;
			}
		}
	}
	
	//设置写缓存大小
	value = (tx_reg[3] << 6) + (tx_reg[2] << 4) + \
			(tx_reg[1] << 2) + tx_reg[0];
	drv_w5100_tx_byte(W5100_TMSR, value);
	
	//设置读缓存大小
	value = (rx_reg[3] << 6) + (rx_reg[2] << 4) + \
			(rx_reg[1] << 2) + rx_reg[0];
	drv_w5100_tx_byte(W5100_RMSR, value);
	
	//设置缓冲区参数
	for (i = 0;i < 4;i++)
	{
		//缓冲区大小
		W5100_Tx_Buf[i].size = tx_size[i] * 1024;
		W5100_Rx_Buf[i].size = rx_size[i] * 1024;
		
		//屏蔽地址
		W5100_Tx_Buf[i].mask_addr = W5100_Tx_Buf[i].size - 1;
		W5100_Rx_Buf[i].mask_addr = W5100_Rx_Buf[i].size - 1;
		
		//基地址
		if (i == 0)
		{
			W5100_Tx_Buf[i].base_addr = W5100_TX;
			W5100_Rx_Buf[i].base_addr = W5100_RX;
		}
		else
		{
			W5100_Tx_Buf[i].base_addr = W5100_Tx_Buf[i - 1].base_addr + W5100_Tx_Buf[i - 1].size;
			W5100_Rx_Buf[i].base_addr = W5100_Rx_Buf[i - 1].base_addr + W5100_Tx_Buf[i - 1].size;
		}
	}
}

/*********************************************************************
*							读取w5100端口的发送存储器剩余空间寄存器
*参数:socket:端口:0-3
*返回:发送存储器剩余空间
**********************************************************************/

uint16_t drv_w5100_get_socket_tx_fsr(uint8_t socket)
{
	uint16_t reg = 0;
	uint16_t size1 = 0;
	uint16_t size2 = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_TX_FSR + socket * 0x100;
	
	while (1)
	{
		//读取中断寄存器
		size1 = drv_w5100_rx_byte(reg);
		size1 = (size1 << 8) + drv_w5100_rx_byte(reg + 1);
		if (size1 != 0)
		{
			size2 = drv_w5100_rx_byte(reg);
			size2 = (size2 << 8) + drv_w5100_rx_byte(reg + 1);
			
			if (size1 == size2)
			{
				break;
			}
		}
	}
	
	return size1;
}

/*********************************************************************
*							读取w5100端口的接收数据字节数寄存器
*参数:socket:端口:0-3
*返回:接收数据字节数
**********************************************************************/

uint16_t drv_w5100_get_socket_rx_rsr(uint8_t socket)
{
	uint16_t reg = 0;
	uint16_t size1 = 0;
	uint16_t size2 = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_RX_RSR + socket * 0x100;
	
	while (1)
	{
		//读取中断寄存器
		size1 = drv_w5100_rx_byte(reg);
		size1 = (size1 << 8) + drv_w5100_rx_byte(reg + 1);
		if (size1 != 0)
		{
			size2 = drv_w5100_rx_byte(reg);
			size2 = (size2 << 8) + drv_w5100_rx_byte(reg + 1);
			
			if (size1 == size2)
			{
				break;
			}
		}
	}
	
	return size1;
}

/*********************************************************************
*							读取w5100端口接收的数据
*参数:socket:端口:0-3
*     buf:接收的数据存放的缓存
*     len:读取接收数据长度
*	  ip:接收数据的ip
*     port:接收数据的端口
**********************************************************************/

void drv_w5100_socket_rx(uint8_t socket,uint8_t *buf,uint16_t len,uint8_t *ip,uint16_t *port)
{
	uint16_t shift = 0;
	uint16_t addr = 0;
	uint16_t reg = 0;
	uint16_t size = 0;
	uint16_t i = 0;
	uint8_t header[8] = {0};
	
	//读取接收缓冲区偏移量
	reg = W5100_S0_RX_RR + socket * 0x100;
	shift = drv_w5100_rx_byte(reg);
	shift = (shift << 8) + drv_w5100_rx_byte(reg + 1);
	//实际的偏移量
	shift &= W5100_Rx_Buf[socket].mask_addr;
	//物理地址
	addr = W5100_Rx_Buf[socket].base_addr + shift;

	/*
	for (i = 0;i < len;i++)
	{
		if (shift >= W5100_Rx_Buf[socket].size)
		{
			addr = W5100_Rx_Buf[socket].base_addr;
			shift = 0;
		}
		buf[i] = drv_w5100_rx_byte(addr++);
		shift++;
	}
	*/
	/*
	//读取正文
	if (shift + len > W5100_Rx_Buf[socket].size)
	{
		size = W5100_Rx_Buf[socket].size - shift;
		drv_w5100_rx_buf(addr, buf, size);
		drv_w5100_rx_buf(W5100_Rx_Buf[socket].base_addr, buf + size, len - size);
	}
	else
	{
		drv_w5100_rx_buf(addr, buf, len);
	}
	*/
	//读取帧头
	if (shift + 8 > W5100_Rx_Buf[socket].size)
	{
		size = W5100_Rx_Buf[socket].size - shift;
		drv_w5100_rx_buf(addr, header, size);
		drv_w5100_rx_buf(W5100_Rx_Buf[socket].base_addr, header + size, 8 - size);
		shift = 8 - size;
	}
	else
	{
		drv_w5100_rx_buf(addr, header, 8);
		shift += 8;
	}
	
	//保存帧头
	//读取ip
	ip[0] = header[0];
	ip[1] = header[1];
	ip[2] = header[2];
	ip[3] = header[3];
	//端口
	*port = (header[4] << 8) + header[5];
	
	//实际地址更改
	addr = W5100_Rx_Buf[socket].base_addr + shift;
	//接收数据长度更改
	len -= 8;
	
	//读取正文
	if (shift + len > W5100_Rx_Buf[socket].size)
	{
		size = W5100_Rx_Buf[socket].size - shift;
		drv_w5100_rx_buf(addr, buf, size);
		drv_w5100_rx_buf(W5100_Rx_Buf[socket].base_addr, buf + size, len - size);
	}
	else
	{
		drv_w5100_rx_buf(addr, buf, len);
	}
	
	//计算下一次偏移量
	shift = drv_w5100_rx_byte(reg);
	shift = (shift << 8) + drv_w5100_rx_byte(reg + 1);
	shift += len + 8;
	drv_w5100_tx_byte(reg,(shift >> 8) & 0xff);
	drv_w5100_tx_byte(reg + 1,shift & 0xff);
	
	//接收处理完成
	reg = W5100_S0_CR + socket * 0x100;
	drv_w5100_tx_byte(reg,S_CR_RECV);
}

/*********************************************************************
*							w5100端口发送数据
*参数:socket:端口:0-3
*     buf:发送的数据存放的缓存
*     len:发送数据长度
**********************************************************************/

void drv_w5100_socket_tx(uint8_t socket,uint8_t *buf,uint16_t len)
{
	uint16_t shift = 0;
	uint16_t addr = 0;
	uint16_t reg = 0;
	uint16_t size = 0;
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_TX_WR + socket * 0x100;
	//获得接收缓冲区读指针地址
	shift = drv_w5100_rx_byte(reg);
	shift = (shift << 8) + drv_w5100_rx_byte(reg + 1);
	//偏移地址
	shift &= W5100_Tx_Buf[socket].mask_addr;
	//实际地址
	addr = W5100_Tx_Buf[socket].base_addr + shift;
	
	//发送数据
	if (shift + len > W5100_Tx_Buf[socket].size)
	{
		size = W5100_Tx_Buf[socket].size - shift;
		drv_w5100_tx_buf(addr, buf, size);
		drv_w5100_tx_buf(W5100_Tx_Buf[socket].base_addr, buf + size, len - size);
	}
	else
	{
		drv_w5100_tx_buf(addr, buf, len);
	}
	
	//发送指针偏移
	shift = drv_w5100_rx_byte(reg);
	shift = (shift << 8) + drv_w5100_rx_byte(reg + 1);
	shift += len;
	drv_w5100_tx_byte(reg, (shift >> 8) & 0xff);
	drv_w5100_tx_byte(reg + 1, shift & 0xff);
	
	//根据端口号选择寄存器地址
	reg = W5100_S0_CR + socket * 0x100;
	//发送
	drv_w5100_tx_byte(reg, S_CR_SEND);
}


接口层文件:

inf_w5100.h

/*********************************************************************
*						  w5100接口层头文件
*						(c)copyright 2013,jdh
*						  All Right Reserved
*文件名:inf_w5100.h
*程序员:jdh
*修改日期:2013/10/24
**********************************************************************/

#ifndef _INF_W5100_H_
#define _INF_W5100_H_

/*********************************************************************
*							头文件
**********************************************************************/

//驱动层头文件
#include "drv_w5100.h"

/*********************************************************************
*							数据结构
**********************************************************************/

/*********************************************************************
*							数据结构
**********************************************************************/

/*********************************************************************
*							w5100端口中断信息
**********************************************************************/

struct _W5100_Socket_Irq_Msg
{
	//端口中断
	uint8_t socket_int;
	
	//数据发送完成
	uint8_t send_ok;
	//在连接或终止,数据发送等过程超时
	uint8_t timeout;
	//当端口接收到数据时
	uint8_t recv;
	//当收到终止连接请求或终止连接过程已结束
	uint8_t discon;
	//当连接成功时
	uint8_t con;
	
	//接收ip
	uint8_t ip[4];
	//接收端口
	uint16_t port;
	//接收数据的字节数
	uint16_t size;
};

/*********************************************************************
*							w5100中断信息
**********************************************************************/

struct _W5100_Irq_Msg
{
	//ip冲突
	uint8_t confict;
	//无法到达地址
	uint8_t unreach;
	//PPPoe连接关闭
	uint8_t pppoe;
	
	//端口中断信息
	struct _W5100_Socket_Irq_Msg socket_msg[4];
};

/*********************************************************************
*							函数
**********************************************************************/

/*********************************************************************
*							初始化w5100
*参数:ip:本机ip,4字节
*	  mac:本机mac,6字节
*	  submask:掩码:4字节
*	  gateway:网关,4字节
*	  socket_tx_size:socket发送缓存大小,4字节
*	  socket_rx_size:socket接收缓存大小,4字节
**********************************************************************/

void inf_w5100_init(uint8_t *ip,uint8_t *mac,uint8_t *submask,uint8_t *gateway,\
					uint8_t *socket_tx_size,uint8_t *socket_rx_size);
					
/*********************************************************************
*							w5100设置本机ip
*参数:ip:需要设置的ip,4字节
**********************************************************************/

void inf_w5100_set_ip(uint8_t *ip);

/*********************************************************************
*							读取w5100的ip地址
*参数:addr:读取ip地址,4字节
**********************************************************************/

void inf_w5100_get_ip(uint8_t *ip);

/*********************************************************************
*							w5100设置mac地址
*参数:mac:需要设置的mac,6字节
**********************************************************************/

void inf_w5100_set_mac(uint8_t *mac);

/*********************************************************************
*							读取w5100的mac地址
*参数:addr:读取mac地址,4字节
**********************************************************************/

void inf_w5100_get_mac(uint8_t *mac);

/*********************************************************************
*							w5100设置网关
*参数:addr:需要设置的网关,4字节
**********************************************************************/

void inf_w5100_set_gateway(uint8_t *addr);

/*********************************************************************
*							读取w5100网关
*参数:addr:读取的网关存放地址,4字节长度
**********************************************************************/

void inf_w5100_get_gateway(uint8_t *addr);

/*********************************************************************
*							w5100设置子网掩码
*参数:addr:需要设置的子网掩码,4字节
**********************************************************************/

void inf_w5100_set_submask(uint8_t *addr);

/*********************************************************************
*							读取w5100子网掩码
*参数:addr:读取的子网掩码,4字节
**********************************************************************/

void inf_w5100_get_submask(uint8_t *addr);

/*********************************************************************
*							读取w5100端口的目的ip地址
*参数:socket:端口:0-3
*     ip:读取的目的ip,4字节
**********************************************************************/

void inf_w5100_get_socket_dst_ip(uint8_t socket,uint8_t *ip);

/*********************************************************************
*							读取w5100端口的目的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t inf_w5100_get_socket_dst_port(uint8_t socket);

/*********************************************************************
*							读取w5100端口的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t inf_w5100_get_socket_port(uint8_t socket);

/*********************************************************************
*							w5100设置端口为udp模式
*参数:socket:端口:0-3
*	  port:端口号
**********************************************************************/

void inf_w5100_set_socket_udp_mode(uint8_t socket,uint16_t port);

/*********************************************************************
*							w5100发送数据
*参数:socket:端口
*	  data:数据
*	  size:大小,单位字节
*	  ip:目标ip
*	  port:目标端口号
**********************************************************************/

void inf_w5100_write_data(uint16_t socket,uint8_t *data,uint16_t size,\
						  uint8_t *ip,uint16_t port);

/*********************************************************************
*							清除中断信息结构体
*参数:msg:中断结构体地址
**********************************************************************/

void inf_w5100_clear_w5100_irg_msg(struct _W5100_Irq_Msg *msg);
						  
/*********************************************************************
*							w5100中断处理函数
*参数:msg:中断信息
*	  buf0:接收socket0数据地址
*	  buf1:接收socket1数据地址
*	  buf2:接收socket2数据地址
*	  buf3:接收socket3数据地址
**********************************************************************/

void inf_w5100_irq_handler(struct _W5100_Irq_Msg *msg,uint8_t *buf0,uint8_t *buf1,uint8_t *buf2,uint8_t *buf3);

#endif


inf_w5100.c

/*********************************************************************
*						  w5100接口层文件
*						(c)copyright 2013,jdh
*						  All Right Reserved
*文件名:inf_w5100.c
*程序员:jdh
*修改日期:2013/10/24
**********************************************************************/

/*********************************************************************
*							头文件
**********************************************************************/

#include "inf_w5100.h"

/*********************************************************************
*							函数
**********************************************************************/

/*********************************************************************
*							初始化w5100
*参数:ip:本机ip,4字节
*	  mac:本机mac,6字节
*	  submask:掩码:4字节
*	  gateway:网关,4字节
*	  socket_tx_size:socket发送缓存大小,4字节
*	  socket_rx_size:socket接收缓存大小,4字节
**********************************************************************/

void inf_w5100_init(uint8_t *ip,uint8_t *mac,uint8_t *submask,uint8_t *gateway,\
					uint8_t *socket_tx_size,uint8_t *socket_rx_size)
{
	drv_w5100_init(ip,mac,submask,gateway,socket_tx_size,socket_rx_size);
}

/*********************************************************************
*							w5100设置本机ip
*参数:ip:需要设置的ip,4字节
**********************************************************************/

void inf_w5100_set_ip(uint8_t *ip)
{
	drv_w5100_set_ip(ip);
}

/*********************************************************************
*							读取w5100的ip地址
*参数:addr:读取ip地址,4字节
**********************************************************************/

void inf_w5100_get_ip(uint8_t *ip)
{
	drv_w5100_get_ip(ip);
}

/*********************************************************************
*							w5100设置mac地址
*参数:mac:需要设置的mac,6字节
**********************************************************************/

void inf_w5100_set_mac(uint8_t *mac)
{
	drv_w5100_set_mac(mac);
}

/*********************************************************************
*							读取w5100的mac地址
*参数:addr:读取mac地址,4字节
**********************************************************************/

void inf_w5100_get_mac(uint8_t *mac)
{
	drv_w5100_get_mac(mac);
}

/*********************************************************************
*							w5100设置网关
*参数:addr:需要设置的网关,4字节
**********************************************************************/

void inf_w5100_set_gateway(uint8_t *addr)
{
	drv_w5100_set_gateway(addr);
}

/*********************************************************************
*							读取w5100网关
*参数:addr:读取的网关存放地址,4字节长度
**********************************************************************/

void inf_w5100_get_gateway(uint8_t *addr)
{
	drv_w5100_get_gateway(addr);
}

/*********************************************************************
*							w5100设置子网掩码
*参数:addr:需要设置的子网掩码,4字节
**********************************************************************/

void inf_w5100_set_submask(uint8_t *addr)
{
	drv_w5100_set_submask(addr);
}

/*********************************************************************
*							读取w5100子网掩码
*参数:addr:读取的子网掩码,4字节
**********************************************************************/

void inf_w5100_get_submask(uint8_t *addr)
{
	drv_w5100_get_submask(addr);
}

/*********************************************************************
*							读取w5100端口的目的ip地址
*参数:socket:端口:0-3
*     ip:读取的目的ip,4字节
**********************************************************************/

void inf_w5100_get_socket_dst_ip(uint8_t socket,uint8_t *ip)
{
	drv_w5100_get_socket_dst_ip(socket,ip);
}

/*********************************************************************
*							读取w5100端口的目的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t inf_w5100_get_socket_dst_port(uint8_t socket)
{
	return drv_w5100_get_socket_dst_port(socket);
}

/*********************************************************************
*							读取w5100端口的端口号
*参数:socket:端口:0-3
*返回:端口号
**********************************************************************/

uint16_t inf_w5100_get_socket_port(uint8_t socket)
{
	return drv_w5100_get_socket_port(socket);
}

/*********************************************************************
*							w5100设置端口为udp模式
*参数:socket:端口:0-3
*	  port:端口号
**********************************************************************/

void inf_w5100_set_socket_udp_mode(uint8_t socket,uint16_t port)
{
	uint8_t state = 0;
	uint16_t reg = 0;
	
	while (1)
	{
		//设置为udp模式
		//根据端口号选择寄存器地址
		reg = W5100_S0_MR + socket * 0x100;
		//设置端口模式
		drv_w5100_tx_byte(reg,S_MR_UDP);
			
		//设置端口号
		drv_w5100_set_socket_port(socket,port);
		
		//打开端口
		//根据端口号选择寄存器地址
		reg = W5100_S0_CR + socket * 0x100;
		//端口开关
		drv_w5100_tx_byte(reg,S_CR_OPEN);
		
		//读取端口状态
		reg = W5100_S0_SSR + socket * 0x100;
		state = drv_w5100_rx_byte(reg);
		if (state == S_SSR_UDP)
		{
			break;
		}
		else
		{
			//关闭端口
			//根据端口号选择寄存器地址
			reg = W5100_S0_CR + socket * 0x100;
			//端口开关
			drv_w5100_tx_byte(reg,0x10);
		}
	}
}

/*********************************************************************
*							w5100发送数据
*参数:socket:端口
*	  data:数据
*	  size:大小,单位字节
*	  ip:目标ip,4字节
*	  port:目标端口号
**********************************************************************/

void inf_w5100_write_data(uint16_t socket,uint8_t *data,uint16_t size,\
						  uint8_t *ip,uint16_t port)
{
	uint16_t free_bytes = 0;
	uint8_t dst_ip[4] = {0};
	
	//等待端口有足够空间发送
	while (1)
	{
		free_bytes = drv_w5100_get_socket_tx_fsr(socket);
		if (free_bytes >= size)
		{
			break;
		}
	}
	//设置目标ip
	drv_w5100_set_socket_dst_ip(socket,ip);
	//设置目标端口
	drv_w5100_set_socket_dst_port(socket,port);
	//发送数据
	drv_w5100_socket_tx(socket,data,size);
}

/*********************************************************************
*							清除中断信息结构体
*参数:msg:中断结构体地址
**********************************************************************/

void inf_w5100_clear_w5100_irg_msg(struct _W5100_Irq_Msg *msg)
{
	uint8_t i = 0;
	
	//ip冲突
	msg->confict = 0;
	//无法到达地址
	msg->unreach = 0;
	//PPPoe连接关闭
	msg->pppoe = 0;
	
	for (i = 0;i < 4;i++)
	{
		//端口中断
		msg->socket_msg[i].socket_int = 0;
		
		//端口中断信息
		//数据发送完成
		msg->socket_msg[i].send_ok = 0;
		//在连接或终止,数据发送等过程超时
		msg->socket_msg[i].timeout = 0;
		//当端口接收到数据时
		msg->socket_msg[i].recv = 0;
		//当收到终止连接请求或终止连接过程已结束
		msg->socket_msg[i].discon = 0;
		//当连接成功时
		msg->socket_msg[i].con = 0;
		
		//ip
		msg->socket_msg[i].ip[0] = 0;
		msg->socket_msg[i].ip[1] = 0;
		msg->socket_msg[i].ip[2] = 0;
		msg->socket_msg[i].ip[3] = 0;
		//端口
		msg->socket_msg[i].port = 0;
		//接收的字节数
		msg->socket_msg[i].size = 0;
	}
}

/*********************************************************************
*							w5100中断处理函数
*参数:msg:中断信息
*	  buf0:接收socket0数据地址
*	  buf1:接收socket1数据地址
*	  buf2:接收socket2数据地址
*	  buf3:接收socket3数据地址
**********************************************************************/

void inf_w5100_irq_handler(struct _W5100_Irq_Msg *msg,uint8_t *buf0,uint8_t *buf1,uint8_t *buf2,uint8_t *buf3)
{
	uint8_t reg_value = 0;
	uint8_t i = 0;
	uint8_t flag[4] = {0};
	uint16_t reg_addr = 0;
	uint16_t shift = 0;
	
	//清除中断信号
	inf_w5100_clear_w5100_irg_msg(msg);
	
	//读取中断寄存器,判断中断类型
	reg_value = drv_w5100_rx_byte(W5100_IR);
	//清中断标志
	drv_w5100_tx_byte(W5100_IR,reg_value & 0xf0);
	
	//判断中断类型
	//IP地址冲突
	if ((reg_value & IR_CONFLICT) == IR_CONFLICT)
	{
		msg->confict = 1;
	}
	
	//无法抵达地址
	if ((reg_value & IR_UNREACH) == IR_UNREACH)
	{
		msg->unreach = 1;
	}
	
	//端口0中断
	if ((reg_value & IR_S0_INT) == IR_S0_INT)
	{
		flag[0] = 1;
	}
	
	//端口1中断
	if ((reg_value & IR_S1_INT) == IR_S1_INT)
	{
		flag[1] = 1;
	}
	
	//端口2中断
	if ((reg_value & IR_S2_INT) == IR_S2_INT)
	{
		flag[2] = 1;
	}
	
	//端口3中断
	if ((reg_value & IR_S3_INT) == IR_S3_INT)
	{
		flag[3] = 1;
	}
	
	for (i = 0;i < 4;i++)
	{
		if (flag[i])
		{
			msg->socket_msg[i].socket_int = 1;
			
			//读取端口中断寄存器
			reg_addr = W5100_S0_IR + i * 0x100;
			reg_value = drv_w5100_rx_byte(reg_addr);
			//清中断标志
			drv_w5100_tx_byte(reg_addr,reg_value);
				
			//判断中断类型
			//数据发送完成
			if ((reg_value & S_IR_SENDOK) == S_IR_SENDOK)
			{
				msg->socket_msg[i].send_ok = 1;
			}
			
			//在连接或终止,数据发送等过程超时
			if ((reg_value & S_IR_TIMEOUT) == S_IR_TIMEOUT)
			{
				msg->socket_msg[i].timeout = 1;
			}
			
			//当端口接收到数据时
			if ((reg_value & S_IR_RECV) == S_IR_RECV)
			{
				msg->socket_msg[i].recv = 1;
				msg->socket_msg[i].size = drv_w5100_get_socket_rx_rsr(i);
				
				//读取接收字节数
				switch (i)
				{
				case 0:
					{
						drv_w5100_socket_rx(i,buf0,msg->socket_msg[i].size,\
											msg->socket_msg[i].ip,&msg->socket_msg[i].port);
						break;
					}
				case 1:
					{
						drv_w5100_socket_rx(i,buf1,msg->socket_msg[i].size,\
											msg->socket_msg[i].ip,&msg->socket_msg[i].port);
						break;
					}
				case 2:
					{
						drv_w5100_socket_rx(i,buf2,msg->socket_msg[i].size,\
											msg->socket_msg[i].ip,&msg->socket_msg[i].port);
						break;
					}
				case 3:
					{
						drv_w5100_socket_rx(i,buf3,msg->socket_msg[i].size,\
											msg->socket_msg[i].ip,&msg->socket_msg[i].port);
						break;
					}
				}
				
				//接收正文字节数
				msg->socket_msg[i].size -= 8;
			}
			
			//当收到终止连接请求或终止连接过程已结束
			if ((reg_value & S_IR_DISCON) == S_IR_DISCON)
			{
				msg->socket_msg[i].discon = 1;
			}
			
			//当连接成功时
			if ((reg_value & S_IR_CON) == S_IR_CON)
			{
				msg->socket_msg[i].con = 1;
			}
		}
	}
}

测试代码:

main.c:初始化w5100

int main(void)
{
	uint8_t i = 0;
	uint16_t buf1[3] = {1,2,3};
	uint16_t buf2[10] = {0};
	uint8_t ip[4] = {10,58,1,5};

	uint8_t mac[6] = {0x00,0xe0,0x4c,0x36,0xc9,0xb0};
	uint8_t submask[4] = {255,255,255,0};
	uint8_t gateway[4] = {10,58,1,1};
	uint8_t socket_tx_size[4] = {2,2,2,2};
	uint8_t socket_rx_size[4] = {2,2,2,2};

	uint8_t dst_ip[4] = {10,58,1,3};
	uint8_t buf[3] = {'j','d','h'};

	uint8_t arr[10] = {0};
	
	//初始化设备
	init_device();

#ifndef DEBUG	
	//打开内部看门狗
	inf_enable_iwdg();
#endif
	
	//sram测试代码
	//FSMC_SRAM_WriteHalfWord(0,1);
	//FSMC_SRAM_WriteHalfWord(2,2);
	//FSMC_SRAM_WriteHalfWord(4,3);
	//Test_Data = FSMC_SRAM_ReadHalfWord(2);
	//FSMC_SRAM_WriteBuffer(buf1,0,3);
	//FSMC_SRAM_ReadBuffer(buf2,0,3);
	test_sram[0] = 5;
	test_sram[1] = 2;
	test_sram[2] = 3;
	FSMC_SRAM_ReadBuffer(buf2,0,10);
	__nop();
	
	//初始化网络
	inf_w5100_init(ip,mac,submask,gateway,socket_tx_size,socket_rx_size);
	
	//打开端口
	inf_w5100_set_socket_udp_mode(SOCKET0,2000);
	
	//inf_delay_ms(5000);
	
	//发送数据
	//inf_w5100_write_data(SOCKET0,ip,4,dst_ip,2000);
	
	
	

	//状态机执行
	while (1)
	{
		for (i = 0;i < 6;i++)
		{
			inf_set_led(i + 1,LED_ON);
			inf_delay_ms(10);
			inf_set_led(i + 1,LED_OFF);
			inf_delay_ms(10);
		}
	}
}

中断函数:定时发送,接收处理

/********************************************************************* * 系统滴答中断函数 **********************************************************************/ void SysTick_Handler(void) { uint8_t ip[4] = {10,58,1,5}; uint8_t dst_ip[4] = {10,58,1,3}; char *str = "zhang ling"; Tick++; //if (Tick > 50 && Tick % 20 == 0) if (Tick > 50) { inf_w5100_write_data(SOCKET0,(uint8_t *)str,11,dst_ip,2000); } } /********************************************************************* * w5100中断处理 **********************************************************************/ void EXTI9_5_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line6) != RESET) { //清中断 EXTI_ClearITPendingBit(EXTI_Line6); //处理w5100中断 inf_w5100_irq_handler(&Msg,Buf0,Buf1,Buf2,Buf3); } } 



你可能感兴趣的:(STM32驱动W5100实现udp通信)