热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(转)USB小白学习之路(8)FX2LPcy7c68013——SlaveFIFO与FPGA通信

FX2LPcy7c68013——SlaveFIFO

此博客转自CSDN:http://blog.csdn.net/xx116213/article/details/50535682

1 USB 概述

USB名称解释 
USB是通用串行总线(Universal Serial Bus)的缩写。能过在计算机运行过程中随意地接入,并且立刻就能投入工作,那么这样的特性叫做即插即用PnP(Plug and Play)。由于USB是主从模式的结构,设备与设备之间、主机与主机之间不能互连。为了解决这个问题,出现了USB OTG(On the go),它的做法:同一个设备,在不同场合下可以在主机与从机之间切换。

USB系统组成 
usb系统的三个组成:Host、HUB和Device。

  • Host:主控器,能读写usb设备的设备。例如插有U盘的电脑,那么PC就是主控器。
  • HUB:扩充USB接口。
  • Device(USB Device):如硬盘、打印机、U盘等。

USB设备组成 
每一个USB设备由一个或多个配置来控制其行为,使用多配置原因是对操作系统的支持;一个配置是由接口(Interface)组成;接口则是由管道(Pipe)组成;管道是和USB设备的端点(Endpoint)对应,端点都是输入输出成对的。在固件编程中,USB设备、配置、接口和管道都来描述符来报告其属性。

一个端点(Endpoint)建立一个管道。管道的端点总是成对出现,即In Endpoint和Out Endpoint。端点0默认为控制管道,其它端点可以配置成数据管道。一个具体的端点,只能工作在一种传输模式下。

  • In Endpoint:由device向Host发送数据的端点。
  • Out Endpoint:由Host向device发送数据的端点。

USB传输速度 
USB1.0和USB1.1版本中,只支持1.5Mb/s的低速(low-speed)模式和12Mb/s的全速模式。在USB2.0种,又加入了速度更快(480Mb/s)的高速模式。而USB3.0的最大传输带宽高达5.0Gbps(625MB/s)。

USB可扩展设备 
USB1.1规定最多为4层,USB2.0规定最多为6层。理论上,一个USB主控制器最多可接127个设备,这是因为协议规定每个USB设备具有一个7 bit的地址(取值范围0~127),而地址0是保留给未初始化的设备使用。

USB传输类型 
虽然USB定义了数据在总线上传输的基本单位是包,但是我们还不能随意地使用包来传输数据,必须按照一定的关系把这些不同的包组织成事务才能传输数据。

事务通常由两个或者三个包组成:令牌包,数据包和握手包。

  • 令牌包用来启动一个事务,总是由主机发送。
  • 数据包传送数据,可以从主机到设备,也可以从设备到主机,方向由令牌包来制定。
  • 握手包的发送者通常为数据接收者,当数据接收正确后,发送握手包。设备也可以使用NAK握手包来表示数据还未准备好。

USB协议规定了4种传输类型:批量传输、等时传输(同步传输),中断传输和控制传输。其中,批量传输、等时传输、中断传输每传输一次数据都是一个事务;控制传输包括三个过程,建立过程和状态过程分别是一个事务,数据过程则可能包含多个事务。4种数据传输的相关特性(仅限USB1.1协议)如下表。

传输模式中断传输Interrupt批量传输Bulk等时传输ISO控制传输Control
传输速率/Mbps 12(1.5,低速) 12 12 1.5/12
数据的最大长度/Byte 1~64(1~8,低速) 8/16/32/64 1~1023 1~64(1~8,低速)
数据周期性 没有 没有
发送错误重传
应用设备 鼠标键盘 打印机 语音  
可得到的最大宽度/Mbps 6.762(0.051低速) 9.728 10.240  

批量传输使用批量事务传输数据。一个批量事务由三个阶段:令牌包阶段,数据包阶段和握手包阶段。每个阶段都是一个独立的包。批量传输通常用于数据量大,对数据的实时性要求不高的场合。

