AT32F421专题---SPI连接CH395Q以太网芯片

【啰嗦2句】

      写作不是我主业,所以写得少,但是尽可能给满是雷同知识海洋里面添加一点独特的元素。

      本文是AT32F421C8T7芯片跟以太网芯片CH395Q的SPI对接与驱动。因部分属于商业内容,不便于公开,但也会把核心需要注意的内容讲出来。

【硬件简介】

    CH395Q是南京沁恒公司出的一款”以太网协议栈“芯片,内置10/100M PHY模块,并且自带TCP/IP协议栈,接口SPI。要说类似的芯片很多,比如W5500(WIZnet),ENC28J60,但是经过相当多实践之后,我发现他们各自的优缺点。

     ENC28J60:优点是便宜,到处有,他也集成了PHY,网上能找到大量有用的资料,我曾用STM32平台驱动过,很方便。缺点:没有协议栈,需要自行集成uIP或lwIP协议栈,导致固件复杂度提高,维护稍微麻烦些,抗干扰一般。

     W5500:优点是价格还能接受,内置的协议栈非常方便,印象中已经很方便于跟服务器TCP通信,但是DHCP没有内置,要自行补充。缺点倒是不多,最大毛病是容易受电源干扰,抗干扰不行。

     CH395Q:优点是集成了更多的协议栈,不用自己开发,普通的MCU就能驱动,难度也不大,厂家说明书也够用,内容不多,照着写个驱动没问题,抗干扰方面还勉强,厂家有技术支持,曾经跟他们联系过,工程师挺耐心的(反正比我有耐心),8个Socket可以灵活定制。缺点是特别贵,划不来,发热大,故障率较高,似乎对电源质量要求高,实际使用中遇到较多烧芯片现象。

      原理图:

原理图有不明白的地方,请参考官方文档,点击这里查看icon-default.png?t=N7T8http://wch.cn/download/CH395DS1_PDF.htmlCH395DS1.PDF 产品中心

【折腾什么呢】

      一个MCU+一个以太网模块,能干吗呢?其实能做的不能说特别多,但是做一个智能家居网关却相当合适。可以给结合433模块控制开关,或者自身整合了开关,或者远程给电脑开关机等。本文介绍如何开放一个TCP端口和一个UDP端口跟服务器通信,实现收发指令。

【通信架构】

    本文演示单片机跟上位机通信,采用UDP协议,定时2秒发消息(Hello文字)。同时上位机发送的内容,单片机接收后原文返回。上位机仅用普通UDP/TCP测试工具即可,类似工具很多可自行搜索。

    单片机端采用DHCP获取到IP为192.168.1.231,端口7777,上位机固定IP为:192.168.1.51,端口8888。

【关键代码开发】

    官方的案例代码可在沁恒官网找到。本文介绍重点驱动代码,并且TCP通信也能找到相应参考资料。

 CH395Q驱动:

文件名:ch395.c



#include "includes.h"	//整合了ch395q.h,mian.h等的头文件


u8 CH395Q_Ver=0;            //CH395Q模块的硬件版本号 


void CH395Q_SPI_NSS_H(void)
{
    CH395Q_SPI_CSN_PORT->scr = CH395Q_SPI_CSN_PIN;
}
void CH395Q_SPI_NSS_L(void)
{
    CH395Q_SPI_CSN_PORT->clr  = CH395Q_SPI_CSN_PIN;
}
void CH395Q_RST_H(void)
{
    CH395Q_RST_PORT->scr = CH395Q_RST_PIN;
}
void CH395Q_RST_L(void)
{
    CH395Q_RST_PORT->clr  = CH395Q_RST_PIN;
}
/*******************************************************************************
* 函数名  : CH395Q_GPIO_Configuration
* 描述    : CH395Q GPIO初始化配置
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void CH395Q_gpio_irq_init()
{
  exint_init_type exint_init_struct;

  crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOA, SCFG_PINS_SOURCE1);

  exint_default_para_init(&exint_init_struct);
  exint_init_struct.line_enable = TRUE;
  exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
  exint_init_struct.line_select = EXINT_LINE_1;
  exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
  exint_init(&exint_init_struct);

  nvic_priority_group_config(NVIC_PRIORITY_GROUP_2);
  nvic_irq_enable(EXINT1_0_IRQn, 1, 0);
	 
}


/*******************************************************************************
* 函数名  : CH395Q_GPIO_Configuration
* 描述    : CH395Q GPIO初始化配置
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void CH395Q_GPIO_Configuration(void)
{
	gpio_init_type gpio_initstructure;
  spi_init_type spi_init_struct;  
	
	
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE13, GPIO_MUX_0);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE14, GPIO_MUX_0);
  gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE15, GPIO_MUX_0);
	gpio_default_para_init(&gpio_initstructure);
	/* sck */
	gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_DOWN;
  gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pins = GPIO_PINS_13;
  gpio_init(GPIOB, &gpio_initstructure);
  /* miso */
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_DOWN;
  gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pins = GPIO_PINS_14;
  gpio_init(GPIOB, &gpio_initstructure);
  /* mosi */
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pins = GPIO_PINS_15;
  gpio_init(GPIOB, &gpio_initstructure);
	
	
 

  crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
  spi_default_para_init(&spi_init_struct);
  spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
  spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
  spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_16;
  spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
  spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
  spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
  spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
  spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
  spi_init(SPI2, &spi_init_struct);
  spi_enable(SPI2, TRUE);
	
	//CS
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pins           = CH395Q_SPI_CSN_PIN;
  gpio_init(CH395Q_SPI_CSN_PORT, &gpio_initstructure); 

  //RST
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pins           = CH395Q_RST_PIN;
  gpio_init(CH395Q_RST_PORT, &gpio_initstructure);
	//INT
	gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_mode = GPIO_MODE_INPUT;
  gpio_initstructure.gpio_pins = CH395Q_INT_PIN;
  gpio_initstructure.gpio_pull = GPIO_PULL_UP;  //GPIO_PULL_DOWN;//
  gpio_init(CH395Q_INT_PORT, &gpio_initstructure);
	
  CH395Q_CS_HIGH;
	CH395Q_gpio_irq_init();
	
}


