[通用8051核FLASH系列] 【芯圣电子HC89S105A测评报告】+网口TCP客户端

[复制链接]
1199|0
 楼主| 比神乐 发表于 2023-5-27 10:52 | 显示全部楼层 |阅读模式
本帖最后由 芯圣电子官方QQ 于 2023-7-19 16:42 编辑

今天搞了一下SPI接口的网口,芯片是W5500,TCP客户端。
接线:
CS接P1.1,SCK接P1.0,MISO接P0.1,MOSI接P0.0。
RST接P1.2,指示灯接P3.0,这个因为板子上的灯被占用,借用另外一块板子的灯。
主程序代码:
  1. #define ALLOCATE_EXTERN
  2. #include "HC89S105AC8.h"

  3. #include "W5500.h"                        
  4. #include <string.h>



  5. //unsigned char SPI_WriteReadData(unsigned char fuc_Data); //SPI读写数据
  6. void Delay_ms(unsigned int fui_i);                                                           //延时函数

  7. unsigned int Timer2_Counter=0; //Timer2?¨ê±?÷??êy±?á?(ms)
  8. unsigned int W5500_Send_Delay_Counter=0; //W5500·¢?í?óê±??êy±?á?(ms)
  9. unsigned char temp=0;
  10. /*******************************************************************************
  11. * oˉêy??  : W5500_Initialization
  12. * ?èê?    : W55003?ê???????
  13. * ê?è?    : ?T
  14. * ê?3?    : ?T
  15. * ·μ???μ  : ?T
  16. * ?μ?÷    : ?T
  17. *******************************************************************************/
  18. void W5500_Initialization(void)
  19. {
  20.         W5500_Init();                //3?ê??ˉW5500??′??÷oˉêy
  21.         Detect_Gateway();        //?ì2éí?1?·t???÷
  22.         Socket_Init(0);                //???¨Socket(0~7)3?ê??ˉ,3?ê??ˉ???ú0
  23. }

  24. /*******************************************************************************
  25. * oˉêy??  : Load_Net_Parameters
  26. * ?èê?    : ×°??í???2?êy
  27. * ê?è?    : ?T
  28. * ê?3?    : ?T
  29. * ·μ???μ  : ?T
  30. * ?μ?÷    : í?1??¢?ú???¢??àíμ??·?¢±??úIPμ??·?¢???úo??¢??μ?IPμ??·?¢??μ????úo??¢???ú1¤×÷?£ê?
  31. *******************************************************************************/
  32. void Load_Net_Parameters(void)
  33. {
  34.         Gateway_IP[0] = 169;//?ó??í?1?2?êy
  35.         Gateway_IP[1] = 254;
  36.         Gateway_IP[2] = 206;
  37.         Gateway_IP[3] = 1;

  38.         Sub_Mask[0]=255;//?ó??×óí??ú??
  39.         Sub_Mask[1]=255;
  40.         Sub_Mask[2]=0;
  41.         Sub_Mask[3]=0;

  42.         Phy_Addr[0]=0x6D;//?ó????àíμ??·
  43.         Phy_Addr[1]=0x58;
  44.         Phy_Addr[2]=0x49;
  45.         Phy_Addr[3]=0xFC;
  46.         Phy_Addr[4]=0xA9;
  47.         Phy_Addr[5]=0xB4;

  48.         IP_Addr[0]=169;//?ó??±??úIPμ??·
  49.         IP_Addr[1]=254;
  50.         IP_Addr[2]=206;
  51.         IP_Addr[3]=40;

  52.         S0_Port[0] = 0x13;//?ó?????ú0μ????úo?5000
  53.         S0_Port[1] = 0x88;

  54.         S0_DIP[0]=169;//?ó?????ú0μ???μ?IPμ??·
  55.         S0_DIP[1]=254;
  56.         S0_DIP[2]=206;
  57.         S0_DIP[3]=87;
  58.         
  59.         S0_DPort[0] = 0x17;//?ó?????ú0μ???μ????úo?6000
  60.         S0_DPort[1] = 0x70;

  61.         S0_Mode=TCP_CLIENT;//?ó?????ú0μ?1¤×÷?£ê?,TCP?í?§???£ê?
  62. }

  63. /*******************************************************************************
  64. * oˉêy??  : W5500_Socket_Set
  65. * ?èê?    : W5500???ú3?ê??ˉ????
  66. * ê?è?    : ?T
  67. * ê?3?    : ?T
  68. * ·μ???μ  : ?T
  69. * ?μ?÷    : ·?±eéè??4?????ú,?ù?Y???ú1¤×÷?£ê?,?????ú??óúTCP·t???÷?¢TCP?í?§???òUDP?£ê?.
  70. *                        ′ó???ú×′ì?×??úSocket_State?éò??D?????úμ?1¤×÷?é??
  71. *******************************************************************************/
  72. void W5500_Socket_Set(void)
  73. {
  74.         if(S0_State==0)//???ú03?ê??ˉ????
  75.         {
  76.                 if(S0_Mode==TCP_SERVER)//TCP·t???÷?£ê?
  77.                 {
  78.                         if(Socket_Listen(0)==TRUE)
  79.                                 S0_State=S_INIT;
  80.                         else
  81.                                 S0_State=0;
  82.                 }
  83.                 else if(S0_Mode==TCP_CLIENT)//TCP?í?§???£ê?
  84.                 {
  85.                         if(Socket_Connect(0)==TRUE)
  86.                                 S0_State=S_INIT;
  87.                         else
  88.                                 S0_State=0;
  89.                 }
  90.                 else//UDP?£ê?
  91.                 {
  92.                         if(Socket_UDP(0)==TRUE)
  93.                                 S0_State=S_INIT|S_CONN;
  94.                         else
  95.                                 S0_State=0;
  96.                 }
  97.         }
  98. }

  99. /*******************************************************************************
  100. * oˉêy??  : Process_Socket_Data
  101. * ?èê?    : W5500?óê?2¢·¢?í?óê?μ?μ?êy?Y
  102. * ê?è?    : s:???úo?
  103. * ê?3?    : ?T
  104. * ·μ???μ  : ?T
  105. * ?μ?÷    : ±?1y3ì?èμ÷ó?S_rx_process()′óW5500μ????ú?óê?êy?Y?o3????áè?êy?Y,
  106. *                        è?oó???áè?μ?êy?Y′óRx_Buffer??±′μ?Temp_Buffer?o3?????DD′|àí?£
  107. *                        ′|àííê±?£???êy?Y′óTemp_Buffer??±′μ?Tx_Buffer?o3????£μ÷ó?S_tx_process()
  108. *                        ·¢?íêy?Y?£
  109. *******************************************************************************/
  110. void Process_Socket_Data(SOCKET s)
  111. {
  112.         unsigned short size;
  113.         size=Read_SOCK_Data_Buffer(s, Rx_Buffer);
  114.         if(Rx_Buffer[0]=='1')
  115.                 P3_0=0;
  116.         if(Rx_Buffer[0]=='0')
  117.                 P3_0=1;
  118.         memcpy(Tx_Buffer, Rx_Buffer, size);                        
  119.         Write_SOCK_Data_Buffer(s, Tx_Buffer, size);
  120. }
  121. /***************************************************************************************
  122.   * @实现效果        主机一直向从机发送数据0xAA,从机将接收的数据通过串口发送至上位机
  123.   * @操作方法   两个MCU相同IO连接,P00->P00 P01->P01 P10->P10 ,逻辑分析仪接P00 P01 P10
  124.   * @注意事项   主机SCK跑2M以上时,从机CPU的速率需要比主机高,2M以下无此限制,可设置任何速率  
  125. ***************************************************************************************/
  126. void main()
  127. {
  128. /***************************************系统初始化*******************************************/               
  129.         WDTCCR = 0x00;                           //关闭看门狗
  130.                                                            //本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
  131.         CLKCON = 0x02;                           //选择内部高频RC为系统时钟, Fosc=32MHz
  132.         CLKDIV = 0x02;                           //Fosc 2分频得到Fcpu,Fcpu=16MHz        
  133.         
  134. /************************************SPI初始化*****************************************/
  135.         P0M0 = P0M0&0x0F|0x40;        //P01带SMT输入
  136.         P0M0 = P0M0&0xF0|0x08;        //P00推挽输出
  137.         //P0M1 = 0x88;
  138.         //P1M0 = P1M0&0xF0|0x08;        //P10推挽输出
  139.         P1M0 = 0xCC;        //P10推挽输出
  140.         P1M1 = 0xFC;
  141.         P3M0 = 0xFC;
  142.         P3_0=1;
  143.         P0DRENL=0XFF;
  144.         MISO_MAP=0x01;                      //SPI_MISO 映射到P01口 输入口
  145.         MOSI_MAP=0x00;                      //SPI_MOSI 映射到P00口 输出口
  146.         SCK_MAP=0x08;                      //SPI_SCK  映射到P10口 时钟端
  147.         
  148.         SPDAT=0x00;                   //数据寄存器写0
  149.         SPSTAT=0x00;                  //状态寄存器清0     
  150.         SPCTL=0xD3;                   //主机模式,时钟128分频                                                   
  151.         Load_Net_Parameters();                //×°??í???2?êy        
  152.         W5500_Hardware_Reset();                //ó2?t?′??W5500
  153.         W5500_Initialization();                //W55003?ê???????
  154. //        while(1)
  155. //        {
  156. //                Write_W5500_1Byte(0x0001,169);
  157. //                temp=Read_W5500_1Byte(0x0001);
  158. //                Delay(5);
  159. //        }
  160.         Write_W5500_1Byte(0x0001,169);
  161.         temp=Read_W5500_1Byte(0x0001);
  162.         while (1)
  163.         {
  164.                 W5500_Socket_Set();//W5500???ú3?ê??ˉ????

  165.                 W5500_Interrupt_Process();//W5500?D??′|àí3ìDò?ò?ü

  166.                 if((S0_Data & S_RECEIVE) == S_RECEIVE)//è?1?Socket0?óê?μ?êy?Y
  167.                 {
  168.                         S0_Data&=~S_RECEIVE;
  169.                         Process_Socket_Data(0);//W5500?óê?2¢·¢?í?óê?μ?μ?êy?Y
  170.                 }
  171.                 else if(W5500_Send_Delay_Counter >= 5000)//?¨ê±·¢?í×?·?′?
  172.                 {
  173.                         if(S0_State == (S_INIT|S_CONN))
  174.                         {
  175.                                 S0_Data&=~S_TRANSMITOK;
  176.                                 memcpy(Tx_Buffer, "\r\nWelcome To ChuangWeiElec!\r\n", 27);
  177.                                 Write_SOCK_Data_Buffer(0, Tx_Buffer, 27);//???¨Socket(0~7)·¢?íêy?Y′|àí,???ú0·¢?í27×??úêy?Y
  178.                         }
  179.                         W5500_Send_Delay_Counter=0;
  180.                 }        
  181.                 W5500_Send_Delay_Counter++;
  182.         }
  183. }

  184. /***********************************************************************************
  185.   * @说明          延时函数
  186.   * @参数          fui_i : 延时时间
  187.   * @返回值 无
  188.   * @注           Fcpu = 16MHz,fui_i = 1时,延时时间约为1ms
  189.   *********************************************************************************/
  190. void Delay_ms(unsigned int fui_i)
  191. {
  192.         unsigned int fui_j;
  193.         for(;fui_i > 0;fui_i --)
  194.         for(fui_j = 1596;fui_j > 0;fui_j --);
  195. }