USB2.0 数据帧 
USB2.0和USB1.1规范的最大不同就是数据帧。在USB1.1规范中,USB数据采用每毫秒一个数据帧的方式进行数据传输,在毫秒数据帧的开始,USB主机首先产生帧开始(SOF)数据包,并传输当前数据帧号,后面是传输数据。对于USB2.0规范,为了支持480Mbps高速传输速度,USB2.0提出了微帧的概念,每毫秒数据帧又包含8个微帧。

USB2.0 端点缓冲区

传输类型USB1.1数据包大小USB2.0数据包大小
控制传输 8,16,32,64 64
批量传输 8,16,32,64 512
中断传输 1~64 1024
等时传输 1023 1024

2 CY7C68013与FPGA

官方资料AN61345 提供了一个示例项目,用以通过从设备 FIFO 接口将 FX2LP 连接至 FPGA。示例实现中描述的接口为各个应用执行高速度的 USB 连接事项,如数据采集、工业控制和监控以及图像处理。 
技术分享图片 
可以通过两个不同的模式将 FX2LP 连接至 FPGA。这两个模式分别为通用可编程接口( GPIF)模式和从设备 FIFO模式。

2.1 硬件连接

技术分享图片

引脚名称说明
SLRD SLRD 引脚应由主设备激活,用以从 FIFO 读取数据。
SLWR SLWR 引脚应该由主设备激活,以将数据写入到 FIFO 内。
SLOE 是指 FIFO 输出驱动器的使能信号。
FIFOADR[1:0] 这些信号用于选择有效的端点。
FD[15:0] 16 位数据总线
FLAGA/FLAGB/FLAGC/FLAGD FIFO 使用这些标志来表示各种状态(满、空、可编程)。
IFCLK 是指与从设备 FIFO 接口同步的时钟。在本应用笔记所提供的设计中,该时钟的频率被配置为 48 MHz,并由连接至 FX2LP 的 FPGA 生成。
CLKOUT FX2LP 的 CLKOUT 引脚可以提供的时钟频率分别为 12、 24 或 48 MHz

2.2 固件的实现