/*******************************************************************************
* 函数名  : CH395Q_ReadWriteByte
* 描述    : SPI2发送1个字节数据
* 输入    : dat:待发送的数据
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
uint8_t CH395Q_ReadWriteByte(u8 TxData)
{
	  uint8_t i, temp;
    temp = 0;
    while (spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    {
        i++;
        if(i > 200)return 0;
    }			  
	  spi_i2s_data_transmit(SPI2, TxData); //通过外设SPIx发送一个数据
	  i=0;

	  while (spi_i2s_flag_get(SPI2, SPI_I2S_RDBF_FLAG) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
    {
        i++;
        if(i > 200)return 0;
    }
    temp = spi_i2s_data_receive(SPI2);	
		return temp;
}

/*******************************************************************************
* 函数名  : CH395Q_Hardware_Reset
* 描述    : 硬件复位CH395Q
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : CH395Q的复位引脚保持低电平至少500us以上,才能重围CH395Q
*******************************************************************************/
void CH395Q_Hardware_Reset(void)
{
	CH395Q_RST_LOW;//复位引脚拉低
	delay_ms(100);
	CH395Q_RST_HIGH;//复位引脚拉高
	delay_ms(200);
	//while((Read_CH395Q_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成
}
/*******************************************************************************
* 函数名  : CH395Q_CheckExist
* 描述    : 检查CH395Q是否存在,如果存在会返回按位取反的字节
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 
*******************************************************************************/
u8 CH395Q_CheckExist(void)
{
	unsigned char dat;

	CH395Q_CS_LOW;//置CH395Q的SCS为低电平
	CH395Q_ReadWriteByte(CMD11_CHECK_EXIST);//检查状态命令
	CH395Q_ReadWriteByte(0xA5);
	dat=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;//置CH395Q的SCS为高电平

	//Uart1Send(dat);
    if(dat==0x5A)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

/*******************************************************************************
* 函数名  : CH395Q_getVersion
* 描述    : 获取芯片版本号
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 芯片版本号大于0x44才支持获取全局中断数量,否则只支持0-3SOCKET
*******************************************************************************/
u8 	CH395Q_getVersion(void)
{
	unsigned char dat;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD01_GET_IC_VER);//命令
	dat=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;
	return dat;
}
/*******************************************************************************
* 函数名  : CH395Q_getPHYStatus
* 描述    : 获取物理链路连接状态,可以用于判断是否拔线
* 输入    : 无
* 输出    : 无
* 返回值  : 1--断开,2、4、8、10分别是10M全双工、10M半双工、100M全双工、100M半双工
* 说明    : 
*******************************************************************************/
u8 	CH395Q_getPHYStatus(void)
{
	unsigned char dat;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD01_GET_PHY_STATUS);//命令
	dat=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;
	return dat;
}
/*******************************************************************************
* 函数名  : CH395Q_getMAC
* 描述    : 获取MAC
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 存储在配置SP_MAC中
*******************************************************************************/
void CH395Q_getMAC(void)
{
  u8 SP_MAC[6];
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD06_GET_MAC_ADDR);//命令
	SP_MAC[0]=CH395Q_ReadWriteByte(0xFF);
	SP_MAC[1]=CH395Q_ReadWriteByte(0xFF);
	SP_MAC[2]=CH395Q_ReadWriteByte(0xFF);
	SP_MAC[3]=CH395Q_ReadWriteByte(0xFF);
	SP_MAC[4]=CH395Q_ReadWriteByte(0xFF);
	SP_MAC[5]=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;

}
/*******************************************************************************
* 函数名  : CH395Q_setDHCP
* 描述    : 设置DHCP开或关
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 启用DHCP必须在已经初始化了网卡协议栈(不是硬件初始化)才可以使用
*******************************************************************************/
void CH395Q_setDHCP(u8 onoff)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD10_DHCP_ENABLE);//命令
	CH395Q_ReadWriteByte(onoff);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_InitNet
* 描述    : 启动网络协议栈
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 初始化了网卡协议栈
*******************************************************************************/
u8 CH395Q_InitNet(void)
{
	u8 status=0;
	u8 i=0;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD0W_INIT_CH395);//命令
	CH395Q_CS_HIGH;
	while(1)
  {
    delay_ms(10);
		CH395Q_CS_LOW;
		CH395Q_ReadWriteByte(CMD01_GET_CMD_STATUS);//命令
		status = CH395Q_ReadWriteByte(0xFF);		  /* 不能过于频繁查询*/
		CH395Q_CS_HIGH;                               /* 延时查询,建议2MS以上*/
                                             
    if(status !=CH395_ERR_BUSY)break;                 /* 如果CH395芯片返回忙状态*/
    if(i++ > 200)return CH395_ERR_UNKNOW;        /* 超时退出,本函数需要500MS以上执行完毕 */
  }
	return CMD_ERR_SUCCESS;
}
/*******************************************************************************
* 函数名  : CH395Q_getDHCPStatus
* 描述    : 获取DHCP状态,一般在DHCP成功中断后读取
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
u8 CH395Q_getDHCPStatus(void)
{
	unsigned char dat;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD01_GET_DHCP_STATUS);//命令
	dat=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;
	return dat;
}

/*******************************************************************************
* 函数名  : CH395Q_getIPInfo
* 描述    : DHCP时,获取IP信息
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 4字节IP地址、4字节网关IP、4字节子网掩码、4字节 DNS1(主 DNS)、4字节DNS2(次DNS)
*******************************************************************************/
u8 CH395Q_getIPInfo(void)
{
	u8 ipinfo[20];
	u8 i=0;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD014_GET_IP_INF);//命令
	for(i=0;i<20;i++)
	{
		ipinfo[i]=CH395Q_ReadWriteByte(0xFF);
	}
	
	CH395Q_CS_HIGH;
	return 0;
}
/*******************************************************************************
* 函数名  : CH395Q_getGlobIntStatusAll
* 描述    : 获取全局中断状态,收到此命令CH395自动取消中断,0x44及以上版本使用
* 输入    : 无
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
u16 CH395Q_getGlobIntStatusAll(void)
{
	unsigned int dat;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD02_GET_GLOB_INT_STATUS_ALL);//命令
	delay_us(2);
	dat=CH395Q_ReadWriteByte(0xFF);
	dat=((u16)CH395Q_ReadWriteByte(0xFF)<<8) | dat;
	CH395Q_CS_HIGH;
	return dat;
}
/*******************************************************************************
* 函数名  : CH395Q_setSocketDesIP
* 描述    : 设置Socket目的端口IP
* 输入    : socket--socket号,ipaddr--ip地址
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_setSocketDesIP(u8 socket,u8 *ipaddr)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD50_SET_IP_ADDR_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_ReadWriteByte(*ipaddr++);
	CH395Q_ReadWriteByte(*ipaddr++);
	CH395Q_ReadWriteByte(*ipaddr++);
	CH395Q_ReadWriteByte(*ipaddr++);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_setSocketProtType
* 描述    : Socket协议类型
* 输入    : socket--socket号,type--类型(TCP,UDP,MAC,IP等)
* 输出    : 无
* 返回值  : 
* 说明    : 此命令必须在CMD_OPEN_SOCKET_SN之前执行
*******************************************************************************/
void CH395Q_setSocketProtType(u8 socket,u8 type)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD20_SET_PROTO_TYPE_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_ReadWriteByte(type);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_setSocketDesPort
* 描述    : 设置socket n的目的端口号
* 输入    : socket--socket号,port--端口
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_setSocketDesPort(u8 socket,u16 port)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD30_SET_DES_PORT_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_ReadWriteByte(port);
	CH395Q_ReadWriteByte(port>>8);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_setSocketSrcPort