w5500.c代码:
  1. #include "HC89S105AC8.h"               
  2. #include "W5500.h"        

  3. /***************----- 网络参数变量定义 -----***************/
  4. unsigned char Gateway_IP[4];//网关IP地址
  5. unsigned char Sub_Mask[4];        //子网掩码
  6. unsigned char Phy_Addr[6];        //物理地址(MAC)
  7. unsigned char IP_Addr[4];        //本机IP地址

  8. unsigned char S0_Port[2];        //端口0的端口号(5000)
  9. unsigned char S0_DIP[4];        //端口0目的IP地址
  10. unsigned char S0_DPort[2];        //端口0目的端口号(6000)

  11. unsigned char UDP_DIPR[4];        //UDP(广播)模式,目的主机IP地址
  12. unsigned char UDP_DPORT[2];        //UDP(广播)模式,目的主机端口号

  13. /***************----- 端口的运行模式 -----***************/
  14. unsigned char S0_Mode =3;        //端口0的运行模式,0:TCP服务器模式,1:TCP客户端模式,2:UDP(广播)模式
  15. #define TCP_SERVER        0x00        //TCP服务器模式
  16. #define TCP_CLIENT        0x01        //TCP客户端模式
  17. #define UDP_MODE        0x02        //UDP(广播)模式

  18. /***************----- 端口的运行状态 -----***************/
  19. unsigned char S0_State =0;        //端口0状态记录,1:端口完成初始化,2端口完成连接(可以正常传输数据)
  20. #define S_INIT                0x01        //端口完成初始化
  21. #define S_CONN                0x02        //端口完成连接,可以正常传输数据

  22. /***************----- 端口收发数据的状态 -----***************/
  23. unsigned char S0_Data;                //端口0接收和发送数据的状态,1:端口接收到数据,2:端口发送数据完成
  24. #define S_RECEIVE         0x01        //端口接收到一个数据包
  25. #define S_TRANSMITOK 0x02        //端口发送一个数据包完成

  26. /***************----- 端口数据缓冲区 -----***************/
  27. unsigned char Rx_Buffer[1024];        //端口接收数据缓冲区
  28. unsigned char Tx_Buffer[1024];        //端口发送数据缓冲区

  29. unsigned char W5500_Interrupt;        //W5500中断标志(0:无中断,1:有中断)


  30. extern void Delay_ms(unsigned int fui_i);
  31. //extern unsigned char SPI_WriteReadData(unsigned char fuc_Data);
  32. /************************************************************************************
  33.   * @说明          SPI写读函数
  34.   *        @参数          fuc_Data :SPI读写数据
  35.   * @返回值 SPDAT : SPI读取数据
  36.   * @注                  无
  37.   *********************************************************************************/
  38. void SPI_WriteReadData(unsigned char fuc_Data)
  39. {
  40.         SPSTAT = 0xC0;
  41.         SPDAT = fuc_Data;
  42.         while(!(SPSTAT&0x80));
  43. //        SPSTAT = 0xC0;
  44. //        return SPDAT;
  45. }
  46. /*******************************************************************************
  47. * 函数名  : SPI1_Send_Byte
  48. * 描述    : SPI1发送1个字节数据
  49. * 输入    : dat:待发送的数据
  50. * 输出    : 无
  51. * 返回值  : 无
  52. * 说明    : 无
  53. *******************************************************************************/
  54. void SPI1_Send_Byte(unsigned char dat)
  55. {
  56.         
  57.         SPI_WriteReadData(dat);

  58. }

  59. /*******************************************************************************
  60. * 函数名  : SPI1_Send_Short
  61. * 描述    : SPI1发送2个字节数据(16位)
  62. * 输入    : dat:待发送的16位数据
  63. * 输出    : 无
  64. * 返回值  : 无
  65. * 说明    : 无
  66. *******************************************************************************/
  67. void SPI1_Send_Short(unsigned short dat)
  68. {
  69.         SPI1_Send_Byte(dat/256);//写数据高位
  70.         SPI1_Send_Byte(dat);        //写数据低位
  71. }

  72. /*******************************************************************************
  73. * 函数名  : Write_W5500_1Byte
  74. * 描述    : 通过SPI1向指定地址寄存器写1个字节数据
  75. * 输入    : reg:16位寄存器地址,dat:待写入的数据
  76. * 输出    : 无
  77. * 返回值  : 无
  78. * 说明    : 无
  79. *******************************************************************************/
  80. void Write_W5500_1Byte(unsigned short reg, unsigned char dat)
  81. {
  82.         P1_1=0;//置W5500的SCS为低电平

  83.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  84.         SPI1_Send_Byte(FDM1|RWB_WRITE|COMMON_R);//通过SPI1写控制字节,1个字节数据长度,写数据,选择通用寄存器
  85.         SPI1_Send_Byte(dat);//写1个字节数据

  86.         P1_1=1; //置W5500的SCS为高电平
  87. }

  88. /*******************************************************************************
  89. * 函数名  : Write_W5500_2Byte
  90. * 描述    : 通过SPI1向指定地址寄存器写2个字节数据
  91. * 输入    : reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
  92. * 输出    : 无
  93. * 返回值  : 无
  94. * 说明    : 无
  95. *******************************************************************************/
  96. void Write_W5500_2Byte(unsigned short reg, unsigned short dat)
  97. {
  98.         P1_1=0;//置W5500的SCS为低电平
  99.                
  100.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  101.         SPI1_Send_Byte(FDM2|RWB_WRITE|COMMON_R);//通过SPI1写控制字节,2个字节数据长度,写数据,选择通用寄存器
  102.         SPI1_Send_Short(dat);//写16位数据

  103.         P1_1=1; //置W5500的SCS为高电平
  104. }

  105. /*******************************************************************************
  106. * 函数名  : Write_W5500_nByte
  107. * 描述    : 通过SPI1向指定地址寄存器写n个字节数据
  108. * 输入    : reg:16位寄存器地址,*dat_ptr:待写入数据缓冲区指针,size:待写入的数据长度
  109. * 输出    : 无
  110. * 返回值  : 无
  111. * 说明    : 无
  112. *******************************************************************************/
  113. void Write_W5500_nByte(unsigned short reg, unsigned char *dat_ptr, unsigned short size)
  114. {
  115.         unsigned short i;

  116.         P1_1=0;//置W5500的SCS为低电平        
  117.                
  118.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  119.         SPI1_Send_Byte(VDM|RWB_WRITE|COMMON_R);//通过SPI1写控制字节,N个字节数据长度,写数据,选择通用寄存器

  120.         for(i=0;i<size;i++)//循环将缓冲区的size个字节数据写入W5500
  121.         {
  122.                 SPI1_Send_Byte(*dat_ptr++);//写一个字节数据
  123.         }

  124.         P1_1=1; //置W5500的SCS为高电平
  125. }

  126. /*******************************************************************************
  127. * 函数名  : Write_W5500_SOCK_1Byte
  128. * 描述    : 通过SPI1向指定端口寄存器写1个字节数据
  129. * 输入    : s:端口号,reg:16位寄存器地址,dat:待写入的数据
  130. * 输出    : 无
  131. * 返回值  : 无
  132. * 说明    : 无
  133. *******************************************************************************/
  134. void Write_W5500_SOCK_1Byte(SOCKET s, unsigned short reg, unsigned char dat)
  135. {
  136.         P1_1=0;//置W5500的SCS为低电平        
  137.                
  138.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  139.         SPI1_Send_Byte(FDM1|RWB_WRITE|(s*0x20+0x08));//通过SPI1写控制字节,1个字节数据长度,写数据,选择端口s的寄存器
  140.         SPI1_Send_Byte(dat);//写1个字节数据

  141.         P1_1=1; //置W5500的SCS为高电平
  142. }

  143. /*******************************************************************************
  144. * 函数名  : Write_W5500_SOCK_2Byte
  145. * 描述    : 通过SPI1向指定端口寄存器写2个字节数据
  146. * 输入    : s:端口号,reg:16位寄存器地址,dat:16位待写入的数据(2个字节)
  147. * 输出    : 无
  148. * 返回值  : 无
  149. * 说明    : 无
  150. *******************************************************************************/
  151. void Write_W5500_SOCK_2Byte(SOCKET s, unsigned short reg, unsigned short dat)
  152. {
  153.         P1_1=0;//置W5500的SCS为低电平
  154.                         
  155.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  156.         SPI1_Send_Byte(FDM2|RWB_WRITE|(s*0x20+0x08));//通过SPI1写控制字节,2个字节数据长度,写数据,选择端口s的寄存器
  157.         SPI1_Send_Short(dat);//写16位数据

  158.         P1_1=1; //置W5500的SCS为高电平
  159. }

  160. /*******************************************************************************
  161. * 函数名  : Write_W5500_SOCK_4Byte
  162. * 描述    : 通过SPI1向指定端口寄存器写4个字节数据
  163. * 输入    : s:端口号,reg:16位寄存器地址,*dat_ptr:待写入的4个字节缓冲区指针
  164. * 输出    : 无
  165. * 返回值  : 无
  166. * 说明    : 无
  167. *******************************************************************************/
  168. void Write_W5500_SOCK_4Byte(SOCKET s, unsigned short reg, unsigned char *dat_ptr)
  169. {
  170.         P1_1=0;//置W5500的SCS为低电平
  171.                         
  172.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  173.         SPI1_Send_Byte(FDM4|RWB_WRITE|(s*0x20+0x08));//通过SPI1写控制字节,4个字节数据长度,写数据,选择端口s的寄存器

  174.         SPI1_Send_Byte(*dat_ptr++);//写第1个字节数据
  175.         SPI1_Send_Byte(*dat_ptr++);//写第2个字节数据
  176.         SPI1_Send_Byte(*dat_ptr++);//写第3个字节数据
  177.         SPI1_Send_Byte(*dat_ptr++);//写第4个字节数据

  178.         P1_1=1; //置W5500的SCS为高电平
  179. }
  180. unsigned char SPI_ReadData(void)
  181. {
  182.         
  183.         return SPDAT;
  184. }
  185. /*******************************************************************************
  186. * 函数名  : Read_W5500_1Byte
  187. * 描述    : 读W5500指定地址寄存器的1个字节数据
  188. * 输入    : reg:16位寄存器地址
  189. * 输出    : 无
  190. * 返回值  : 读取到寄存器的1个字节数据
  191. * 说明    : 无
  192. *******************************************************************************/
  193. unsigned char Read_W5500_1Byte(unsigned short reg)
  194. {
  195.         unsigned char i;

  196.         P1_1=0;//置W5500的SCS为低电平
  197.                         
  198.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  199.         SPI1_Send_Byte(FDM1|RWB_READ|COMMON_R);//通过SPI1写控制字节,1个字节数据长度,读数据,选择通用寄存器

  200.         i=SPI_ReadData();
  201.         SPI1_Send_Byte(0x00);//发送一个哑数据
  202.         i=SPI_ReadData();//读取1个字节数据

  203.         P1_1=1; //置W5500的SCS为高电平
  204.         return i;//返回读取到的寄存器数据
  205. }

  206. /*******************************************************************************
  207. * 函数名  : Read_W5500_SOCK_1Byte
  208. * 描述    : 读W5500指定端口寄存器的1个字节数据
  209. * 输入    : s:端口号,reg:16位寄存器地址
  210. * 输出    : 无
  211. * 返回值  : 读取到寄存器的1个字节数据
  212. * 说明    : 无
  213. *******************************************************************************/
  214. unsigned char Read_W5500_SOCK_1Byte(SOCKET s, unsigned short reg)
  215. {
  216.         unsigned char i;

  217.         P1_1=0;//置W5500的SCS为低电平
  218.                         
  219.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  220.         SPI1_Send_Byte(FDM1|RWB_READ|(s*0x20+0x08));//通过SPI1写控制字节,1个字节数据长度,读数据,选择端口s的寄存器

  221.         i=SPI_ReadData();
  222.         SPI1_Send_Byte(0x00);//发送一个哑数据
  223.         i=SPI_ReadData();//读取1个字节数据

  224.         P1_1=1; //置W5500的SCS为高电平
  225.         return i;//返回读取到的寄存器数据
  226. }

  227. /*******************************************************************************
  228. * 函数名  : Read_W5500_SOCK_2Byte
  229. * 描述    : 读W5500指定端口寄存器的2个字节数据
  230. * 输入    : s:端口号,reg:16位寄存器地址
  231. * 输出    : 无
  232. * 返回值  : 读取到寄存器的2个字节数据(16位)
  233. * 说明    : 无
  234. *******************************************************************************/
  235. unsigned short Read_W5500_SOCK_2Byte(SOCKET s, unsigned short reg)
  236. {
  237.         unsigned short i;

  238.         P1_1=0;//置W5500的SCS为低电平
  239.                         
  240.         SPI1_Send_Short(reg);//通过SPI1写16位寄存器地址
  241.         SPI1_Send_Byte(FDM2|RWB_READ|(s*0x20+0x08));//通过SPI1写控制字节,2个字节数据长度,读数据,选择端口s的寄存器

  242.         i=SPI_ReadData();
  243.         SPI1_Send_Byte(0x00);//发送一个哑数据
  244.         i=SPI_ReadData();//读取高位数据
  245.         SPI1_Send_Byte(0x00);//发送一个哑数据
  246.         i*=256;
  247.         i+=SPI_ReadData();//读取低位数据

  248.         P1_1=1; //置W5500的SCS为高电平
  249.         return i;//返回读取到的寄存器数据
  250. }

  251. /*******************************************************************************
  252. * 函数名  : Read_SOCK_Data_Buffer
  253. * 描述    : 从W5500接收数据缓冲区中读取数据
  254. * 输入    : s:端口号,*dat_ptr:数据保存缓冲区指针
  255. * 输出    : 无
  256. * 返回值  : 读取到的数据长度,rx_size个字节
  257. * 说明    : 无
  258. *******************************************************************************/
  259. unsigned short Read_SOCK_Data_Buffer(SOCKET s, unsigned char *dat_ptr)
  260. {
  261.         unsigned short rx_size;
  262.         unsigned short offset, offset1;
  263.         unsigned short i;
  264.         unsigned char j;

  265.         rx_size=Read_W5500_SOCK_2Byte(s,Sn_RX_RSR);
  266.         if(rx_size==0) return 0;//没接收到数据则返回
  267.         if(rx_size>1460) rx_size=1460;

  268.         offset=Read_W5500_SOCK_2Byte(s,Sn_RX_RD);
  269.         offset1=offset;
  270.         offset&=(S_RX_SIZE-1);//计算实际的物理地址

  271.         P1_1=0;//置W5500的SCS为低电平

  272.         SPI1_Send_Short(offset);//写16位地址
  273.         SPI1_Send_Byte(VDM|RWB_READ|(s*0x20+0x18));//写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
  274.         j=SPI_ReadData();
  275.         
  276.         if((offset+rx_size)<S_RX_SIZE)//如果最大地址未超过W5500接收缓冲区寄存器的最大地址
  277.         {
  278.                 for(i=0;i<rx_size;i++)//循环读取rx_size个字节数据
  279.                 {
  280.                         SPI1_Send_Byte(0x00);//发送一个哑数据
  281.                         j=SPI_ReadData();//读取1个字节数据
  282.                         //j=SPI1_Send_Byte(0x00);
  283.                         *dat_ptr=j;//将读取到的数据保存到数据保存缓冲区
  284.                         dat_ptr++;//数据保存缓冲区指针地址自增1
  285.                 }
  286.         }
  287.         else//如果最大地址超过W5500接收缓冲区寄存器的最大地址
  288.         {
  289.                 offset=S_RX_SIZE-offset;
  290.                 for(i=0;i<offset;i++)//循环读取出前offset个字节数据
  291.                 {
  292.                         SPI1_Send_Byte(0x00);//发送一个哑数据
  293.                         j=SPI_ReadData();//读取1个字节数据
  294.                 //        j=SPI1_Send_Byte(0x00);
  295.                         *dat_ptr=j;//将读取到的数据保存到数据保存缓冲区
  296.                         dat_ptr++;//数据保存缓冲区指针地址自增1
  297.                 }
  298.                 P1_1=1;  //置W5500的SCS为高电平

  299.                 P1_1=0;//置W5500的SCS为低电平

  300.                 SPI1_Send_Short(0x00);//写16位地址
  301.                 SPI1_Send_Byte(VDM|RWB_READ|(s*0x20+0x18));//写控制字节,N个字节数据长度,读数据,选择端口s的寄存器
  302.                 j=SPI_ReadData();

  303.                 for(;i<rx_size;i++)//循环读取后rx_size-offset个字节数据
  304.                 {
  305.                         SPI1_Send_Byte(0x00);//发送一个哑数据
  306.                         j=SPI_ReadData();//读取1个字节数据
  307.                         //j=SPI1_Send_Byte(0x00);
  308.                         *dat_ptr=j;//将读取到的数据保存到数据保存缓冲区
  309.                         dat_ptr++;//数据保存缓冲区指针地址自增1
  310.                 }
  311.         }
  312.         P1_1=1;  //置W5500的SCS为高电平

  313.         offset1+=rx_size;//更新实际物理地址,即下次读取接收到的数据的起始地址
  314.         Write_W5500_SOCK_2Byte(s, Sn_RX_RD, offset1);
  315.         Write_W5500_SOCK_1Byte(s, Sn_CR, RECV);//发送启动接收命令
  316.         return rx_size;//返回接收到数据的长度
  317. }

  318. /*******************************************************************************
  319. * 函数名  : Write_SOCK_Data_Buffer
  320. * 描述    : 将数据写入W5500的数据发送缓冲区
  321. * 输入    : s:端口号,*dat_ptr:数据保存缓冲区指针,size:待写入数据的长度
  322. * 输出    : 无
  323. * 返回值  : 无
  324. * 说明    : 无
  325. *******************************************************************************/
  326. void Write_SOCK_Data_Buffer(SOCKET s, unsigned char *dat_ptr, unsigned short size)
  327. {
  328.         unsigned short offset,offset1;
  329.         unsigned short i;

  330.         //如果是UDP模式,可以在此设置目的主机的IP和端口号
  331.         if((Read_W5500_SOCK_1Byte(s,Sn_MR)&0x0f) != SOCK_UDP)//如果Socket打开失败
  332.         {               
  333.                 Write_W5500_SOCK_4Byte(s, Sn_DIPR, UDP_DIPR);//设置目的主机IP                  
  334.                 Write_W5500_SOCK_2Byte(s, Sn_DPORTR, UDP_DPORT[0]*256+UDP_DPORT[1]);//设置目的主机端口号                                
  335.         }

  336.         offset=Read_W5500_SOCK_2Byte(s,Sn_TX_WR);
  337.         offset1=offset;
  338.         offset&=(S_TX_SIZE-1);//计算实际的物理地址

  339.         P1_1=0;//置W5500的SCS为低电平

  340.         SPI1_Send_Short(offset);//写16位地址
  341.         SPI1_Send_Byte(VDM|RWB_WRITE|(s*0x20+0x10));//写控制字节,N个字节数据长度,写数据,选择端口s的寄存器

  342.         if((offset+size)<S_TX_SIZE)//如果最大地址未超过W5500发送缓冲区寄存器的最大地址
  343.         {
  344.                 for(i=0;i<size;i++)//循环写入size个字节数据
  345.                 {
  346.                         SPI1_Send_Byte(*dat_ptr++);//写入一个字节的数据               
  347.                 }
  348.         }
  349.         else//如果最大地址超过W5500发送缓冲区寄存器的最大地址
  350.         {
  351.                 offset=S_TX_SIZE-offset;
  352.                 for(i=0;i<offset;i++)//循环写入前offset个字节数据
  353.                 {
  354.                         SPI1_Send_Byte(*dat_ptr++);//写入一个字节的数据
  355.                 }
  356.                 P1_1=1; //置W5500的SCS为高电平

  357.                 P1_1=0;//置W5500的SCS为低电平

  358.                 SPI1_Send_Short(0x00);//写16位地址
  359.                 SPI1_Send_Byte(VDM|RWB_WRITE|(s*0x20+0x10));//写控制字节,N个字节数据长度,写数据,选择端口s的寄存器

  360.                 for(;i<size;i++)//循环写入size-offset个字节数据
  361.                 {
  362.                         SPI1_Send_Byte(*dat_ptr++);//写入一个字节的数据
  363.                 }
  364.         }
  365.         P1_1=1;  //置W5500的SCS为高电平

  366.         offset1+=size;//更新实际物理地址,即下次写待发送数据到发送数据缓冲区的起始地址
  367.         Write_W5500_SOCK_2Byte(s, Sn_TX_WR, offset1);
  368.         Write_W5500_SOCK_1Byte(s, Sn_CR, SEND);//发送启动发送命令                                
  369. }

  370. /*******************************************************************************
  371. * 函数名  : W5500_Hardware_Reset
  372. * 描述    : 硬件复位W5500
  373. * 输入    : 无
  374. * 输出    : 无
  375. * 返回值  : 无
  376. * 说明    : W5500的复位引脚保持低电平至少500us以上,才能重围W5500
  377. *******************************************************************************/
  378. void W5500_Hardware_Reset(void)
  379. {
  380.         P1_2=0;//复位引脚拉低
  381.         Delay_ms(50);
  382.         P1_2=1; //复位引脚拉高
  383.         Delay_ms(200);
  384.         while((Read_W5500_1Byte(PHYCFGR)&LINK)==0);//等待以太网连接完成
  385. }

  386. /*******************************************************************************
  387. * 函数名  : W5500_Init
  388. * 描述    : 初始化W5500寄存器函数
  389. * 输入    : 无
  390. * 输出    : 无
  391. * 返回值  : 无
  392. * 说明    : 在使用W5500之前,先对W5500初始化
  393. *******************************************************************************/
  394. void W5500_Init(void)
  395. {
  396.         u8 i=0;

  397.         Write_W5500_1Byte(MR, RST);//软件复位W5500,置1有效,复位后自动清0
  398.         Delay_ms(10);//延时10ms,自己定义该函数

  399.         //设置网关(Gateway)的IP地址,Gateway_IP为4字节unsigned char数组,自己定义
  400.         //使用网关可以使通信突破子网的局限,通过网关可以访问到其它子网或进入Internet
  401.         Write_W5500_nByte(GAR, Gateway_IP, 4);
  402.                         
  403.         //设置子网掩码(MASK)值,SUB_MASK为4字节unsigned char数组,自己定义
  404.         //子网掩码用于子网运算
  405.         Write_W5500_nByte(SUBR,Sub_Mask,4);               
  406.         
  407.         //设置物理地址,PHY_ADDR为6字节unsigned char数组,自己定义,用于唯一标识网络设备的物理地址值
  408.         //该地址值需要到IEEE申请,按照OUI的规定,前3个字节为厂商代码,后三个字节为产品序号
  409.         //如果自己定义物理地址,注意第一个字节必须为偶数
  410.         Write_W5500_nByte(SHAR,Phy_Addr,6);               

  411.         //设置本机的IP地址,IP_ADDR为4字节unsigned char数组,自己定义
  412.         //注意,网关IP必须与本机IP属于同一个子网,否则本机将无法找到网关
  413.         Write_W5500_nByte(SIPR,IP_Addr,4);               
  414.         
  415.         //设置发送缓冲区和接收缓冲区的大小,参考W5500数据手册
  416.         for(i=0;i<8;i++)
  417.         {
  418.                 Write_W5500_SOCK_1Byte(i,Sn_RXBUF_SIZE, 0x02);//Socket Rx memory size=2k
  419.                 Write_W5500_SOCK_1Byte(i,Sn_TXBUF_SIZE, 0x02);//Socket Tx mempry size=2k
  420.         }

  421.         //设置重试时间,默认为2000(200ms)
  422.         //每一单位数值为100微秒,初始化时值设为2000(0x07D0),等于200毫秒
  423.         Write_W5500_2Byte(RTR, 0x07d0);

  424.         //设置重试次数,默认为8次
  425.         //如果重发的次数超过设定值,则产生超时中断(相关的端口中断寄存器中的Sn_IR 超时位(TIMEOUT)置“1”)
  426.         Write_W5500_1Byte(RCR,8);
  427. }

  428. /*******************************************************************************
  429. * 函数名  : Detect_Gateway
  430. * 描述    : 检查网关服务器
  431. * 输入    : 无
  432. * 输出    : 无
  433. * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
  434. * 说明    : 无
  435. *******************************************************************************/
  436. unsigned char Detect_Gateway(void)
  437. {
  438.         unsigned char ip_adde[4];
  439.         ip_adde[0]=IP_Addr[0]+1;
  440.         ip_adde[1]=IP_Addr[1]+1;
  441.         ip_adde[2]=IP_Addr[2]+1;
  442.         ip_adde[3]=IP_Addr[3]+1;

  443.         //检查网关及获取网关的物理地址
  444.         Write_W5500_SOCK_4Byte(0,Sn_DIPR,ip_adde);//向目的地址寄存器写入与本机IP不同的IP值
  445.         Write_W5500_SOCK_1Byte(0,Sn_MR,MR_TCP);//设置socket为TCP模式
  446.         Write_W5500_SOCK_1Byte(0,Sn_CR,OPEN);//打开Socket        
  447.         Delay_ms(5);//延时5ms         
  448.         
  449.         if(Read_W5500_SOCK_1Byte(0,Sn_SR) != SOCK_INIT)//如果socket打开失败
  450.         {
  451.                 Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);//打开不成功,关闭Socket
  452.                 return FALSE;//返回FALSE(0x00)
  453.         }

  454.         Write_W5500_SOCK_1Byte(0,Sn_CR,CONNECT);//设置Socket为Connect模式                                                

  455.         do
  456.         {
  457.                 u8 j=0;
  458.                 j=Read_W5500_SOCK_1Byte(0,Sn_IR);//读取Socket0中断标志寄存器
  459.                 if(j!=0)
  460.                 Write_W5500_SOCK_1Byte(0,Sn_IR,j);
  461.                 Delay_ms(5);//延时5ms
  462.                 if((j&IR_TIMEOUT) == IR_TIMEOUT)
  463.                 {
  464.                         return FALSE;        
  465.                 }
  466.                 else if(Read_W5500_SOCK_1Byte(0,Sn_DHAR) != 0xff)
  467.                 {
  468.                         Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);//关闭Socket
  469.                         return TRUE;                                                        
  470.                 }
  471.         }while(1);
  472. }

  473. /*******************************************************************************
  474. * 函数名  : Socket_Init
  475. * 描述    : 指定Socket(0~7)初始化
  476. * 输入    : s:待初始化的端口
  477. * 输出    : 无
  478. * 返回值  : 无
  479. * 说明    : 无
  480. *******************************************************************************/
  481. void Socket_Init(SOCKET s)
  482. {
  483.         //设置分片长度,参考W5500数据手册,该值可以不修改        
  484.         Write_W5500_SOCK_2Byte(0, Sn_MSSR, 1460);//最大分片字节数=1460(0x5b4)
  485.         //设置指定端口
  486.         switch(s)
  487.         {
  488.                 case 0:
  489.                         //设置端口0的端口号
  490.                         Write_W5500_SOCK_2Byte(0, Sn_PORT, S0_Port[0]*256+S0_Port[1]);
  491.                         //设置端口0目的(远程)端口号
  492.                         Write_W5500_SOCK_2Byte(0, Sn_DPORTR, S0_DPort[0]*256+S0_DPort[1]);
  493.                         //设置端口0目的(远程)IP地址
  494.                         Write_W5500_SOCK_4Byte(0, Sn_DIPR, S0_DIP);                        
  495.                         
  496.                         break;

  497.                 case 1:
  498.                         break;

  499.                 case 2:
  500.                         break;

  501.                 case 3:
  502.                         break;

  503.                 case 4:
  504.                         break;

  505.                 case 5:
  506.                         break;

  507.                 case 6:
  508.                         break;

  509.                 case 7:
  510.                         break;

  511.                 default:
  512.                         break;
  513.         }
  514. }

  515. /*******************************************************************************
  516. * 函数名  : Socket_Connect
  517. * 描述    : 设置指定Socket(0~7)为客户端与远程服务器连接
  518. * 输入    : s:待设定的端口
  519. * 输出    : 无
  520. * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
  521. * 说明    : 当本机Socket工作在客户端模式时,引用该程序,与远程服务器建立连接
  522. *                        如果启动连接后出现超时中断,则与服务器连接失败,需要重新调用该程序连接
  523. *                        该程序每调用一次,就与服务器产生一次连接
  524. *******************************************************************************/
  525. unsigned char Socket_Connect(SOCKET s)
  526. {
  527.         Write_W5500_SOCK_1Byte(s,Sn_MR,MR_TCP);//设置socket为TCP模式
  528.         Write_W5500_SOCK_1Byte(s,Sn_CR,OPEN);//打开Socket
  529.         Delay_ms(5);//延时5ms
  530.         if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_INIT)//如果socket打开失败
  531.         {
  532.                 Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//打开不成功,关闭Socket
  533.                 return FALSE;//返回FALSE(0x00)
  534.         }
  535.         Write_W5500_SOCK_1Byte(s,Sn_CR,CONNECT);//设置Socket为Connect模式
  536.         return TRUE;//返回TRUE,设置成功
  537. }

  538. /*******************************************************************************
  539. * 函数名  : Socket_Listen
  540. * 描述    : 设置指定Socket(0~7)作为服务器等待远程主机的连接
  541. * 输入    : s:待设定的端口
  542. * 输出    : 无
  543. * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
  544. * 说明    : 当本机Socket工作在服务器模式时,引用该程序,等等远程主机的连接
  545. *                        该程序只调用一次,就使W5500设置为服务器模式
  546. *******************************************************************************/
  547. unsigned char Socket_Listen(SOCKET s)
  548. {
  549.         Write_W5500_SOCK_1Byte(s,Sn_MR,MR_TCP);//设置socket为TCP模式
  550.         Write_W5500_SOCK_1Byte(s,Sn_CR,OPEN);//打开Socket        
  551.         Delay_ms(5);//延时5ms
  552.         if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_INIT)//如果socket打开失败
  553.         {
  554.                 Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//打开不成功,关闭Socket
  555.                 return FALSE;//返回FALSE(0x00)
  556.         }        
  557.         Write_W5500_SOCK_1Byte(s,Sn_CR,LISTEN);//设置Socket为侦听模式        
  558.         Delay_ms(5);//延时5ms
  559.         if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_LISTEN)//如果socket设置失败
  560.         {
  561.                 Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//设置不成功,关闭Socket
  562.                 return FALSE;//返回FALSE(0x00)
  563.         }

  564.         return TRUE;

  565.         //至此完成了Socket的打开和设置侦听工作,至于远程客户端是否与它建立连接,则需要等待Socket中断,
  566.         //以判断Socket的连接是否成功。参考W5500数据手册的Socket中断状态
  567.         //在服务器侦听模式不需要设置目的IP和目的端口号
  568. }

  569. /*******************************************************************************
  570. * 函数名  : Socket_UDP
  571. * 描述    : 设置指定Socket(0~7)为UDP模式
  572. * 输入    : s:待设定的端口
  573. * 输出    : 无
  574. * 返回值  : 成功返回TRUE(0xFF),失败返回FALSE(0x00)
  575. * 说明    : 如果Socket工作在UDP模式,引用该程序,在UDP模式下,Socket通信不需要建立连接
  576. *                        该程序只调用一次,就使W5500设置为UDP模式
  577. *******************************************************************************/
  578. unsigned char Socket_UDP(SOCKET s)
  579. {
  580.         Write_W5500_SOCK_1Byte(s,Sn_MR,MR_UDP);//设置Socket为UDP模式*/
  581.         Write_W5500_SOCK_1Byte(s,Sn_CR,OPEN);//打开Socket*/
  582.         Delay_ms(5);//延时5ms
  583.         if(Read_W5500_SOCK_1Byte(s,Sn_SR)!=SOCK_UDP)//如果Socket打开失败
  584.         {
  585.                 Write_W5500_SOCK_1Byte(s,Sn_CR,CLOSE);//打开不成功,关闭Socket
  586.                 return FALSE;//返回FALSE(0x00)
  587.         }
  588.         else
  589.                 return TRUE;

  590.         //至此完成了Socket的打开和UDP模式设置,在这种模式下它不需要与远程主机建立连接
  591.         //因为Socket不需要建立连接,所以在发送数据前都可以设置目的主机IP和目的Socket的端口号
  592.         //如果目的主机IP和目的Socket的端口号是固定的,在运行过程中没有改变,那么也可以在这里设置
  593. }

  594. /*******************************************************************************
  595. * 函数名  : W5500_Interrupt_Process
  596. * 描述    : W5500中断处理程序框架
  597. * 输入    : 无
  598. * 输出    : 无
  599. * 返回值  : 无
  600. * 说明    : 无
  601. *******************************************************************************/
  602. void W5500_Interrupt_Process(void)
  603. {
  604.         unsigned char i,j;

  605. IntDispose:

  606.         i=Read_W5500_1Byte(SIR);//读取端口中断标志寄存器        
  607.         if((i & S0_INT) == S0_INT)//Socket0事件处理
  608.         {
  609.                 j=Read_W5500_SOCK_1Byte(0,Sn_IR);//读取Socket0中断标志寄存器
  610.                 Write_W5500_SOCK_1Byte(0,Sn_IR,j);
  611.                 if(j&IR_CON)//在TCP模式下,Socket0成功连接
  612.                 {
  613.                         S0_State|=S_CONN;//网络连接状态0x02,端口完成连接,可以正常传输数据
  614.                 }
  615.                 if(j&IR_DISCON)//在TCP模式下Socket断开连接处理
  616.                 {
  617.                         Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);//关闭端口,等待重新打开连接
  618.                         Socket_Init(0);                //指定Socket(0~7)初始化,初始化端口0
  619.                         S0_State=0;//网络连接状态0x00,端口连接失败
  620.                 }
  621.                 if(j&IR_SEND_OK)//Socket0数据发送完成,可以再次启动S_tx_process()函数发送数据
  622.                 {
  623.                         S0_Data|=S_TRANSMITOK;//端口发送一个数据包完成
  624.                 }
  625.                 if(j&IR_RECV)//Socket接收到数据,可以启动S_rx_process()函数
  626.                 {
  627.                         S0_Data|=S_RECEIVE;//端口接收到一个数据包
  628.                 }
  629.                 if(j&IR_TIMEOUT)//Socket连接或数据传输超时处理
  630.                 {
  631.                         Write_W5500_SOCK_1Byte(0,Sn_CR,CLOSE);// 关闭端口,等待重新打开连接                        
  632.                         S0_State=0;//网络连接状态0x00,端口连接失败
  633.                 }
  634.         }

  635.         if(Read_W5500_1Byte(SIR) != 0)
  636.                 goto IntDispose;
  637. }

效果图:
4.jpg
打开上位机,连接成功,下位机不停向上位机发数据。上位机往下位机发送字符1,另一个板子上的灯亮。
3.jpg 2.jpg
上位机向下位机发字符0,另一个板子灯灭。
0.jpg 1.jpg
您需要登录后才可以回帖 登录 | 注册

本版积分规则

470

主题

3537

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部