当前位置: 首页 > news >正文

西安网站开发建设wordpress首页摘要

西安网站开发建设,wordpress首页摘要,响应式网站建设机构,萝岗企业网站建设EEPROM 简介 EEPROM (Electrically Erasable Progammable Read Only Memory#xff0c;E2PROM)即电可擦除可编程只读存储器#xff0c;是一种常用的非易失性存储器#xff08;掉电数据不丢失#xff09;#xff0c;EEPROM 有多种类型的产品#xff0c;此次实验使用的是A…EEPROM 简介 EEPROM (Electrically Erasable Progammable Read Only MemoryE2PROM)即电可擦除可编程只读存储器是一种常用的非易失性存储器掉电数据不丢失EEPROM 有多种类型的产品此次实验使用的是ATMEL 公司生产的 AT24C 系列的 AT24C64 这一型号。AT24C64 具有高可靠性可对所存数据保存 100 年并可多次擦写擦写次数达一百万次。 AT24C64 采用两线串行接口的双向数据传输协议——I2C 协议实现读写操作其存储容量为 64Kbit内部分成 256 页每页 32 字节共有 8192 个字节且其读写操作都是以字节为基本单位写入的数据是先写入到缓存中需要等一段时间才会同步到ROM中可以通过发设备地址来确认同步是否完成完成后会响应ACK否则响应NAK对于 AT24C64 其缓存大小为 32B 因此一次可写入的最大长度为 32 字节。 I2C 协议解析 I2C 即 Inter-Integrated Circuit(集成电路总线是由 Philips 半导体公司现在的 NXP 半导体公司在八十年代初设计出来的一种简单、双向、二线制总线标准多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。 在物理层上I2C 接口只需要两条总线线路即 SCL串行时钟线、SDA串行数据线I2C 总线是半双工的所以任意时刻只能有一个主机。每个连接在总线上的 I2C 器件都有一个唯一的器件地址在通信的时候就是靠这个地址来通信的。I2C 传输速率标准模式下可以达到 100kb/s快速模式下可以达到 400kb/s高速模式下可达 3.4Mbit/s。总线上的主设备与从设备之间以字节(8 位)为单位进行双向的数据传输。 I2C 总线上的每一个设备都可以作为主设备或者从设备但同一时刻最多只能有一个主设备且每一个从设备都会对应一个唯一的地址(可以从 I2C 器件数据手册得知)主从设备之间就是通过这个地址来确定与哪个器件进行通信。通常情况下主从器件的角色是确定的也就是说从机一直工作在从机模式如下是常见的 I2C总线物理拓扑结构图。 I2C 协议规定 在时钟SCL为高电平的时候数据总线SDA必须保持稳定所以数据总线SDA在时钟SCL为低电平的时候才能改变。 在时钟SCL为高电平的时候数据总线SDA由高到低的跳变为总线起始信号在时钟SCL为高电平的时候数据总线SDA由低到高的跳变为总线停止信号 当传输器件将 8 位数据输出完后会将数据总线SDA释放即设置为输入然后等待接收器件应答低电平 0 表示应答1 表示非应答此时的时钟仍然是主机提供的。 I2C 器件地址 每个 I2C 器件都有一个器件地址有些 I2C 器件的器件地址是固定的而有些 I2C 器件的器件地址由一个固定部分和一个可编程的部分构成这是因为很可能在一个系统中有几个同样的器件器件地址的可编程部分能最大数量的使这些器件连接到 I2C 总线上例如 EEPROM 器件为了增加系统的 EEPROM 容量可能需要多个 EEPROM。器件可编程地址位一般由它管脚决定比如 EEPROM 器件一般会留下 3 个管脚用于设置可编程地址位。但有些 I2C 器件在出厂时器件地址就设置好了用户不可以更改如实时时钟 PCF8563 的器件地址为固定的 7’h51。 对于 AT24C64 而言其器件地址为 1010 加 3 位的可编程地址3 位可编程地址由器件上的 3 个管脚A2、A1、A0见图 31.2.2的硬件连接决定。当硬件电路上分别将这三个管脚连接到 GND 或 VCC 时就可以设置不同的可编程地址。 进行数据传输时主机首先向总线上发出开始信号对应开始位 S然后按照从高到低的位序发送器件地址一般为 7bit第 8bit 位为读写控制位 R/W该位为 0 时表示主机对从机进行写操作当该位为 1时表示主机对从机进行读操作然后接收从机响应。对于 AT24C64 来说其传输器件地址格式如下图所示。 I2C 存储器地址 一般而言每个兼容 I2C 协议的器件内部总会有可供读写的寄存器或存储器例如EEPROM 存储器内部就是顺序编址的一系列存储单元型号为 OV7670 的 CMOS 摄像头OV7670 的该接口叫 SCCB 接口其实质也是一种特殊的 I2C 协议可以直接兼容 I2C 协议其内部就是一系列编址的可供读写的寄存器。因此要对一个 I2C 器件中的存储单元包括寄存器和存储器进行读写时必须要先指定存储单元的地址。该地址为一个或两个字节长度具体长度由器件内部的存储单元的数量决定当存储单元数量不超过一个字节所能表示的最大数量256时用一个字节表示超过一个字节所能表示的最大数量时就需要用两个字节来表示例如同是 E2PROM 存储器AT24C02 的存储单元容量为 2Kbit256Byte用一个字节地址即可寻址所有的存储单元而 AT24C64 的存储单元容量为64Kb8KB需要 13 位的地址位而 I2C 又是以字节为单位进行传输的所以需要用两个字节地址来寻址整个存储单元。 I2C 单字节写时序 下图分别是 1 字节存储器地址器件和 2 字节存储器地址器件单字节写时序图 单字节存储器地址写单字节数据过程 主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输 1 字节地址数据主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输待写入的数据设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机产生 STOP 位终止传输。 双字节存储器地址写单字节数据过程主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据高字节主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据低字节设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输待写入的数据设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机产生 STOP 位终止传输。 I2C 连续写时序 注意 I2C 连续写时序仅部分器件支持 连续写是主机连续写多个字节数据到从机这个和单字节写操作类似连续多字节写操作也是分为 1 字节存储器地址器件和 2 字节存储器地址器件的写操作下图分别是 1 字节存储器地址器件和 2 字节存储器地址器件的连续写时序图 单字节存储器地址器件连续多字节写数据过程 主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输 1 字节地址数据主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输待写入的第 1 个数据设置 SDA 为三态门输入读取从机应答信号读取应答信号成功后主机设置 SDA 为输出传输待写入的下一个数据设置 SDA 为三态门输入读取从机应答信号n 个数据被写完转到步骤 11若数据未被写完转到步骤 9读取应答信号成功主机产生 STOP 位终止传输。 双字节存储器地址器件连续多字节写数据过程主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据高字节主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据低字节设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输待写入的第 1 个数据设置 SDA 为三态门输入读取从机应答信号读取应答信号成功后主机设置 SDA 为输出传输待写入的下一个数据设置 SDA 为三态门输入读取从机应答信号n 个数据被写完转到步骤 13若数据未被写完转到步骤 11读取应答信号成功主机产生 STOP 位终止传输。 I2C 单字节读时序 单字节读操作分为 1 字节存储器地址器件单字节数据读操作和 2 字节存储器地址器件单字节数据读操作。下图分别为不同情况的时序图 单字节存储器地址读取单字节数据过程 主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输 1 字节地址数据主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机发起起始信号主机传输器件地址字节其中最低位为 1表明为读操作设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为三态门输入读取 SDA 总线上的一个字节的数据产生无应答信号高电平无需设置为输出高电平因为总线会被自动拉高主机产生 STOP 位终止传输。 双字节存储器地址读取单字节数据过程主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据高字节主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据低字节设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机发起起始信号主机传输器件地址字节其中最低位为 1表明为读操作设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为三态门输入读取 SDA 总线上的一个字节的数据主机设置 SDA 输出产生无应答信号高电平无需设置为输出高电平因为总线会被自动拉高主机产生 STOP 位终止传输 I2C 连续读时序 连续读是主机连续从从机读取多个字节数据这个和单字节读操作类似连续多字节读操作也是分为 1 字节存储器地址器件和 2 字节存储器地址器件的读操作下图分别为字节存储器地址器件和 2 字节存储器地址器件连续多字节读的时序图。 单字节存储器地址器件连续多字节读取数据过程 主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输 1 字节地址数据主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机发起起始信号主机传输器件地址字节其中最低位为 1表明为读操作设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为三态门输入读取 SDA 总线上的第 1 个字节的数据主机设置 SDA 输出发送一位应答信号设置 SDA 为三态门输入读取 SDA 总线上的下一个字节的数据若 n 个字节数据读完成跳转到步骤 13若数据未读完跳转到步骤 11主机设置 SDA 输出产生无应答信号高电平无需设置为输出高电平因为总线会被自动拉高主机产生 STOP 位终止传输。 双字节存储器地址器件连续多字节读取数据过程主机设置 SDA 为输出主机发起起始信号主机传输器件地址字节其中最低位为 0表明为写操作主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据高字节主机设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为输出传输地址数据低字节设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机发起起始信号主机传输器件地址字节其中最低位为 1表明为读操作设置 SDA 为三态门输入读取从机应答信号读取应答信号成功主机设置 SDA 为三态门输入读取 SDA 总线上的第 1 个字节的数据主机设置 SDA 输出发送一位应答信号设置 SDA 为三态门输入读取 SDA 总线上的下一个字节的数据若 n 个字节数据读完成跳转到步骤 15若数据未读完跳转到步骤 13主机设置 SDA 输出产生无应答信号高电平无需设置为输出高电平因为总线会被自动拉高主机产生 STOP 位终止传输。 I2C 控制器功能拆分 通过前面的读写时序可以发现每次读写过程都可以由开始、发送包括读取对方应答、接收包括回复对方应答、停止这 4 过个操作组合而来因此 I2C 控制器只需要实现这 4 个操作即可三层模块提供 I2C 控制其提供的这 4 中操作即可完成 I2C 从设备的读写。 EEPROM 原理图 代码编写 代码一共分为3个模块分别是 I2C 驱动模块、EEPROM 驱动模块、EEPROM 读写测试模块其功能如下 I2C 驱动模块提供 I2C 总线收发数据的功能生成模块可以提供此模块在总线上测试起始和结束信号并进行数据收发。 EEPROM 驱动模块基于 I2C驱动模块实现 EEPROM 的一些基本操作如读、写等。 EEPROM 读写测试模块利用 EEPROM 驱动模块提供的 EEPROM 基本操作进行读、写测试测试过程中状态 LED 常灭测试出错状态 LED闪烁测试完成状态 LED 常亮。 I2C 驱动模块 module i2c_driver #(parameter I2C_CLK_PERIOD 125 //I2C时钟周期以系统时钟为参考 ) (input sys_rst_n, //系统复位input sys_clk, //系统时钟input [7:0] ctrl_cmd, //i2c控制命令input ctrl_start, //i2c控制器启动信号output ctrl_idle, //i2c控制器空闲信号output reg ctrl_done, //i2c控制器完成信号input [7:0] tx_data, //需要发送的数据output reg tx_ack, //数据发送完成后从设备返回的应答output reg [7:0] rx_data, //接收到的数据input rx_ack, //数据接收完成后响应给从机的应答output reg i2c_scl, //i2c时钟输出output reg i2c_sda_o, //i2c数据输出input i2c_sda_i, //i2c数据输入output reg i2c_sda_t //i2c数据方向控制1输入0输出 );//时钟周期的一半 localparam I2C_CLK_PERIOD_HALF I2C_CLK_PERIOD / 2;//状态机的状态 localparam IDLE_STATE 8b0000001; //空闲状态 localparam GEN_STA_STATE 8b0000010; //产生起始信号 localparam WR_DATA_STATE 8b0000100; //写数据状态写完8bit后还要读ACK localparam RD_DATA_STATE 8b0001000; //读数据状态读完8bit后还要生成ACK localparam GEN_STO_STATE 8b0010000; //产生停止信号//指令集 localparam GEN_STA_CMD 7b0000010; //产生起始信号 localparam WR_DATA_CMD 7b0000100; //写数据状态写完8bit后还要读ACK localparam RD_DATA_CMD 7b0001000; //读数据状态读完8bit后还要生成ACK localparam GEN_STO_CMD 7b0010000; //产生停止信号//I2C时钟周期计数器 reg [32:0] clk_period_count;//传输bit计数 reg [7:0] bit_cnt;//发送移位寄存器 reg [7:0] tx_data_reg; //从机响应的ACK reg tx_ack_reg;//接收移位寄存器 reg [7:0] rx_data_reg; //发送给从机的ACK reg rx_ack_reg;//上一刻的状态 reg [7:0] prev_state; //当前状态 reg [7:0] current_state; //下一刻的状态 reg [7:0] next_state; //当前状态结束标志切换到下一个状态 reg state_done;//I2C总线空闲标志 reg bus_idle_flag;//记录上一时刻的状态 //状态跳转 always (posedge sys_clk) beginif(!sys_rst_n) beginprev_state IDLE_STATE;current_state IDLE_STATE;endelse beginprev_state current_state;current_state next_state;end end//根据当前状态确定下一刻状态 always (*) begincase(current_state)IDLE_STATE: beginif((state_done 1b0) (ctrl_start 1b1) (ctrl_cmd GEN_STA_CMD))next_state GEN_STA_STATE;else if((state_done 1b0) (ctrl_start 1b1) (ctrl_cmd WR_DATA_CMD))next_state WR_DATA_STATE;else if((state_done 1b0) (ctrl_start 1b1) (ctrl_cmd RD_DATA_CMD))next_state RD_DATA_STATE;else if((state_done 1b0) (ctrl_start 1b1) (ctrl_cmd GEN_STO_CMD))next_state GEN_STO_STATE;elsenext_state IDLE_STATE;endGEN_STA_STATE: beginif(state_done 1b1)next_state IDLE_STATE;elsenext_state GEN_STA_STATE;endWR_DATA_STATE: beginif(state_done 1b1)next_state IDLE_STATE;elsenext_state WR_DATA_STATE;endRD_DATA_STATE: beginif(state_done 1b1)next_state IDLE_STATE;elsenext_state RD_DATA_STATE;endGEN_STO_STATE: beginif(state_done 1b1)next_state IDLE_STATE;elsenext_state GEN_STO_STATE;enddefault: beginnext_state IDLE_STATE;endendcase end//进行时钟周期计数 always (posedge sys_clk) beginif(!sys_rst_n)clk_period_count 32b0;else begincase(current_state)IDLE_STATE: beginclk_period_count 32b0;endGEN_STA_STATE, WR_DATA_STATE, RD_DATA_STATE, GEN_STO_STATE: begin//产生启动信号按I2C_CLK_PERIOD进行计数//发送数据发送完成后读取ACK按I2C_CLK_PERIOD进行计数//接收数据接收完成后生成ACK按I2C_CLK_PERIOD进行计数//产生停止信号按I2C_CLK_PERIOD进行计数if(state_done 1b0) beginif(clk_period_count (I2C_CLK_PERIOD - 1))clk_period_count clk_period_count 32b1;elseclk_period_count 32b0;endenddefault: beginclk_period_count 32b0;endendcaseend end//进行传输bit计数 always (posedge sys_clk) beginif(!sys_rst_n)bit_cnt 8b0;else begincase(current_state)IDLE_STATE: beginbit_cnt 8b0;endGEN_STA_STATE, GEN_STO_STATE: begin//产生开始信号和停止信号时第一个时钟周期用于将IO设置为初始状态低二个时钟周期输出开始或结束信号if(clk_period_count (I2C_CLK_PERIOD - 1)) beginif(bit_cnt (2 - 1))bit_cnt bit_cnt 8b1;endendWR_DATA_STATE, RD_DATA_STATE: begin//发送数据8bit数据加1bit应答//接收数据8bit数据加1bit应答if(clk_period_count (I2C_CLK_PERIOD - 1)) beginif(bit_cnt (9 - 1))bit_cnt bit_cnt 8b1;endenddefault: beginbit_cnt 8b0;endendcaseend end//锁存需要发送的数据 always (posedge sys_clk) beginif(!sys_rst_n) begintx_data_reg 8b0;rx_ack_reg 1b0;endelse if(current_state IDLE_STATE) begin//暂存需要发送的数据if(next_state WR_DATA_STATE)tx_data_reg tx_data;//暂存需要发送的ACKif(next_state RD_DATA_STATE)rx_ack_reg rx_ack;end end//控制数据传输 always (posedge sys_clk) beginif(!sys_rst_n) beginbus_idle_flag 1b1;i2c_scl 1b1;i2c_sda_o 1b1;i2c_sda_t 1b1;tx_ack_reg 1b0;rx_data_reg 8b0;state_done 1b0;endelse begincase(current_state)IDLE_STATE: beginif(bus_idle_flag 1b1) begini2c_scl 1b1;i2c_sda_o 1b1;i2c_sda_t 1b1;tx_ack_reg 1b0;rx_data_reg 8b0;endstate_done 1b0;endGEN_STA_STATE: beginif(state_done 1b0) begin//设置总线为忙if((bit_cnt 0) (clk_period_count 0))bus_idle_flag 1b0;//第一个时钟周期SCL和SDA均输出高进入准备状态//第二个时钟周期SCL保持高SDA前半个周期为高后半个周期为低产生开始信号if(bit_cnt (2 - 2)) begin//SCL为高i2c_scl 1b1;//SDA为输出i2c_sda_t 1b0;//SDA为输出高i2c_sda_o 1b1;endelse begin//SCL为高i2c_scl 1b1;//SDA为输出i2c_sda_t 1b0;//前半个周期SDA为高后半个周期SDA为低if(clk_period_count (I2C_CLK_PERIOD_HALF - 1)) i2c_sda_o 1b1;elsei2c_sda_o 1b0;end//启动信号结束if((bit_cnt (2 - 1)) (clk_period_count (I2C_CLK_PERIOD - 1)))state_done 1b1;endendWR_DATA_STATE: beginif(state_done 1b0) beginif(bus_idle_flag 1b0) beginif(bit_cnt (9 - 2)) begin//写8bit数据//SDA为输出i2c_sda_t 1b0;//SDA输出数据寄存器中的值i2c_sda_o tx_data_reg[7 - bit_cnt];//前半个周期SCL为低后半个周期SCL为高if(clk_period_count (I2C_CLK_PERIOD_HALF - 1)) i2c_scl 1b0;elsei2c_scl 1b1;endelse begin//读从机应答//SDA为输入i2c_sda_t 1b1;//前半个周期SCL为低后半个周期SCL为高if(clk_period_count (I2C_CLK_PERIOD_HALF - 1))i2c_scl 1b0;elsei2c_scl 1b1;//在时钟周期3/4处采样SDA输入if(clk_period_count (I2C_CLK_PERIOD - I2C_CLK_PERIOD / 4 - 1))tx_ack_reg i2c_sda_i;end//写操作结束if((bit_cnt (9 - 1)) (clk_period_count (I2C_CLK_PERIOD - 1)))state_done 1b1;endelsestate_done 1b1;endendRD_DATA_STATE: beginif(state_done 1b0) beginif(bus_idle_flag 1b0) beginif(bit_cnt (9 - 2)) begin//读8bit数据//SDA为输入i2c_sda_t 1b1;//前半个周期SCL为低后半个周期SCL为高if(clk_period_count (I2C_CLK_PERIOD_HALF - 1))i2c_scl 1b0;elsei2c_scl 1b1;//在时钟周期3/4处采样SDA输入if(clk_period_count (I2C_CLK_PERIOD - I2C_CLK_PERIOD / 4 - 1))rx_data_reg[7 - bit_cnt] i2c_sda_i;endelse begin//写从机应答//SDA为输出i2c_sda_t 1b0;//SDA输出应答i2c_sda_o rx_ack_reg;//前半个周期SCL为低后半个周期SCL为高if(clk_period_count (I2C_CLK_PERIOD_HALF - 1)) i2c_scl 1b0;elsei2c_scl 1b1;end//读操作结束if((bit_cnt (9 - 1)) (clk_period_count (I2C_CLK_PERIOD - 1))) state_done 1b1;endelsestate_done 1b1;endendGEN_STO_STATE: beginif(state_done 1b0) begin//第一个时钟周期SCL和SDA均输出低进入准备状态//第二个时钟周期SCL保持高SDA前半个周期为低后半个周期为高产生停止信号if(bit_cnt (2 - 2)) begin//SCL为低i2c_scl 1b0;//SDA为输出i2c_sda_t 1b0;//SDA为输出低i2c_sda_o 1b0;endelse begin//SCL为高i2c_scl 1b1;//SDA为输出i2c_sda_t 1b0;//前半个周期SDA为低后半个周期SDA为高if(clk_period_count (I2C_CLK_PERIOD_HALF - 1)) i2c_sda_o 1b0;elsei2c_sda_o 1b1;end//停止信号结束if((bit_cnt (2 - 1)) (clk_period_count (I2C_CLK_PERIOD - 1)))state_done 1b1;//设置总线为空闲if((bit_cnt (2 - 1)) (clk_period_count (I2C_CLK_PERIOD - 1)))bus_idle_flag 1b1;endenddefault: beginif(bus_idle_flag 1b1) begini2c_scl 1b1;i2c_sda_o 1b1;i2c_sda_t 1b1;tx_ack_reg 1b0;rx_data_reg 8b0;endstate_done 1b0;endendcaseend end//输出完成信号和数据 always (posedge sys_clk) beginif(!sys_rst_n) beginctrl_done 1b0;tx_ack 1b0;rx_data 8b0;endelse begincase(current_state)IDLE_STATE: beginif(prev_state ! IDLE_STATE) beginctrl_done 1b1;tx_ack tx_ack_reg;rx_data rx_data_reg;endelsectrl_done 1b0;enddefault: beginctrl_done 1b0;endendcaseend end//空闲标志输出 assign ctrl_idle ((current_state IDLE_STATE) (state_done 1b0) (sys_rst_n 1b1)) ? 1b1 : 1b0;endmoduleEEPROM 读写控制模块 module eeprom_driver #(parameter I2C_CLK_PERIOD 125, //I2C时钟周期以系统时钟为参考parameter EEPROM_MEM_ADDR_BYTES 2 //内存地址字节数 ) (input sys_rst_n, //系统复位input sys_clk, //系统时钟input eeprom_start, //启动信号input [7:0] eeprom_cmd, //操作命令input [6:0] slave_addr, //从机地址input [15:0] mem_addr, //操作的存储器地址input [7:0] wr_data_len, //写入长度input [7:0] wr_data, //需要写入的数据output reg wr_data_req, //写入数据请求input [7:0] rd_data_len, //读取长度output [7:0] rd_data, //读取到的数据output rd_data_flag, //读取输出标志output eeprom_idle, //空闲标志output reg eeprom_error_flag, //EEPROM错误标志output i2c_scl, //i2c时钟输出output i2c_sda_o, //i2c数据输出input i2c_sda_i, //i2c数据输入output i2c_sda_t //i2c数据方向控制1输入0输出 );//状态机的状态 localparam IDLE_STATE 8h01; //空闲状态 localparam READ_STATE 8h02; //读状态 localparam WRITE_STATE 8h04; //写状态//EEPROM操作命令 localparam READ_CMD 8h02; //读命令 localparam WRITE_CMD 8h04; //写命令//i2c指令集 localparam GEN_STA_CMD 7b0000010; //产生起始信号 localparam WR_DATA_CMD 7b0000100; //写数据状态写完8bit后还要读ACK localparam RD_DATA_CMD 7b0001000; //读数据状态读完8bit后还要生成ACK localparam GEN_STO_CMD 7b0010000; //产生停止信号//当前状态 reg [7:0] current_state; //下一刻的状态 reg [7:0] next_state; //当前状态结束标志切换到下一个状态 reg state_done;//I2C操作启动计数 reg [7:0] i2c_opt_begin_count; //I2C操作完成计数 reg [7:0] i2c_opt_end_count; //I2C错误处理启动计数 reg [7:0] i2c_error_begin_count; //I2C错误处理完成计数 reg [7:0] i2c_error_end_count;//i2c控制命令 reg [7:0] i2c_ctrl_cmd; //i2c控制器启动信号 reg i2c_ctrl_start; //i2c控制器空闲信号 wire i2c_ctrl_idle; //i2c控制器完成信号 wire i2c_ctrl_done;//I2C总线发送的数据 reg [7:0] i2c_tx_data; //数据发送完成后从设备返回的应答 wire i2c_tx_ack;//I2C总线接收到的数据 wire [7:0] i2c_rx_data; //数据接收完成后发送给从设备的应答 reg i2c_rx_ack;//状态跳转 always (posedge sys_clk) beginif(!sys_rst_n)current_state IDLE_STATE;elsecurrent_state next_state; end//根据当前状态确定下一刻状态 always (*) begincase(current_state)IDLE_STATE: beginif((state_done 1b0) (eeprom_start 1b1) (eeprom_cmd READ_CMD))next_state READ_STATE;else if((state_done 1b0) (eeprom_start 1b1) (eeprom_cmd WRITE_CMD))next_state WRITE_STATE;elsenext_state IDLE_STATE;endREAD_STATE: beginif(state_done 1b1)next_state IDLE_STATE;elsenext_state READ_STATE;endWRITE_STATE: beginif(state_done 1b1)next_state IDLE_STATE;elsenext_state WRITE_STATE;enddefault:next_state IDLE_STATE;endcase end//空闲标志输出 assign eeprom_idle ((current_state IDLE_STATE) (state_done 1b0)) ? 1b1 : 1b0;//控制I2C传输 always (posedge sys_clk) beginif(!sys_rst_n) begini2c_ctrl_cmd 8b0;i2c_ctrl_start 1b0;i2c_tx_data 8b0;i2c_rx_ack 1b0;endelse begincase(current_state)IDLE_STATE: begini2c_ctrl_cmd 8b0;i2c_ctrl_start 1b0;i2c_tx_data 8b0;i2c_rx_ack 1b0;endREAD_STATE: beginif(state_done 1b0) beginif((i2c_tx_ack 1b0) (eeprom_error_flag 1b0)) begin//发送状态回复ACKif((i2c_ctrl_idle 1b1) (i2c_ctrl_start 1b0)) begin//产生开始信号if(i2c_opt_begin_count 0) begini2c_ctrl_cmd GEN_STA_CMD;i2c_ctrl_start 1b1;end//发送设备地址写标志if(i2c_opt_begin_count 1) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data {slave_addr, 1b0};i2c_ctrl_start 1b1;end//发送内存地址if(EEPROM_MEM_ADDR_BYTES 2) begin//发送内存地址高字节if(i2c_opt_begin_count 2) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data mem_addr[15:8];i2c_ctrl_start 1b1;end//发送内存地址低字节if(i2c_opt_begin_count 3) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data mem_addr[7:0];i2c_ctrl_start 1b1;endendelse begin//发送内存地址if(i2c_opt_begin_count 2) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data mem_addr[7:0];i2c_ctrl_start 1b1;endend//产生停止信号if(i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 2)) begini2c_ctrl_cmd GEN_STO_CMD;i2c_ctrl_start 1b1;end//再次产生开始信号if(i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 3)) begini2c_ctrl_cmd GEN_STA_CMD;i2c_ctrl_start 1b1;end//发送设备地址读标志if(i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 4)) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data {slave_addr, 1b1};i2c_ctrl_start 1b1;end//读数据if((i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 5)) (i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 5 rd_data_len))) begini2c_ctrl_cmd RD_DATA_CMD;//控制输出给从机的应答信号读取最后byte时输出NAKif(i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 5 rd_data_len - 1))i2c_rx_ack 1b0;elsei2c_rx_ack 1b1;i2c_ctrl_start 1b1;end//产生停止信号if(i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 5 rd_data_len)) begini2c_ctrl_cmd GEN_STO_CMD;i2c_ctrl_start 1b1;endendelse if(i2c_ctrl_idle 1b0)i2c_ctrl_start 1b0;endelse begin//发送状态回复NCKif((i2c_ctrl_idle 1b1) (i2c_ctrl_start 1b0)) begin//产生停止信号if(i2c_error_begin_count 0) begini2c_ctrl_cmd GEN_STO_CMD;i2c_ctrl_start 1b1;endendelse if(i2c_ctrl_idle 1b0)i2c_ctrl_start 1b0;endendendWRITE_STATE: beginif(state_done 1b0) beginif((i2c_tx_ack 1b0) (eeprom_error_flag 1b0)) begin//发送状态回复ACKif((i2c_ctrl_idle 1b1) (i2c_ctrl_start 1b0)) begin//产生开始信号if(i2c_opt_begin_count 0) begini2c_ctrl_cmd GEN_STA_CMD;i2c_ctrl_start 1b1;end//发送设备地址写标志if(i2c_opt_begin_count 1) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data {slave_addr, 1b0};i2c_ctrl_start 1b1;end//发送内存地址if(EEPROM_MEM_ADDR_BYTES 2) begin//发送内存地址高字节if(i2c_opt_begin_count 2) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data mem_addr[15:8];i2c_ctrl_start 1b1;end//发送内存地址低字节if(i2c_opt_begin_count 3) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data mem_addr[7:0];i2c_ctrl_start 1b1;endendelse begin//发送内存地址if(i2c_opt_begin_count 2) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data mem_addr[7:0];i2c_ctrl_start 1b1;endend//写数据if((i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 2)) (i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 2 wr_data_len))) begini2c_ctrl_cmd WR_DATA_CMD;i2c_tx_data wr_data;i2c_ctrl_start 1b1;end//产生停止信号if(i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 2 wr_data_len)) begini2c_ctrl_cmd GEN_STO_CMD;i2c_ctrl_start 1b1;endendelse if(i2c_ctrl_idle 1b0)i2c_ctrl_start 1b0;endelse begin//发送状态回复NCKif((i2c_ctrl_idle 1b1) (i2c_ctrl_start 1b0)) begin//产生停止信号if(i2c_error_begin_count 0) begini2c_ctrl_cmd GEN_STO_CMD;i2c_ctrl_start 1b1;endendelse if(i2c_ctrl_idle 1b0)i2c_ctrl_start 1b0;endendenddefault: begini2c_ctrl_cmd 8b0;i2c_ctrl_start 1b0;i2c_tx_data 8b0;i2c_rx_ack 1b0;endendcaseend end//数据请求输出 always (posedge sys_clk)beginif(!sys_rst_n)wr_data_req 1b0;else if((current_state WRITE_STATE) (i2c_tx_ack 1b0) (i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 1)) (i2c_opt_begin_count (EEPROM_MEM_ADDR_BYTES 1 wr_data_len))) beginif((i2c_ctrl_idle 1b0) (i2c_ctrl_start 1b1))wr_data_req 1b1;elsewr_data_req 1b0;endelsewr_data_req 1b0; end//输出读取到的数据 assign rd_data i2c_rx_data; assign rd_data_flag ((current_state READ_STATE) (i2c_opt_end_count (EEPROM_MEM_ADDR_BYTES 5)) (i2c_opt_end_count (EEPROM_MEM_ADDR_BYTES 5 rd_data_len))) ? i2c_ctrl_done : 1b0;//错误检测 always (posedge sys_clk) beginif(!sys_rst_n) begineeprom_error_flag 1b0;endelse if(current_state ! IDLE_STATE) begin//从机响应NAKif(i2c_tx_ack 1b1)eeprom_error_flag 1b1;endelseeeprom_error_flag 1b0; end//I2C操作启动计数 always (posedge sys_clk) beginif(!sys_rst_n) begini2c_opt_begin_count 0;i2c_error_begin_count 0;endelse if(current_state ! IDLE_STATE) beginif(eeprom_error_flag 1b0) beginif((i2c_ctrl_idle 1b0) (i2c_ctrl_start 1b1))i2c_opt_begin_count i2c_opt_begin_count 1;endelse beginif((i2c_ctrl_idle 1b0) (i2c_ctrl_start 1b1))i2c_error_begin_count i2c_error_begin_count 1;endendelse if(current_state IDLE_STATE) begini2c_opt_begin_count 0;i2c_error_begin_count 0;end end//I2C操作完成计数 //I2C错误处理完成计数 always (posedge sys_clk) beginif(!sys_rst_n) begini2c_opt_end_count 0;i2c_error_end_count 0;endelse if(current_state ! IDLE_STATE) beginif(eeprom_error_flag 1b0) beginif(i2c_ctrl_done 1b1)i2c_opt_end_count i2c_opt_end_count 1;endelse beginif(i2c_ctrl_done 1b1)i2c_error_end_count i2c_error_end_count 1;endendelse if(current_state IDLE_STATE) begini2c_opt_end_count 0;i2c_error_end_count 0;end end//状态结束检测 always (posedge sys_clk) beginif(!sys_rst_n)state_done 1b0;else begincase(current_state)IDLE_STATE: beginstate_done 1b0;endREAD_STATE: begin//读存储器操作完成或出错if(i2c_opt_end_count (EEPROM_MEM_ADDR_BYTES 6 rd_data_len) || (i2c_error_end_count 1))state_done 1b1;endWRITE_STATE: begin//写存储器操作完成或出错if(i2c_opt_end_count (EEPROM_MEM_ADDR_BYTES 3 wr_data_len) || (i2c_error_end_count 1))state_done 1b1;enddefault: beginstate_done 1b0;endendcaseend end//例化i2c_driver模块 i2c_driver #(.I2C_CLK_PERIOD(I2C_CLK_PERIOD) ) tb_i2c_driver_inst0 (.sys_rst_n(sys_rst_n),.sys_clk(sys_clk),.ctrl_cmd(i2c_ctrl_cmd),.ctrl_start(i2c_ctrl_start),.ctrl_idle(i2c_ctrl_idle),.ctrl_done(i2c_ctrl_done),.tx_data(i2c_tx_data),.tx_ack(i2c_tx_ack),.rx_data(i2c_rx_data),.rx_ack(i2c_rx_ack),.i2c_scl(i2c_scl),.i2c_sda_o(i2c_sda_o),.i2c_sda_i(i2c_sda_i),.i2c_sda_t(i2c_sda_t) );endmoduleEEPROM 读写测试模块 module eeprom_rw_test #(parameter I2C_CLK_PERIOD 1250, //I2C时钟周期以系统时钟为参考parameter ALARM_LED_PERIOD 25d25_000_000,parameter WAIT_TIME 250000 ) (input sys_rst_n, //系统复位input sys_clk, //系统时钟output i2c_scl, //i2c时钟输出inout i2c_sda, //i2c数据output reg alarm_led //状态指示灯 );//EEPROM操作命令 localparam READ_CMD 8h02; //读命令 localparam WRITE_CMD 8h04; //写命令//状态机的状态 localparam IDLE_STATE 8h01; //空闲状态 localparam READ_STATE 8h02; //读状态 localparam WAIT_STATE 8h04; //等待状态 localparam WRITE_STATE 8h08; //写状态//错误指示 reg error_flag; //警示LED闪烁计数器 reg [31:0] led_count;//写入计数 reg [7:0] write_count; //读取计数 reg [7:0] read_count;//等待写入计时计数器 reg [31:0] wait_count;//当前状态 reg [7:0] current_state; //下一刻的状态 reg [7:0] next_state; //对应状态结束标志应切换到下一个状态一个bit对应一个状态 reg [7:0] state_done; //状态启动标志 reg [7:0] state_start;//启动信号 reg eeprom_start; //操作命令 reg [7:0] eeprom_cmd; //操作的存储器地址 reg [15:0] mem_addr;//写入长度 reg [7:0] wr_data_len; //需要写入的数据 reg [7:0] wr_data; //写入数据请求 wire wr_data_req;//读取长度 reg [7:0] rd_data_len; //读取到的数据 wire [7:0] rd_data; //读取输出标志 wire rd_data_flag;//空闲标志 wire eeprom_idle; //EEPROM错误标志 wire eeprom_error_flag;//根据错误标志控制led闪烁或常亮 //操作未完成熄灭 //操作完成常亮 //发生错误时闪烁 always (posedge sys_clk) beginif(!sys_rst_n) beginalarm_led 1b0;led_count 32b0;endelse if(error_flag 1b1) beginif(led_count (ALARM_LED_PERIOD - 1)) beginalarm_led ~alarm_led;led_count 32b0;endelseled_count led_count 32b1;endelse if((current_state IDLE_STATE) (state_done ! 8h0)) beginalarm_led 1b1;led_count 32b0;endelse begin alarm_led 1b0;led_count 32b0;end end//状态跳转 always (posedge sys_clk)beginif(!sys_rst_n)current_state IDLE_STATE;elsecurrent_state next_state; end//根据当前状态确定下一刻状态 always (*)begincase(current_state)IDLE_STATE: beginif((state_done 16h0) (error_flag 1b0))next_state WRITE_STATE;elsenext_state IDLE_STATE;endWRITE_STATE: beginif(error_flag 1b1)next_state IDLE_STATE;else if(state_done WRITE_STATE)next_state WAIT_STATE;elsenext_state WRITE_STATE;endWAIT_STATE: beginif(error_flag 1b1)next_state IDLE_STATE;else if(state_done WAIT_STATE)next_state READ_STATE;elsenext_state WAIT_STATE;endREAD_STATE: beginif(error_flag 1b1)next_state IDLE_STATE;else if(state_done READ_STATE)next_state IDLE_STATE;elsenext_state READ_STATE;enddefault:next_state IDLE_STATE;endcase end//写入等待过程计时 always (posedge sys_clk)beginif(!sys_rst_n) wait_count 0;else beginif(current_state WAIT_STATE) beginif(wait_count (WAIT_TIME - 1))wait_count wait_count 1;endelsewait_count 0;end end//控制EEPROM读写 always (posedge sys_clk)beginif(!sys_rst_n) begineeprom_start 1b0;eeprom_cmd 8b0;mem_addr 16b0;wr_data_len 8b0;rd_data_len 8b0;state_done 8h0;state_start 8h0;endelse begincase(current_state)WRITE_STATE: begin//启动写操作if((eeprom_idle 1b1) (!(state_start WRITE_STATE)) (eeprom_start 1b0)) begineeprom_start 1b1;eeprom_cmd WRITE_CMD;mem_addr 16h0000;wr_data_len 8d8;state_start state_start | WRITE_STATE;end//写操作完成if((eeprom_idle 1b1) (state_start WRITE_STATE) (eeprom_start 1b0)) beginif(!(state_done WRITE_STATE))state_done state_done | WRITE_STATE;end//操作已经启动复位启动标志if((eeprom_idle 1b0) (eeprom_start 1b1))eeprom_start 1b0;endWAIT_STATE: begin//等待EEPROM写入结束if(wait_count (WAIT_TIME - 1))state_done state_done | WAIT_STATE;endREAD_STATE: begin//启动读flash操作if((eeprom_idle 1b1) (!(state_start READ_STATE)) (eeprom_start 1b0)) begineeprom_start 1b1;eeprom_cmd READ_CMD;mem_addr 24h0000;rd_data_len 8d8;state_start state_start | READ_STATE;end//读操作完成if((eeprom_idle 1b1) (state_start READ_STATE) (eeprom_start 1b0)) beginif(!(state_done READ_STATE))state_done state_done | READ_STATE;end//操作已经启动复位启动标志if((eeprom_idle 1b0) (eeprom_start 1b1))eeprom_start 1b0;enddefault: begineeprom_start 1b0;eeprom_cmd 8b0;mem_addr 16b0;endendcaseend end//生成写入的数据 always (posedge sys_clk)beginif(!sys_rst_n) beginwr_data 8h0;write_count 8h0;endelse if(current_state WRITE_STATE) beginif(wr_data_req 1b1) begin//生成写入数据wr_data write_count[7:0] 1;//写入计数write_count write_count 8h1;endendelse beginwr_data 0;write_count 0;end end//处理读取的数据 //处理EEPROM错误 always (posedge sys_clk)beginif(!sys_rst_n) beginerror_flag 1b0;read_count 8h0;endelse begin//处理EEPROM错误if(eeprom_error_flag 1b1)error_flag 1b1;//处理读取的数据if(current_state READ_STATE) beginif(rd_data_flag 1b1) begin//检查接收的数据if(rd_data ! (read_count[7:0] 1))error_flag 1b1;//接收计数read_count read_count 8h1;endendend end//用IOBUF将SDA合并 //对于inout类型的端口最好显示的调用IOBUF硬核 IOBUF u_IOBUF_inst0(.IO(i2c_sda), //连接到外部IO引脚.T(i2c_sda_t), //输入输出控制0输出将I输出到IO1输入将IO设置为高阻态此时O为IO输入电平.I(i2c_sda_o), //IOBUF输入应接用户逻辑输出.O(i2c_sda_i) //IOBUF输出应接用户逻辑输入 );//例化eeprom_driver eeprom_driver #(.I2C_CLK_PERIOD(1250),.EEPROM_MEM_ADDR_BYTES(2) ) tb_eeprom_driver_inst0(.sys_rst_n(sys_rst_n),.sys_clk(sys_clk),.eeprom_start(eeprom_start),.eeprom_cmd(eeprom_cmd),.slave_addr(7b1010000),.mem_addr(mem_addr),.wr_data_len(wr_data_len),.wr_data(wr_data),.wr_data_req(wr_data_req),.rd_data_len(rd_data_len),.rd_data(rd_data),.rd_data_flag(rd_data_flag),.eeprom_idle(eeprom_idle),.eeprom_error_flag(eeprom_error_flag),.i2c_scl(i2c_scl),.i2c_sda_o(i2c_sda_o),.i2c_sda_i(i2c_sda_i),.i2c_sda_t(i2c_sda_t) );endmodule仿真激励文件 在仿真过程中需要用到AT24C64的仿真激励模型可以通过AT24C64仿真激励模型下载地址进行下载完成的仿真激励文件如下 timescale 1ns / 1psmodule tb_eeprom_rw_test( );reg sys_rst_n; //系统复位 reg sys_clk; //系统时钟wire i2c_scl; //i2c时钟输出 wire i2c_sda; //i2c数据wire alarm_led; //状态指示灯//产生仿真信号序列 initial beginsys_rst_n 1b0;sys_clk 1b0;#2000sys_rst_n 1b1; end//产生时钟 always #10 sys_clk ~sys_clk;//将SDA数据线上拉 pullup(i2c_sda);//例化eeprom_rw_test eeprom_rw_test #(.I2C_CLK_PERIOD(1250),.ALARM_LED_PERIOD(25d25_000_000) ) tb_eeprom_rw_test_inst0(.sys_rst_n(sys_rst_n),.sys_clk(sys_clk),.i2c_scl(i2c_scl),.i2c_sda(i2c_sda),.alarm_led(alarm_led) );//例化e2prom仿真模型 M24LC64 u_M24LC64_inst0(.A0(0),.A1(0),.A2(0),.WP(0),.SDA(i2c_sda),.SCL(i2c_scl),.RESET(~sys_rst_n) );endmodule引脚约束 #时序约束 create_clock -period 20.000 -name sys_clk [get_ports sys_clk]#IO 管脚约束 set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS15} [get_ports sys_clk] set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS15} [get_ports sys_rst_n] set_property -dict {PACKAGE_PIN F13 IOSTANDARD LVCMOS33} [get_ports i2c_scl] set_property -dict {PACKAGE_PIN A19 IOSTANDARD LVCMOS33} [get_ports i2c_sda] set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS15} [get_ports alarm_led]
http://www.pierceye.com/news/191500/

相关文章:

  • 设置网站建设WordPress adsen
  • 网站与微信内容建设与运维总结建筑网络图
  • 网站模板文件不存在网站建设礻金手指下拉十二
  • 东莞浩智建设网站公司做百度推广员赚钱吗
  • qq网站推广代码昆明哪里做网站
  • 章丘营销型网站设计公司青岛网络优化排名
  • 制作网站模板的发展空间wordpress 阿里云 cdn
  • 交互式网站备案万网域名网站建设
  • 备案 个人网站名称月坛网站建设公司
  • 网站建设要解决哪些方面的事项临海外发加工网
  • 甜品店网站开发背景江宁区住房建设局网站
  • asp.net网站开发视频教程找能做网站的
  • 租房合同范本下载word东莞网络优化
  • 做网站需要会写代码6net快速建站
  • 克拉玛依 网站建设红圈工程项目管理软件
  • 北京网站ui设计公司共青城网站建设公司
  • 电子商务网站设计说明书开发一个网站
  • 网站制作长沙怎么做淘客手机网站
  • 五路居网站建设wordpress php允许上传文件大小
  • 旅游网站的设计代码下列哪些不属于企业网站建设基本原则
  • 房屋租赁网站开发意义做男鞋的网站
  • 网站负责人可以备案北京建设部网站 信息中心
  • 网站建设分录怎么开四川省城乡住房建设部网站首页
  • 刘家窑网站建设公司如何在网络上推广产品
  • 全球建站东莞市的网站公司哪家好
  • 地方网站发展怎么做链接推广产品
  • 上海制造网站公司网站优化做网站优化
  • vs2012做网站wordpress 页眉
  • 北网站建设重庆建设工程查询网站
  • 给我做网站的人老是给我留点尾巴太原本地网站搭建公司