* 描述    : 设置socket n的源端口号
* 输入    : socket--socket号,port--端口
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_setSocketSrcPort(u8 socket,u16 port)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD30_SET_SOUR_PORT_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_ReadWriteByte(port);
	CH395Q_ReadWriteByte(port>>8);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_SendData
* 描述    : 向发送缓冲区写数据
* 输入    : socket--端口,buf--数据,length--长度
* 输出    : 无
* 返回值  : 
* 说明    : 在SINT_STAT_SENBUF_FREE之前,不得向该 Socket发送缓冲区再次写入数据
*******************************************************************************/
void CH395Q_SendData(u8 socket,u8 *buf,u16 length)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD30_WRITE_SEND_BUF_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_ReadWriteByte(length);
	CH395Q_ReadWriteByte(length>>8);
	while(length--)
	{
	    CH395Q_ReadWriteByte(*buf++);
	}
	CH395Q_CS_HIGH;
}

/*******************************************************************************
* 函数名  : CH395Q_getDataLength
* 描述    : 获取缓冲区数据长度
* 输入    : socket--端口,
* 输出    : 无
* 返回值  : 长度
* 说明    : 
*******************************************************************************/
u16 CH395Q_getDataLength(u8 socket)
{
	unsigned int dat;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD12_GET_RECV_LEN_SN);//命令
	CH395Q_ReadWriteByte(socket);
	dat=CH395Q_ReadWriteByte(0xFF);
	dat=((u16)CH395Q_ReadWriteByte(0xFF)<<8) | dat;
	CH395Q_CS_HIGH;
	return dat;
}
/*******************************************************************************
* 函数名  : CH395Q_ClearRecvBuf
* 描述    : 清除接收缓冲区
* 输入    : enable--1开,0关
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_ClearRecvBuf(u8 socket)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD10_CLEAR_RECV_BUF_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_RevData
* 描述    : 获取接收缓冲区长度
* 输入    : socket--端口,buf--数据,length--长度
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_RevData(u8 socket,u8 *buf,u16 length)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD30_READ_RECV_BUF_SN);//命令
	CH395Q_ReadWriteByte(socket);
	CH395Q_ReadWriteByte(length);
	CH395Q_ReadWriteByte(length>>8);
	while(length--)
	{
	    *buf=CH395Q_ReadWriteByte(0xFF);
		buf++;
	}
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_getSocketStatus
* 描述    : 获取Socket状态,开或者关
* 输入    : socket--端口,info
* 输出    : 无
* 返回值  : 第一字节0x05开,0x00关,第二字节仅在TCP模式,并且打开时有意义
* 说明    : 
*******************************************************************************/
void CH395Q_getSocketStatus(u8 socket,u8 *info)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD12_GET_SOCKET_STATUS_SN);//命令
	CH395Q_ReadWriteByte(socket);
	*info++=CH395Q_ReadWriteByte(0xFF);
	*info++=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_OpenSocket
* 描述    : 打开socket,此命令需要等待执行成功
* 输入    : socket--端口,
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_OpenSocket(u8 socket)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD1W_OPEN_SOCKET_SN);//命令
	CH395Q_ReadWriteByte(socket);
	//做个标记,用于判断是否打开成功

	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_CloseSocket