利用Cypress Suite USB提供的资源,在此基础上修改例程。 
FX2LP固件 
技术分享图片 
Fw.c 文件包含 main 函数。它执行了 USB 维持的大部分操作(如进行枚举),并且每当需要自定义时,它将调用应用代码( Slave.c)中特定名称的外部函数。一般情况下,不需要修改 Fw.c 文件。执行各个日常操作的步骤后,该函数将调用 Slave.c 所提供的外部函数,即 TD_init。(前缀TD 表示“任务调度” 。然后,它进入一个无限循环,以通过 CONTROL 端点 0 检查 SETUP 数据包的到来。该循环还会检查 USB 暂停事件,但从设备 FIFO 应用不会使用该循环。每次进入该循环时,该函数都将调用 Slave.c 文件中提供的外部函数 TD_Poll。 TD_Poll 函数用于同步化 FPGA 和 FX2LP 间所传输的数据。开始传输数据时,由于 FIFO 被配置为自动模式,因此该函数不会进行任何操作。

每个 USB 外设通过它们的 CONTROL 端点接收两个请求类型:枚举和操作。 
枚举 
当 与 USB 器 件 连 接 时 , 主 机 PC 将 发 送 多 个GET_DESCRIPTOR 请求以确定器件类型及其要求。这些操作属于枚举过程的一部分。 fw.c 代码截取这些请求,并通过使用 dscr.a51 文件中所存储的数值处理请求。 
操作 
需要用户代码时, fw.c 将调用一个带有特定名称前缀为 DR(器件请求)的外部函数(存储在 Slave.c 文件中)。对于从设备 FIFO 这种简单的应用,只会使用一个配置和一个借口。因此, 图 14 中所显示的两对 DR_Set-Get 函数只存储由主机发送的“ Set” 值,并在主机发出“ Get” 请求时对该值进行随路。对于更加复杂的配置,您可以使用这些 DR调用( “ hooks” )更改摄像机的分辨率或将请求路由到两个不同的接口等。 

固件代码

 1 #pragma NOIV                    // Do not generate interrupt vectors
 2 #include "fx2.h"
 3 #include "fx2regs.h"
 4 #include "fx2sdly.h"            // SYNCDELAY macro
 5 
 6 extern BOOL GotSUD;             // Received setup data flag
 7 extern BOOL Sleep;
 8 extern BOOL Rwuen;
 9 extern BOOL Selfpwr;
10 
11 BYTE Configuration;             // Current configuration
12 BYTE AlternateSetting;          // Alternate settings
13 
14 //-----------------------------------------------------------------------------
15 // Task Dispatcher hooks
16 //   The following hooks are called by the task dispatcher.
17 //-----------------------------------------------------------------------------
18 void TD_Init( void )
19 { // Called once at startup
20 
21   CPUCS = 0x10; // CLKSPD[1:0]=10, for 48MHz operation, output CLKOUT
22 
23   PINFLAGSAB = 0x08;            // FLAGA - EP2EF
24   SYNCDELAY;
25   PINFLAGSCD = 0x60;            // FLAGA - EP6PF
26   SYNCDELAY;
27   PORTACFG |= 0x80;
28   SYNCDELAY;
29   IFCOnFIG= 0xE3;             // for async? for sync?
30   SYNCDELAY;
31   CPUCS |= 0x02;
32 
33   // EP4 and EP8 are not used in this implementation...
34   EP2CFG = 0xA0;                //out 512 bytes, 4x, bulk
35   SYNCDELAY;                    
36   EP6CFG = 0xE0;                // in 512 bytes, 4x, bulk
37   SYNCDELAY;              
38   EP4CFG = 0x02;                //clear valid bit
39   SYNCDELAY;                     
40   EP8CFG = 0x02;                //clear valid bit
41   SYNCDELAY;   
42 
43   SYNCDELAY;
44   FIFORESET = 0x80;             // activate NAK-ALL to avoid race conditions
45   SYNCDELAY;                    // see TRM section 15.14
46   FIFORESET = 0x02;             // reset, FIFO 2
47   SYNCDELAY;                    // 
48   FIFORESET = 0x04;             // reset, FIFO 4
49   SYNCDELAY;                    // 
50   FIFORESET = 0x06;             // reset, FIFO 6
51   SYNCDELAY;                    // 
52   FIFORESET = 0x08;             // reset, FIFO 8
53   SYNCDELAY;                    // 
54   FIFORESET = 0x00;             // deactivate NAK-ALL
55 
56   // handle the case where we were already in AUTO mode...
57   // ...for example: back to back firmware downloads...
58   SYNCDELAY;                    // 
59   EP2FIFOCFG = 0x00;            // AUTOOUT=0, WORDWIDE=0
60 
61   // core needs to see AUTOOUT=0 to AUTOOUT=1 switch to arm endp‘s
62   SYNCDELAY;                    // 
63   EP2FIFOCFG = 0x11;            // AUTOOUT=1, WORDWIDE
64   SYNCDELAY;                    // 
65   EP6FIFOCFG = 0x0D;            // AUTOIN=1, ZEROLENIN=1, WORDWIDE=1
66   SYNCDELAY;
67 }
68 
69 void TD_Poll( void )
70 { // Called repeatedly while the device is idle
71 
72   // ...nothing to do... slave fifo‘s are in AUTO mode...
73 
74 }

TD_Init 
该函数执行以下操作:

  • 将 8051 时钟频率设置为 48 MHz。
1   CPUCS = 0x10;
2   ……
3   CPUCS |= 0x02;
  • 配置 FIFO 标志输出。 FLAGA 被配置为 EP2 OUTFIFO 的空标志, FLAGD 被配置为 EP6 IN FIFO可编程标志(官方的例程:配置为EP6 IN FIFO 的满标志)。
1   PINFLAGSAB = 0x08;            // FLAGA - EP2EF
2   SYNCDELAY;
3   PINFLAGSCD = 0x60;            // FLAGA - EP6PF
4   SYNCDELAY;
  • 对从设备 FIFO 接口进行配置,使之使用 48 MHz 大小的内部时钟。
1 IFCOnFIG= 0xE3;
  • 将 EP2 配置为 BULK-OUT 端点,并将 EP6 配置为BULK-IN 端点。该两个端点均为四倍缓冲,并使用512 字节的 FIFO。由于本设计中没有使用 EP4 和 EP8,所以它们均被取消激活。
1   EP2CFG = 0xA0;                //out 512 bytes, 4x, bulk
2   SYNCDELAY;                    
3   EP6CFG = 0xE0;                // in 512 bytes, 4x, bulk
4   SYNCDELAY;              
5   EP4CFG = 0x02;                //clear valid bit
6   SYNCDELAY;                     
7   EP8CFG = 0x02;                //clear valid bit
8   SYNCDELAY;
  • 复位 FIFO。
 1   FIFORESET = 0x80;             // activate NAK-ALL to avoid race conditions
 2   SYNCDELAY;                    // see TRM section 15.14
 3   FIFORESET = 0x02;             // reset, FIFO 2
 4   SYNCDELAY;                    // 
 5   FIFORESET = 0x04;             // reset, FIFO 4
 6   SYNCDELAY;                    // 
 7   FIFORESET = 0x06;             // reset, FIFO 6
 8   SYNCDELAY;                    // 
 9   FIFORESET = 0x08;             // reset, FIFO 8
10   SYNCDELAY;                    // 
11   FIFORESET = 0x00;             // deactivate NAK-ALL
12   SYNCDELAY; 
  • 分别将端点 2 FIFO 和端点 6 配置为自动输出模式和自动输入模式,同时使用 16 位接口。
1   EP2FIFOCFG = 0x00;            // AUTOOUT=0, WORDWIDE=0
2   // core needs to see AUTOOUT=0 to AUTOOUT=1 switch to arm endp‘s
3   SYNCDELAY;                    // 
4   EP2FIFOCFG = 0x11;            // AUTOOUT=1, WORDWIDE=1
5   SYNCDELAY;                    // 
6   EP6FIFOCFG = 0x0D;            // AUTOIN=1, ZEROLENIN=1, WORDWIDE=1
7   SYNCDELAY;

TD_Poll 
在 fw.c 文件的无限循环中调用了 TD_Poll。因为EP2和EP6配置为自动输出和输入模式,所以不必要添加代码进行手动操作。

2.3 FPGA代码

  1 library IEEE;
  2 use IEEE.STD_LOGIC_1164.ALL;      
  3 use IEEE.STD_LOGIC_ARITH.ALL;     
  4 use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5 
  6 entity fpga_master is
  7   Port (  
  8     fdata : inout  STD_LOGIC_VECTOR(15 downto 0);  --  FIFO data lines.
  9     faddr     : out STD_LOGIC_VECTOR(1 downto 0); --  FIFO select lines
 10     slrd      : out STD_LOGIC;                    -- Read control line
 11     slwr      : out STD_LOGIC;                    -- Write control line
 12     gstate    : out STD_LOGIC_VECTOR(3 downto 0); -- debug lines
 13 
 14 
 15     flagd     : in  STD_LOGIC;                    --EP6 full flag
 16     flaga     : in  STD_LOGIC;                    --EP2 empty flag
 17     clk       : in  STD_LOGIC;                    --Interface Clock
 18     sloe      : out STD_LOGIC                     --Slave Output Enable control 
 19   );
 20 end fpga_master;
 21 
 22 architecture rtl of fpga_master is
 23 
 24 signal faddr_i    : STD_LOGIC_VECTOR(1 downto 0);  
 25 
 26 signal slrd_i     : STD_LOGIC;
 27 signal slwr_i     : STD_LOGIC;
 28 
 29 signal gstate_i : STD_LOGIC_VECTOR(3 downto 0);
 30 
 31 signal MasterState : STD_LOGIC_VECTOR(3 downto 0);   -- Counter to sequence the fifo signals.
 32 
 33 signal sloe_i : STD_LOGIC;
 34 
 35 shared variable cnt : integer range 0 to 9 := 0 ;
 36 
 37 CONSTANT A: STD_LOGIC_VECTOR (3 DownTo 0) := "0000";
 38 CONSTANT B: STD_LOGIC_VECTOR (3 DownTo 0) := "0001";
 39 CONSTANT C: STD_LOGIC_VECTOR (3 DownTo 0) := "0010";
 40 CONSTANT D: STD_LOGIC_VECTOR (3 DownTo 0) := "0011";
 41 CONSTANT E: STD_LOGIC_VECTOR (3 DownTo 0) := "0100";
 42 CONSTANT F: STD_LOGIC_VECTOR (3 DownTo 0) := "0101";
 43 CONSTANT G: STD_LOGIC_VECTOR (3 DownTo 0) := "0110";
 44 CONSTANT H: STD_LOGIC_VECTOR (3 DownTo 0) := "0111";  
 45 begin
 46 
 47     slrd    <= slrd_i;
 48     slwr    <= slwr_i;
 49     faddr <= faddr_i;
 50     gstate<= gstate_i;
 51     sloe    <= sloe_i;
 52 
 53 
 54 process(clk)
 55 
 56 variable fdatawe : natural := 0;
 57 variable fifodatabyte : STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000";  -- Local for now.
 58 
 59 begin
 60     if(rising_edge(clk)) then
 61 
 62         case MasterState(3 downto 0) is
 63 
 64             when A =>  -- IDLE STATE   
 65 
 66                 sloe_i <= 1;                         
 67                 faddr_i <= "10";        
 68                 slrd_i  <= 1;
 69                 slwr_i  <= 1;
 70                 MasterState <= E;
 71                 fdatawe := 0;
 72                 gstate_i <= "0001";
 73 
 74             when E =>   
 75 
 76                 faddr_i <= "10";
 77                 slrd_i  <= 1;
 78                 sloe_i <= 1;
 79                 if (flagd = 1)   then                 -- if Full flag is in a deasserted state 
 80                     slwr_i  <= 0;                         --assert slave write control signal
 81                     fdatawe := 0 ;
 82                     fdata <= fifodatabyte;  
 83                     fifodatabyte := fifodatabyte + 1;   
 84                     MasterState <= E;                       -- stay in state E 
 85                 else
 86                     slwr_i  <= 1; 
 87                     MasterState <= A;                         --when Full flag gets asserted, move to state A 
 88 
 89                 end if;
 90 
 91                 gstate_i <= "0110";  
 92 
 93             when others =>--if an undefined state move to IDLE
 94 
 95                 faddr_i <= "00";
 96 
 97                 slrd_i  <= 1;                         
 98                 sloe_i <= 1;
 99                 slwr_i  <= 1;
100 
101                 gstate_i <= "1000";  
102                 MasterState <= A;
103         end case;
104     end if;
105 end process;
106 end rtl;

3 总结

CYPRESS提供了FX2LP的固件框架,使得固件开发只需修改TD_Init和TD_Poll(如果采用中断,那就修改中断函数)两个函数即可,大大缩短了开发时间。

(转)USB小白学习之路(8)FX2LP cy7c68013——Slave FIFO 与FPGA通信


推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • php支持中文文件名
    2019独角兽企业重金招聘Python工程师标准大家可能遇到过上传中文文件名的文件,或者读取中文目录时不能读取,出现错误的情况这种情况是因为php自动将中文字符转成了utf8 ... [详细]
  • 阿里云虚拟主机安装多个织梦系统的方法
    本文介绍了在阿里云虚拟主机上安装多个织梦系统的方法。通过创建不同名称的文件夹并将不同的域名解析到对应的目录,可以实现多个系统的安装。在安装过程中需要注意修改数据库前缀,并在系统设置中还原数据库。同时还介绍了阿里云虚拟主机二级域名绑定二级目录和域名重定向的用法。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • MVC设计模式的介绍和演化过程
    本文介绍了MVC设计模式的基本概念和原理,以及在实际项目中的演化过程。通过分离视图、模型和控制器,实现了代码的解耦和重用,提高了项目的可维护性和可扩展性。详细讲解了分离视图、分离模型和分离控制器的具体步骤和规则,以及它们在项目中的应用。同时,还介绍了基础模型的封装和控制器的命名规则。该文章适合对MVC设计模式感兴趣的读者阅读和学习。 ... [详细]
author-avatar
呼吸乱了的声音_648
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有