* 描述    : 关闭socket,
* 输入    : socket--端口,
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void CH395Q_CloseSocket(u8 socket)
{
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD1W_CLOSE_SOCKET_SN);//命令
	CH395Q_ReadWriteByte(socket);
	//做个标记,用于判断是否成功
	
	CH395Q_CS_HIGH;
}
/*******************************************************************************
* 函数名  : CH395Q_getSocketInt
* 描述    : 获取socket n的中断状态
* 输入    : socket--端口,
* 输出    : 无
* 返回值  : 长度
* 说明    : 
*******************************************************************************/
u8 CH395Q_getSocketInt(u8 socket)
{
	unsigned char dat;
	CH395Q_CS_LOW;
	CH395Q_ReadWriteByte(CMD11_GET_INT_STATUS_SN);//命令
	CH395Q_ReadWriteByte(socket);
	dat=CH395Q_ReadWriteByte(0xFF);
	CH395Q_CS_HIGH;
	return dat;
}
/*******************************************************************************
* 函数名  : CH395Q_UDPSendTo
* 描述    : UDP向指定的IP和端口发送数据
* 输入    : socket--端口,buf--数据,length--长度
* 输出    : 无
* 返回值  : 
* 说明    : 在SINT_STAT_SENBUF_FREE之前,不得向该 Socket发送缓冲区再次写入数据
*******************************************************************************/
void CH395Q_UDPSendTo(u8 socket,u8 *buf,u16 length,u8 *ip,u16 port)
{
	CH395Q_setSocketDesIP(socket,ip);
	CH395Q_setSocketDesPort(socket,port);
	CH395Q_SendData(socket,buf,length);
}
/*******************************************************************************
* 函数名  : CH395Q_Init
* 描述    : 初始化CH395Q寄存器函数
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 在使用CH395Q之前,先对CH395Q初始化
*******************************************************************************/
void CH395Q_Init(void)
{
	//u8 value=0;
	if(CH395Q_CheckExist()==1)
	{
		//版本号
		CH395Q_Ver=CH395Q_getVersion();
		
		//MAC
		//CH395Q_getMAC();
		//注意:如果是DHCP,则初始化协议栈之后打开,否则在初始化之前执行IP赋值
		//初始化网卡协议栈
		NetLinkFlag=0;
		
		if(CH395Q_InitNet()==CMD_ERR_SUCCESS)	//初始化协议栈成功
		{
			//DHCP
			if(CH395Q_getPHYStatus()!=PHY_DISCONN)
				{
				  CH395Q_setDHCP(1);	   //启动DHCP,每隔16秒会探测一次,直到获得IP
				}
			
		}
	}
	
}
/*******************************************************************************
* 函数名  : Socket_Init
* 描述    : 初始化S0端口,用于内网配置服务
* 输入    : socket:待初始化的端口
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void Socket0_Init(void)
{

	u8 n=0;
	u8 status=0;
	CH395Q_CloseSocket(0);
	//这里初始化0端口为UDP服务端,用于功能控制和配置服务,芯片默认发送缓存2K,接收缓存4K        
  CH395Q_setSocketProtType(0,PROTO_TYPE_UDP);       //设置socket 0协议类型 
	CH395Q_setSocketDesIP(0,LastS0RemoteIP);            // 设置socket 0目标IP地址,//注意:作为服务器UDP,必须设0xFFFFFFFF的目标IP
  CH395Q_setSocketDesPort(0,LastS0RemotePort);      // 设置socket 0目的端口 
  CH395Q_setSocketSrcPort(0,7777);          // 设置socket 0源端口 
  CH395Q_OpenSocket(0);					  //打开socket 0 ,UDP没有连接,直接可以判断成功
	
	while(n<10)
	{
		delay_ms(10);
		CH395Q_CS_LOW;
		CH395Q_ReadWriteByte(CMD01_GET_CMD_STATUS);//命令
		status = CH395Q_ReadWriteByte(0xFF);		  // 不能过于频繁查询*/
		CH395Q_CS_HIGH;                               // 延时查询,建议2MS以上*/                                      
    if(status !=CH395_ERR_BUSY)	  // 如果CH395芯片返回忙状态*/
		{
			Socket0_Status=SOCKET_OPEN;
			break;                 
		}
    if(n++ >=10)
		{
			Socket0_Status=SOCKET_CLOSED;
		}
	}
	status=0;

}
/*******************************************************************************
* 函数名  : CH395Q_Interrupt_Process
* 描述    : CH395Q中断处理程序框架
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void CH395Q_Interrupt_Process(void)
{
	u16 IRQValue=0;
	u8 value=0;
	//u8 temp[31];
	IRQValue=CH395Q_getGlobIntStatusAll();
	if(IRQValue&GINT_STAT_UNREACH)	 //不可达中断
	{


	}
	if(IRQValue&GINT_STAT_IP_CONFLI)	 //IP冲突中断
	{
     if(NetLinkFlag==1)
		 {			 
		    
		 }
	}
	if(IRQValue&GINT_STAT_PHY_CHANGE)	 //物理连接状态改变
	{
		value=CH395Q_getPHYStatus();
		if(value!=PHY_DISCONN)   //如果网卡已经连接
		{
			NetLinkFlag=1;
			CH395Q_setDHCP(1);
			
		}
		else
		{
			NetLinkFlag=0;
			CH395Q_setDHCP(0);//关闭DHCP,不然反应很慢
		}
	}
	if(IRQValue&GINT_STAT_DHCP)	 //DHCP和PPPOE中断
	{
		if(CH395Q_getDHCPStatus()==0)		//DHCP成功
		{
			CH395Q_getIPInfo();			//获取IP信息
			Socket0_Status=SOCKET_CLOSED;
		}
	}
	if(IRQValue&GINT_STAT_SOCK0)	 //Socket0中断
	{
		Socket0_Handler();
	}
	if(IRQValue&GINT_STAT_SOCK1)	 //Socket1中断
	{
		
	}


}




   文件名:ch395.h


#ifndef	_CH395Q_H_
#define	_CH395Q_H_
//CH395Q有1个通用寄存器,8个单独Socket寄存器,以及TX/RX内存
/* ********************************************************************************************************************* */
/* 命令代码 */
/* 一个命令操作顺序包含:
          一个命令码(对于串口方式,命令码之前还需要两个同步码),
          若干个输入数据(可以是0个),
          若干个输出数据(可以是0个)
       命令码起名规则: CMDxy_NAME
       其中的x和y都是数字, x说明最少输入数据个数(字节数), y说明最少输出数据个数(字节数), y如果是W表示需要等待命令执行成功
       有些命令能够实现0到多个字节的数据块读写, 数据块本身的字节数未包含在上述x或y之内 */
/* ********************************************************************************************************************* */
#define CMD01_GET_IC_VER                          0x01                          /* 获取芯片以及固件版本号 */
/* 输出: 版本号( 位7为0, 位6为1, 位5~位0为版本号 ) */                           
/*       CH3395返回版本号的值为041H即版本号为01H */                             
                                                                                
#define CMD31_SET_BAUDRATE                        0x02                          /* 串口方式: 设置串口通讯波特率(上电或者复位后的默认波特率为9600bps */
/* 输入: 3字节波特率,第字节在前 */                                             
/* 输出: 操作状态( CMD_RET_SUCCESS, 其它值说明操作未完成 ) */                   
                                                                                
#define CMD00_ENTER_SLEEP                         0x03                          /* 进入睡眠状态 */
                                                                                
#define CMD00_RESET_ALL                           0x05                          /* 执行硬件复位 */
                                                                                
#define CMD11_CHECK_EXIST                         0x06                          /* 测试通讯接口以及工作状态 */
/* 输入: 任意数据 */                                                            
/* 输出: 输入数据的按位取反 */                                                  

#define CMD02_GET_GLOB_INT_STATUS_ALL             0x19                          /* 获取全局中断状态,V44版本以后的程序由于增加了socket数量需要用此命令获取全部的中断 */
/*输出:全局中断状态,参考全局中断状态定义 */
                                                                                
#define CMD10_SET_PHY                             0x20                          /* 设置PHY,默认为Auto,自动协商 */
/* 输入:PHY参数,参考PHY参数定义 */                                            
                                                                                
#define CMD60_SET_MAC_ADDR                        0x21                          /* 设置MAC地址 必须在CMD00H_INIT_CH395之前设置完毕 */
/* 输入:6字节的MAC地址 */                                                      
                                                                                
#define CMD40_SET_IP_ADDR                         0x22                          /* 设置IP地址 必须在CMD00H_INIT_CH395之前设置完毕 */
/* 输入:4字节的IP地址 */                                                       
                                                                                
#define CMD40_SET_GWIP_ADDR                       0x23                          /* 设置网关IP地址 必须在CMD00H_INIT_CH395之前设置完毕 */
/* 输入:4字节的网关IP地址 */                                                   
                                                                                
#define CMD40_SET_MASK_ADDR                       0x24                          /* 设置子网掩码, 必须在CMD00H_INIT_CH395之前设置完毕 */
/* 输入:4字节的子网掩码 */                                                     
                                                                                
#define CMD90_SET_MAC_FILT                        0x25                          /* 设置MAC过滤 可以进行广播,多播等过滤 */
/* 输入:9字节参数,第1字节为过滤类型,参考过滤类型定义,*/
/*      第2至第5字节为HASH0,第6至第9字节为HASH1 */

#define CMD01_GET_PHY_STATUS                      0x26                          /* 获取PHY当前状态,如断开连接,10/100M FULL/HALF */
/* 输出:当前PHY状态,状态定义请参考PHY参数定义 */                               
                                                                                
#define CMD0W_INIT_CH395                          0x27                          /* 初始化CH395 */
/* 此命令执行时间大约200MS,需要等待此命令执行成功,才可以发下一条命令 */         
                                                                                
#define CMD08_GET_UNREACH_IPPORT                  0x28                          /* 获取不可达信息 */
/* 输出:8字节,第1字节为不可达类型,参考不可达类型定义 */
/*         第2字节协议不可达协议码 */
/*         第3,4字节不可达端口 */
/*         第5-8字不可达IP */

#define CMD01_GET_GLOB_INT_STATUS                 0x29                          /* 获取全局中断状态,最大值为1S,不可以设置为0 */
/* 输出:全局中断状态,参考全局中断状态定义 */                                   
                                                                                
#define CMD10_SET_RETRAN_COUNT                    0x2A                          /* 重试次数,仅在TCP模式下有效 */
/* 输入:重试次数 */                                                             
                                                                                
#define CMD20_SET_RETRAN_PERIOD                   0x2B                          /* 重试周期,最大值为20,仅在TCP模式下有效,不可以设置为0 */
/* 输入:重试周期 */                                                             
                                                                                
#define CMD01_GET_CMD_STATUS                      0x2C                          /* 获取命令执行状态 */
/* 输出:命令执行状态,参考命令执行状态定义 */                                   
                                                                                
#define CMD06_GET_REMOT_IPP_SN                    0x2D                          /* 获取远端的端口以及IP地址,该命令在TCP服务器模式下使用 */
/* 输出:6字节,第1-4字节为远端的IP地址,第5-6字节为远端的端口号 */               
                                                                                
#define CMD10_CLEAR_RECV_BUF_SN                   0x2E                          /* 清除接收缓冲区  */
/* 输入:第1字节为socket的索引值 */                                              
                                                                                
#define CMD12_GET_SOCKET_STATUS_SN                0x2F                          /* 获取socket n状态 */
/* 输入:socket的索引值,*/                                                      
/* 输出:第1字节:socket n 打开或者关闭                                          
         第2字节:TCP状态,仅在TCP模式且第1字节为打开状态下有意义 */              
                                                                                
#define CMD11_GET_INT_STATUS_SN                   0x30                          /* 获取socket n的中断状态 */
/* 输入: socket的索引值*/                                                       
/* 输出:全局中断状态,参考全局中断状态定义 */                                   
                                                                                
#define CMD50_SET_IP_ADDR_SN                      0x31                          /* 设置socket n的目的IP地址 */
/* 输入:第1字节为socket的索引值,第2至5字节为IP地址 */                           
                                                                                
#define CMD30_SET_DES_PORT_SN                     0x32                          /* 设置socket n的目的端口 */
/* 输入:第1字节为socket的索引值,第2至3字节为目的端口 */                         
                                                                                
#define CMD30_SET_SOUR_PORT_SN                    0x33                           /* 设置socket n的源端口 */
/* 输入:第1字节为socket的索引值,第2至3字节为源端口 */                           
                                                                                
#define CMD20_SET_PROTO_TYPE_SN                   0x34                          /* 设置socket n的协议类型 */
/* 输入:第1字节为socket的索引值,第2协议类型,参考协议类型定义 */                
                                                                                
#define CMD1W_OPEN_SOCKET_SN                      0x35                          /* 打开socket n */
/* 输入:第1字节为socket的索引值,此命令需要等待命令执行成功 */                  
                                                                                
#define CMD1W_TCP_LISTEN_SN                       0x36                          /* socket n监听,收到此命令,socket n进入服务器模式,仅对TCP模式有效 */
/* 输入:第1字节为socket的索引值,此命令需要等待命令执行成功 */                  
                                                                                
#define CMD1W_TCP_CONNECT_SN                      0x37                          /* socket n连接,收到此命令,socket n进入客户端模式,仅对TCP模式有效 */
/* 输入:第1字节为socket的索引值,此命令需要等待命令执行成功 */                  
                                                                                
#define CMD1W_TCP_DISNCONNECT_SN                  0x38                          /* socket n断开连接,收到此命令,socket n断开已有连接,仅对TCP模式有效 */
/* 输入:第1字节为socket的索引值,此命令需要等待命令执行成功 */                  
                                                                                
#define CMD30_WRITE_SEND_BUF_SN                   0x39                          /* 向socket n缓冲区写入数据 */
/* 输入:第1字节为socket的索引值,第2至3字节为长度 */                             
                                                                                
#define CMD12_GET_RECV_LEN_SN                     0x3B                          /* 获取socket n接收数据的长度 */
/* 输入:socket的索引值 */                                                        
/* 输出:2字节的接收长度 */                                                       
                                                                                
#define CMD30_READ_RECV_BUF_SN                    0x3C                          /* 读取socket n接收缓冲区数据 */
/* 输入:第1字节为socket的索引值,第2至3字节为读取的长度n,低位在前 */            
/* 输出:n个数据 */                                                               
                                                                                
#define CMD1W_CLOSE_SOCKET_SN                     0x3D                          /* 关闭socket n */
/* 输入:socket的索引值 */                                                        
                                                                                
#define CMD20_SET_IPRAW_PRO_SN                    0x3E                          /* 在IP RAW下,设置socket n的IP包协议类型 */
/* 输入:第1字节为socket的索引值,第2字节为IP RAW协议类型 */                      
                                                                                
#define CMD01_PING_ENABLE                         0x3F                          /* 开启/关闭PING */
/* 输入:1字节,0为关闭PING,1为开启PING,默认开启 */                            
                                                                                
#define CMD06_GET_MAC_ADDR                        0x40                          /* 获取MAC地址 */
/* 输出:6字节的MAC地址 */                                                      

#define CMD10_DHCP_ENABLE                         0x41                          /* DHCP使能 */
/* 输入:1字节,1启动DHCP,0关闭DHCP */                                                                              
#define CMD01_GET_DHCP_STATUS                     0x42                          /* 获取DHCP状态 */
/* 输出: 1字节状态码,0表示成功,其他值失败 */                                                                               
                                                                             
#define CMD014_GET_IP_INF                         0x43                          /* IP,子网掩码,网关 */
/* 输出:20字节,分别为4字节IP,4字节网关,4字节掩码,4字节的DNS1,4字节的DNS2 */

#define CMD00_PPPOE_SET_USER_NAME                 0x44                          /* 设置PPPOE用户名 */
/* 输入:N个字节,0为结束符 */                                                       
                                                                                
#define CMD00_PPPOE_SET_PASSWORD                  0x45                          /* 设置密码 */
/* 输入:N个字节,0为结束符 */                                                       
                                                                                
#define CMD10_PPPOE_ENABLE                        0x46                          /* PPPOE使能 */
/* 输入:1字节,1启动PPPOE,0关闭PPPOE */                                             
                                                                                
#define CMD01_GET_PPPOE_STATUS                    0x47                          /* 获取pppoe状态 */
/* 输出: 1字节状态码,0表示成功,其他值失败 */                                         
                                                                                
#define CMD20_SET_TCP_MSS                         0x50                          /* 设置TCP MSS */
/* 输入:TCP MSS,低位在前 */

#define CMD20_SET_TTL                             0x51                          /* 设置TTL,TTL最大值为128 */
/* 输入:第1字节为socket的索引值,第2字节为TTL值,最大为128 */

#define CMD30_SET_RECV_BUF                        0x52                          /* 设置SOCKET接收缓冲区 */
/* 输入:第1字节为socket的索引值,第2字节为起始块索引,第3字节为块数 */          
                                                                                
#define CMD30_SET_SEND_BUF                        0x53                          /* 设置SOCKET发送缓冲区 */
/* 输入:第1字节为socket的索引值,第2字节为起始块索引,第3字节为块数 */          
                                                                                
#define CMD10_SET_MAC_RECV_BUF                    0x54                          /* 设置MAC接收缓冲区 */
/* 输入:输入1字节的MAC接收缓冲区的大小,16字节为单位 */                         
                                                                                
#define CMD40_SET_FUN_PARA                        0x55                          /* 设置功能参数 */
/* 输入:4字节的启动参数 */

#define CMD40_SET_KEEP_LIVE_IDLE                  0x56                    /* 设置KEEPLIVE空闲 */
/*输入:4字节的保活定时器空闲时间参数,低位在前 */

#define CMD40_SET_KEEP_LIVE_INTVL                 0x57                    /* 设置间隔时间 */
/*输入:4字节的保活定时器超时间隔,低位在前 */

#define CMD10_SET_KEEP_LIVE_CNT                   0x58                    /* 重试次数 */
/*输入:1字节重试次数 */

#define CMD20_SET_KEEP_LIVE_SN                    0X59                    /* 设置socket nkeeplive功能*/
/*输入:1个字节Socket索引,1个字节设置 */

#define CMD00_EEPROM_ERASE                        0xE9                          /* 擦除EEPROM*/
                                                                                
#define CMD30_EEPROM_WRITE                        0xEA                          /* 写EEPROM */
/* 输入:2字节地址,1字节长度,长度必须小于64字节 */                             
                                                                                
#define CMD30_EEPROM_READ                         0xEB                          /* 读EEPROM */
/* 输入:2字节地址,1字节长度,长度必须小于64字节 */                             
                                                                                
#define CMD10_READ_GPIO_REG                       0xEC                          /* 读GPIO寄存器 */
/* 输入:第1个字节为REG地址,关于地址请参考相关宏定义 */                           
                                                                              
#define CMD20_WRITE_GPIO_REG                      0xED                          /* 写GPIO寄存器 */
/* 输入:第1个字节为REG地址,关于地址请参考相关宏定义 */
/*       第2个字节为数据 */
/* 协议类型 */
#define PROTO_TYPE_IP_RAW                         0                             /* IP层原始数据 */
#define PROTO_TYPE_MAC_RAW                        1                             /* MAC层原始数据 */
#define PROTO_TYPE_UDP                            2                             /* UDP协议类型 */
#define PROTO_TYPE_TCP                            3                             /* TCP协议类型 */
                                                                                
/* PHY 命令参数/状态 */                                                         
#define PHY_DISCONN                               (1<<0)                        /* PHY断开 */
#define PHY_10M_FLL                               (1<<1)                        /* 10M全双工 */
#define PHY_10M_HALF                              (1<<2)                        /* 10M半双工 */
#define PHY_100M_FLL                              (1<<3)                        /* 100M全双工 */
#define PHY_100M_HALF                             (1<<4)                        /* 100M半双工 */
#define PHY_AUTO                                  (1<<5)                        /* PHY自动模式,CMD10H_SET_PHY */
                                                                                
/*CH395 MAC过滤*/                                                               
#define MAC_FILT_RECV_BORADPKT                    (1<<0)                        /* 使能接收广播包 */
#define MAC_FILT_RECV_ALL                         (1<<1)                        /* 使能接收所有数据包 */
#define MAC_FILT_RECV_MULTIPKT                    (1<<2)                        /* 使能接收多播包 */
#define MAC_FILT_RECV_ENABLE                      (1<<3)                        /* 使能接收 */
#define MAC_FILT_SEND_ENABLE                      (1<<4)                        /* 使能发送 */
                                                                                
/* 中断状态 */                                                                  
/* 以下为GLOB_INT会产生的状态 */                                                
#define GINT_STAT_UNREACH                         (1<<0)                        /* 不可达中断 */
#define GINT_STAT_IP_CONFLI                       (1<<1)                        /* IP冲突 */
#define GINT_STAT_PHY_CHANGE                      (1<<2)                        /* PHY状态改变 */
#define GINT_STAT_DHCP                            (1<<3)                        /* PHY状态改变 */
#define GINT_STAT_SOCK0                           (1<<4)                        /* socket0 产生中断 */
#define GINT_STAT_SOCK1                           (1<<5)                        /* socket1 产生中断 */
#define GINT_STAT_SOCK2                           (1<<6)                        /* socket2 产生中断 */
#define GINT_STAT_SOCK3                           (1<<7)                        /* socket3 产生中断 */
#define GINT_STAT_SOCK4                           (1<<8)                        /* scoket4 产生中断 */
#define GINT_STAT_SOCK5                           (1<<9)                        /* scoket5 产生中断 */
#define GINT_STAT_SOCK6                           (1<<10)                       /* scoket6 产生中断 */
#define GINT_STAT_SOCK7                           (1<<11)                       /* scoket7 产生中断 */
                                                                                
/*以下为Sn_INT会产生的状态*/                                                    
#define SINT_STAT_SENBUF_FREE                     (1<<0)                        /* 发送缓冲区空闲 */
#define SINT_STAT_SEND_OK                         (1<<1)                        /* 发送成功 */
#define SINT_STAT_RECV                            (1<<2)                        /* socket端口接收到数据或者接收缓冲区不为空 */
#define SINT_STAT_CONNECT                         (1<<3)                        /* 连接成功,TCP模式下产生此中断 */
#define SINT_STAT_DISCONNECT                      (1<<4)                        /* 连接断开,TCP模式下产生此中断 */
#define SINT_STAT_TIM_OUT                         (1<<6)                        /* ARP和TCP模式下会发生此中断 */
                                                                                
/* 获取命令状态 */                                                              
#define CMD_ERR_SUCCESS                           0x00                          /* 命令操作成功 */
#define CMD_RET_ABORT                             0x5F                          /* 命令操作失败 */
#define CH395_ERR_BUSY                            0x10                          /* 忙状态,表示当前正在执行命令 */
#define CH395_ERR_MEM                             0x11                          /* 内存错误 */
#define CH395_ERR_BUF                             0x12                          /* 缓冲区错误 */
#define CH395_ERR_TIMEOUT                         0x13                          /* 超时 */
#define CH395_ERR_RTE                             0x14                          /* 路由错误*/
#define CH395_ERR_ABRT                            0x15                          /* 连接停止*/
#define CH395_ERR_RST                             0x16                          /* 连接复位 */
#define CH395_ERR_CLSD                            0x17                          /* 连接关闭/socket 在关闭状态 */
#define CH395_ERR_CONN                            0x18                          /* 无连接 */
#define CH395_ERR_VAL                             0x19                          /* 错误的值 */
#define CH395_ERR_ARG                             0x1a                          /* 错误的参数 */
#define CH395_ERR_USE                             0x1b                          /* 已经被使用 */
#define CH395_ERR_IF                              0x1c                          /* MAC错误  */
#define CH395_ERR_ISCONN                          0x1d                          /* 已连接 */
#define CH395_ERR_OPEN                            0X20                          /* 已经打开 */
#define CH395_ERR_UNKNOW                          0xFA                          /* 未知错误 */

/* PPP状态 */
#define CH395_PPP_SUCCESS                         0                             /* 成功 */
#define CH395_PPPERR_PARM                         1                             /* 无效参数 */
#define CH395_PPPERR_OPEN                         2                             /* 无法打开PPP会话 */
#define CH395_PPPERR_DEVICE                       3                             /* 无效的PPP设备 */
#define CH395_PPPERR_ALLOC                        4                             /* 资源分配失败 */
#define CH395_PPPERR_USER                         5                             /* 用户中断 */
#define CH395_PPPERR_CONNECT                      6                             /* 连接断开 */
#define CH395_PPPERR_AUTHFAIL                     7                             /* 挑战鉴别失败 */
#define CH395_PPPERR_PROTOCOL                     8                             /* 握手协议失败 */
#define CH395_PPPERR_TIME_OUT                     9                             /* 超时失败 */
#define CH395_PPPERR_CLOSE                        10                            /* 关闭失败 */

/* 不可达代码 */
#define UNREACH_CODE_HOST                         0                             /* 主机不可达 */
#define UNREACH_CODE_NET                          1                             /* 网络不可达 */
#define UNREACH_CODE_PROTOCOL                     2                             /* 协议不可达 */
#define UNREACH_CODE_PROT                         3                             /* 端口不可达 */
/*其他值请参考RFC792文档*/                                                      
                                                                                
/* 命令包头 */                                                                  
#define SER_SYNC_CODE1                            0x57                          /* 串口命令同步码1 */
#define SER_SYNC_CODE2                            0xAB                          /* 串口命令同步码2 */
                                                  
/* TCP状态 */                                     
#define TCP_CLOSED                                0                     
#define TCP_LISTEN                                1
#define TCP_SYN_SENT                              2
#define TCP_SYN_RCVD                              3
#define TCP_ESTABLISHED                           4
#define TCP_FIN_WAIT_1                            5
#define TCP_FIN_WAIT_2                            6
#define TCP_CLOSE_WAIT                            7
#define TCP_CLOSING                               8
#define TCP_LAST_ACK                              9
#define TCP_TIME_WAIT                             10

/* GPIO寄存器地址 */
#define GPIO_DIR_REG                              0x80                          /* 寄存器方向寄存器,1:输出;0:输入 */
#define GPIO_IN_REG                               0x81                          /* GPIO输入寄存器 */
#define GPIO_OUT_REG                              0x82                          /* GPIO输出寄存器 */
#define GPIO_CLR_REG                              0x83                          /* GPIO输出清除: 0=keep, 1=clear */
#define GPIO_PU_REG                               0x84                          /* GPIO上拉使能寄存器 */
#define GPIO_PD_REG                               0x85                          /* GPIO下拉使能寄存器 */

/* 功能参数 */
#define FUN_PARA_FLAG_TCP_SERVER                  (1<<1)                        /* tcp server 多连接模式标志,0X44版本及以后支持 */
#define FUN_PARA_FLAG_LOW_PWR                     (1<<2)                        /* 低耗能模式 */
#define SOCK_CTRL_FLAG_SOCKET_CLOSE               (1<<3)                        /* CH395不主动关闭Socket */
#define SOCK_DISABLE_SEND_OK_INT                  (1<<4)                        /* send ok中断控制位,为1表示关闭send ok中断 */

#define SOCKET_CLOSED								0x00					   //Socket状态关闭
#define SOCKET_OPEN									0x05						//Socket状态打开



/***************----- CH395Q GPIO定义 -----***************/
#define CH395Q_SPI_CSN_PIN       GPIO_PINS_12
#define CH395Q_SPI_CSN_PORT      GPIOB
#define CH395Q_SPI_CSN           CRM_GPIOB_PERIPH_CLOCK

#define CH395Q_SPI_CLK_PIN       GPIO_PINS_13
#define CH395Q_SPI_CLK_PORT      GPIOB
#define CH395Q_SPI_CLK           CRM_GPIOB_PERIPH_CLOCK

#define CH395Q_SPI_MISO_PIN      GPIO_PINS_14
#define CH395Q_SPI_MISO_PORT     GPIOB
#define CH395Q_SPI_MISO          CRM_GPIOB_PERIPH_CLOCK

#define CH395Q_SPI_MOSI_PIN      GPIO_PINS_15
#define CH395Q_SPI_MOSI_PORT     GPIOB
#define CH395Q_SPI_MOSI          CRM_GPIOB_PERIPH_CLOCK


//RST
#define CH395Q_RST_PIN           GPIO_PINS_11
#define CH395Q_RST_PORT          GPIOA
#define CH395Q_RST               CRM_GPIOA_PERIPH_CLOCK
//INT
#define CH395Q_INT_PIN           GPIO_PINS_12
#define CH395Q_INT_PORT          GPIOA
#define CH395Q_INT               CRM_GPIOA_PERIPH_CLOCK

#define CH395Q_CS_HIGH   			   CH395Q_SPI_CSN_PORT->scr = CH395Q_SPI_CSN_PIN
#define CH395Q_CS_LOW    			   CH395Q_SPI_CSN_PORT->clr  = CH395Q_SPI_CSN_PIN
#define CH395Q_RST_HIGH   			 CH395Q_RST_PORT->scr = CH395Q_RST_PIN 
#define CH395Q_RST_LOW    			 CH395Q_RST_PORT->clr  = CH395Q_RST_PIN



extern u8 CH395Q_Ver;

void CH395Q_GPIO_Configuration(void);//CH395Q GPIO初始化配置
u8 CH395Q_ReadWriteByte(u8 TxData);
void CH395Q_Hardware_Reset(void);//硬件复位CH395Q
unsigned char CH395Q_CheckExist(void);
u8 	CH395Q_getVersion(void);
u8 	CH395Q_getPHYStatus(void);
void CH395Q_getMAC(void);
u8 CH395Q_getDHCPStatus(void);
u8 CH395Q_getIPInfo(void);
void CH395Q_getRemoteIPP(u8 socket,u8 *info);
void CH395Q_getUnreachIPPT(u8 *info);
u16 CH395Q_getDataLength(u8 socket);
void CH395Q_ClearRecvBuf(u8 socket);
void CH395Q_SendData(u8 socket,u8 *buf,u16 length);
void CH395Q_RevData(u8 socket,u8 *buf,u16 length);
u8 CH395Q_getSocketInt(u8 socket);
void CH395Q_UDPSendTo(u8 socket,u8 *buf,u16 length,u8 *ip,u16 port);
void CH395Q_TCPDisconnect(u8 socket);
void CH395Q_CloseSocket(u8 socket);
void CH395Q_TCPConnect(u8 socket);
void Socket_Connect(u8 s);
u8 CH395Q_getCMDStauts(void);
void CH395Q_getSocketStatus(u8 socket,u8 *info);
void Socket0_Open(void);
void Socket0_Init(void);

extern void CH395Q_Init(void);//初始化CH395Q寄存器函数

void CH395Q_Interrupt_Process(void);



#endif

文件名:main.c

/******************** (C) COPYRIGHT 2024 移动中的鸭子 ********************
* File Name          : main.c
* Author             : CZY Application Team
* Version            : V1.0.0
* Date               : 2024-08-03
* Description        : 演示入口及网络处理
*************************************************************************/

#include "includes.h"

u8 NetS0_RevBuffer[S0REV_MAX];     //UDP的缓存
u8 NetS0_SendBuffer[S0SEND_MAX];   //UDP的缓存
u16 Net0SendLength=0;
u8 NetLinkFlag=0;				//网卡连接网络的标记,只用于判断是否网络工作,不是和服务器通信
u8 Socket0_Status=0;		 //端口0的状态
u8 LastS0RemoteIP[4]={192,168,1,51};
u16 LastS0RemotePort=8888;
/*******************************************************************************
* 函数名  : Socket0_ReplyOK
* 描述    : Socket0应答成功
* 输入    : 
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void Socket0_ReplyOK(void)
{
  memcpy(NetS0_SendBuffer,"Hi CZYDemo!Are you OK!",22);
	CH395Q_UDPSendTo(0,NetS0_SendBuffer,22,LastS0RemoteIP,LastS0RemotePort);
}


/*******************************************************************************
* 函数名  : Socket0_Handler
* 描述    : 处理Socket0的中断,这里是作为UDP服务,主要用于控制和配置
* 输入    : 
* 输出    : 无
* 返回值  : 
* 说明    : 
*******************************************************************************/
void Socket0_Handler(void)
{
	u8 socketIRQ=0;
	socketIRQ=CH395Q_getSocketInt(0);
	if(socketIRQ & SINT_STAT_SENBUF_FREE)                      /* 发送缓冲区空闲,可以继续写入要发送的数据 */
  {

  }
  if(socketIRQ & SINT_STAT_SEND_OK)                          /* 发送完成中断 */
  {
		
  }
	if(socketIRQ & SINT_STAT_RECV)                             /* 接收中断 */
  {
		Net0SendLength= CH395Q_getDataLength(0);//注意:UDP服务器模式只能全部接收。服务器模式下CH395会在数据的头部添加8个字
                        //节的信息表,单片机可以根据信息表来获得数据包的来源信息,单片机必须一次性将数据全部读出
		//从395的缓存读出到预设内存
		CH395Q_RevData(0,&NetS0_RevBuffer[0],Net0SendLength);
    //回发给上位机
		CH395Q_UDPSendTo(0,NetS0_RevBuffer,Net0SendLength,LastS0RemoteIP,LastS0RemotePort);
		//尽快读完,不过UDP暂时不需要很快速处理
		memset(NetS0_RevBuffer,0,S0REV_MAX);
		CH395Q_ClearRecvBuf(0);   //后面暂时不要了
		
	}
	if(socketIRQ & SINT_STAT_TIM_OUT)                           //超时中断,UDP好像无效
	{
	 
	}
	
}



/*******************************************************************************
* 函数名  : main
* 描述    : 入口函数,你懂的
* 说明    : 
*******************************************************************************/
int main(void)
{

  Set_System();
  CH395Q_GPIO_Configuration();					//配置网卡								
	CH395Q_Hardware_Reset();
	//检测并配置网卡
	CH395Q_Init();
	Socket0_Init();

  while(1)
  {
		//网络管理
		if(NetLinkFlag==1)	   
		{
			
		}
		
		
		CH395Q_Interrupt_Process();//本例是查询法(未用中断法)
		 
		delay_ms(2000);//这里只是简单延时,演示效果而已,商业应用不建议这么做
		Socket0_ReplyOK();
		
  }
}

文件名:main.h

#ifndef _MAIN_H_
#define _MAIN_H_



#define S0REV_MAX        			512
#define S0SEND_MAX        			512

extern u8 NetS0_RevBuffer[S0REV_MAX];     //UDP的缓存
extern u8 NetS0_SendBuffer[S0SEND_MAX];   //UDP的缓存
extern u16 Net0SendLength;

extern u8 NetLinkFlag;				//网卡连接网络的标记,只用于判断是否网络工作,不是和服务器通信

extern u8 Socket0_Status;		 //端口0的状态

extern u8 LastS0RemoteIP[4];
extern u16 LastS0RemotePort;

void Socket0_Handler(void);

#endif

【实测效果】

以上讲解完成,该程序是为了本文而专门编写,经过测试运行成功。

特别注意:为了演示方便,本例用查询法事实解析接收结果,mian函数while主体用delay_ms(2000)进行延时,会导致接收可能丢包,因为UDP是不可靠,并且不保证到达。实际商业使用时,必须尽可能快地将CH395Q中的缓存读出,否则会丢包。要么用中断读,要么尽可能地快查询。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值