当前位置:文档之家› I2C总线接口电路设计

I2C总线接口电路设计

I2C总线接口电路设计
I2C总线接口电路设计

FPGA与I2C总线器件接口电路设计

利用FPGA模拟I2C总线协议对I2C总线接口器件A T24C256 进行读写操作。利用按键输入读写命令和相应的地址、数据,对芯片进行读写操作,读写的数据用数码管显示。

一、I2C总线接口电路设计分析

1. I2C 总线协议

I2C 总线的两根通信线,一根是串行数据线SDA,另一根是串行时钟线SCL。多个符合I2C总线标准的器件都可以通过同一条I2C总线进行通信,而不需要额外的地址译码器。每个连接到总线上的器件都有一个唯一的地址作为识别的标志,都可以发送或接收数据。I2C 总线通信速率受主机控制,标准模式下可达100kbit/s。

一般具有I2C总线的器件其SDA、SCL引脚都为集电极(或漏极)开路结构。因此实际使用时,SDA 和SCL信号线必须加3~10K的上拉电阻。总线空闲时均保持高平。I2C总线接法如图1所示。

图1 I2C总线连接示意图

(1) I2C的主机和从机,发送器和接收器

产生I2C总线时钟信号和起始、停止控制信号的器件,称为主机,被主机寻址的器件称为从机。

任何将数据传送到I2C总线的器件称为发送器,任何从I2C总线接收数据的器件称为接收器。

主机和从机都可作为发送数据器件和接收数据器件。

(2) I2C 总线上数据的有效性:

时钟线SCL为高电平时,数据线SDA的任何电平变化将被看作总线的起始或停止信号;

在数据传送过程中,当时钟线SCL为高电平时,数据线SDA必须保持稳定状态,不允许有跳变;数据线SDA的状态只能在SCL低电平期间才能改变。即进行串行传送数据时,在SCL高电平期间传送位数据,低电平期间准备数据。

(3) 从机地址

I2C总线不需要额外的片选信号或地址译码。多个I2C总线接口器件可连接到一条I2C总线上,它们之间通过地址来区分。主机是主控制器件,只有一个主机的不需要地址。其它器件均为从机,均有器件地址,但必须保证同一条I2C总线上的器件地址不能重复。一般从机地址由7位地址位和1位读写位组成,地址位为高7位,读写位为最低位。读写位为0时,表示主机将向从机写入数据;读写位为1时,表示主机将要从从机读取数据。

(4) I2C 总线的通信时序

I 2

C 总线的通信时序如图2所示。

图2 I2C 总线的通信时序

① 首先主机发送一个起始信号。当时钟线SCL 处于高电平期间,数据线SDA 电平从高到低的跳变形成I 2C 总线的起始信号,启动I 2C 总线。

② 主机逐位发送7位(高位在前,低位在后)从机地址和1位读写控制信号,共8位。需8个时钟。

③ 与传送地址一致的从机发应答信号(ACK )。在第9个时钟周期时将SDA 线拉低表示其已收到一个8位数据。若在第9个时钟周期,SDA 为高电平时为非应答。

④ 开始传送数据,传送数据数量不限。每个字节(8位)后紧跟1个接收器件发出的应答位。若是主机读取从机数据时,从机发送数据,主机发应答位;若是主机写数据到从机时,主机发送数据,从机发应答位。

⑤ 数据传输结束时,主机发送1个停止信号,当时钟线SCL 为高电平时,数据线SDA 由低电平变为高电平时形成终止信号,停止I 2C 总线通信。

(5) 数据传输基本格式如表1。

表1 I2C 总线数据传输基本格式

其中S 、A7~A1、R/W 、P 总是由主机产生;写数据时,ACK 由从机产生,D7~D0由主机产生;读数据时,ACK 由主机产生,D7~D0由从机产生。 2. I2C 总线器件AT24C256

A T24C256 是一个256K 位的串行CMOS 型 E 2PROM , 可存储32768 个字节。该器件通过I 2C 总线接口进行操作,其引脚如图3所示,各引脚功能见表2。

图3 AT24C256引脚图 表

2 AT24C256引脚功能说明

SDA

S 起始 条件

停止 条件

暂停 控制

作为带有I C总线接口的器件,每个A T24C256都有一个7位的从机地址,其高5 位固定为“10100”,接下来的2 位由A T24C256的引脚A1 A0 硬连线输入决定(A1、A0直接接电源VCC或GND),同一I2C总线上最多可以连接4 个A T24C256器件。A T24C256除了有作为从机的地址,其内部还有作为存储单元的编码子地址,其子地址为双字节(16位),从0000H~7FFFH。本设计中只有1 个A T24C256,可将A T24C256的引脚A1、A0直接接地,其硬件电路如图4所示。则该A T24C256作为从机的7位地址为“1010000”。

图4 单个AT24C256连接电路图

3. 对AT24C256的读写过程

(1) 向A T24C256某一存储单元写入1个字节数据,过程如下:

①主机(这里为FPGA控制器)发送一个起始信号,启动发送过程;

②主机发送7 位从机地址(这里为1010000)和1位写控制位(为0);

③从机(这里为A T24C256)发应答位。在主机发送起始信号和从机地址字节后,A T24C256 监视总线并当其地址与发送的从地址相符时,响应一个应答信号。在第9个时钟,将SDA线拉为低电平;

④主机接收到应答位后,发从机子地址高8位(为A T24C256某一存储单元地址)。

⑤从机接收完高8位子地址后,发应答位;

⑥主机接收到应答位后,发从机子地址低8位;

⑦从机接收完低8位子地址后,发应答位;

⑧主机接收到应答位后,发送待8位写入数据;

⑨从机接收完8数据后,发应答位,并开始内部数据的擦写;

⑩主机接收到应答位后,发停止位,结束传送,总线挂起。

SDA上数据传输格式见表3,数据传送时序如图5所示。

表3 向AT24C256写1个数据时总线SDA上数据传输格式

图5 向AT24C256写一个数据时序

(2) 从A T24C256某一存储单元读出1个字节数据,过程如下:

①主机发送一个起始信号,启动发送过程,接着发送7 位从机地址(1010000)和1位写控制位(0);;

②从机检测到起始信号及本身从地址相符时的从机地址后,发应答位。

③主机接收到应答位后,发从机子地址高8位(为A T24C256某一存储单元地址)。

④从机接收完高8位子地址后,发应答位;

⑤主机接收到应答位后,发从机子地址低8位;

⑥从机接收完低8位子地址后,发应答位;

⑦主机接收到应答位后,再发送一个起始信号(称为重复起始信号),接着再发送7 位从机地址(1010000)和1位读控制位(为1);

⑧从机检测到重复起始信号及从机地址后,发应答位,并将子地址对应的存储单元数据发送到总线上。

⑨主机接收到应答位后,接着准备从总线接收数据,从总线接收完8数据后。发非应答位和发停止位,结束传送,总线挂起。

SDA上数据传输格式见表4所示,数据传送时序如图6所示。

表4 从AT24C256上读1个数据时总线SDA上数据传输格式

图6 从AT24C256读一个数据时序

4. FPGA内部电路

模拟I 2

C 总线对A T24C256的读写控制电路基本结构框图如图7所示。

图7 模拟I2C 总线对AT24C256的读写控制框图

(1) I 2

C 总线端口

I 2C 总线端口为三态输出,当使能端有效时,总线输出为低电平;当使能端无效时三态门输出为高

阻,但由于I 2C 总线上有上拉电阻,总线保持在高电平或由总线上从机输出数据决定。总线数据始终能被读入。其结构示意图如图8所示。

图8 I2C 总线端口示意图

(2) 位传输控制模块

位传输模块以“位”为单位产生各种I 2C 协议命令(开始、停止和重复开始)以及进行位数据读写。为了读写到稳定的“位”数据,读写1位数据分为4到5个阶段完成。1位数据传输时序要求如图9所示。这样内部读写时钟频率一般采用5倍于SCL 时钟总线频率。

Sda

Sda Scl_

图9 I2C 协议命令和位数据传输的执行时序

位传输控制电路根据输入的控制命令,将来自字控制模块的一位待写入的数据送到总线上,或从总线上读入一位数据给字控制模块。当完成1位数据传输时产生读写完成标志,并根据数据传输情况产生忙标志和总线仲裁丢失标志。

(3) 字传输控制模块

字节传输模块以字节为单位控制I 2C 总线的数据传输。该模块根据输入控制命令,将存放在发送寄存器中的数据加载到一个移位寄存器,然后逐位发送到位传输模块,再控制位传输模块将数据发送到I 2C 总线上。或控制位传输模块从总线上逐位接收位数据,暂存到移位寄存器,再转换成字节数据送给数据输出。同时给出相关传输标志。

(4) A T24C256读写控制

根据输入控制信号和来自位传输模块的反馈标志,将控制信号加到命令寄存器,给字节传输模块提供控制信号;将输入数据或指定单元地址加载到数据传送寄存器;将从字节模块读取的数据回送到数据接收寄存器。

二、FPGA 硬件系统电路设计(略) 三、I 2

C 总线接口电路VHDL 设计

1. I2C 总线端口

(1) 名称:IIC_IO.vhd

(2) 功能:I 2C 总线双向端口电路描述

SCL SDA

SCL SDA SCL

SDA SCL

SDA

SCL SDA

开始

重复开始

停止

A B C

(4) VHDL描述

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

ENTITY IIC_IO IS

PORT(

Scl_en,sda_en: IN STD_LOGIC;

Sda,Scl: INOUT STD_LOGIC;

Scl_i,sda_i : OUT STD_LOGIC);

END IIC_IO;

ARCHITECTURE one OF IIC_IO IS

BEGIN

Sda_i<=sda;

Scl_i<=scl;

Scl<='0' WHEN scl_en='0' ELSE 'Z';

Sda<='0' WHEN sda_en='0' ELSE 'Z';

END one;

2. 位传输控制模块

(1)名称:bit_txd_rxd.vhd

(2)功能:实现位数据或协议命令的传输

(3)

(4) VHDL描述

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_Arith.ALL;

USE IEEE.STD_LOGIC_Unsigned.ALL;

ENTITY bit_txd_rxd IS

GENERIC (n:INTEGER:=48);--分频系数

PORT(

Clk_sys: IN STD_LOGIC;

Rst,ena: IN STD_LOGIC;

cmd: IN STD_LOGIC_VECTOR(3 DOWNTO 0);

Bit_data_wr: IN STD_LOGIC;--

Scl_i,sda_i : IN STD_LOGIC;

Scl_oen,sda_oen: OUT STD_LOGIC;

Busy,Lose: OUT STD_LOGIC;

Bit_data_rd,Bit_finish: OUT STD_LOGIC);

END bit_txd_rxd;

ARCHITECTURE two OF bit_txd_rxd IS

Type state_t IS (bit_idle,start_a,start_b,start_c,start_d,start_e,stop_a,stop_b,stop_c,stop_d, write_a, write_b, write_c, write_d,read_a, read_b, read_c, read_d);

SIGNAL sta_p: state_t;

CONSTANT n:INTEGER:=48; --产生500KHz的分频系数

SIGNAL en_500k: STD_LOGIC;--500KHz时钟使能信号

SIGNAL Scl_a,Sda_a, Scl_b,Sda_b:STD_LOGIC;--同步SCL和SDA中间信号

SIGNAL scl_edg: STD_LOGIC;--SCL的边沿信号

SIGNAL scl_oen_r, sda_oen_r: STD_LOGIC;--总线使能信号

SIGNAL sda_chk: STD_LOGIC;--写数据时,检查总线信号

SIGNAL dscl_oen,slave_wait: STD_LOGIC;--时钟延迟等待的信号

SIGNAL Sda_S,Sda_P: STD_LOGIC;--启动、停止标志位

SIGNAL Busy_r,Lose_r: STD_LOGIC;--忙标志、丢失标志信号

SIGNAL stop_cmd,stop_cmd_r: STD_LOGIC;--停止命令信号

BEGIN

PROCESS (clk_sys,rst) --同步SCL和SDA的输入信号

BEGIN

IF rst='0' THEN

Scl_a<='1';

Sda_a<='1';

Scl_b<='1';

Sda_b<='1';

ELSIF RISING_EDGE(clk_sys) THEN --暂存SCL、SDA的值

Scl_a<= Scl_i;

Sda_a<= Sda_i;

Scl_b<= Scl_a;

Sda_b<= Sda_a;

END IF;

END PROCESS;

Scl_edg<=scl_a AND( NOT Scl_b);--检测时钟SCL上升沿

PROCESS (clk_sys) --产生数据输出信号,在SCL上升沿时锁存SDA上的数据值

BEGIN

IF RISING_EDGE(clk_sys) THEN

IF scl_edg='1' THEN

Bit_data_rd<=Sda_a;

END IF;

END IF;

END PROCESS;

--从节点未准备好时,下拉SCL延迟周期;当给出的SCL使能为1时,检测SCL总线为0时,则节点未准备就绪,产生等待信号。

PROCESS (clk_sys)

BEGIN

IF RISING_EDGE(clk_sys) THEN

dscl_oen<=scl_oen_r;

END IF;

END PROCESS;

Slave_wait<=dscl_oen AND (NOT scl_a);

PROCESS (clk_sys,rst) --将24M系统时钟分频产生500KHz时钟使能控制信号

V ARIABLE cnt: INTEGER RANGE 0 TO n-1;--时钟分频计数器

BEGIN

IF rst='0' THEN

cnt:=0;

en_500k<='1';

ELSIF RISING_EDGE(clk_sys) THEN

IF clk_cnt

IF ena='1' THEN

cnt:= cnt+1;

en_500k<='0';

END IF;

ELSE

IF Slave_wait='0' THEN--从节点准备好,给出时钟使能

cnt:=0;

en_500k<='1';

ELSE --从节点未准备好,延迟等待

cnt:= cnt;

en_500k<='0';

END IF;

END IF;

END IF;

END PROCESS;

--生成启动标志和停止标志

--在SCL高电平时,检测SDA的下降沿(起始信号),产生启动标志

--在SCL高电平时,检测SDA的上升沿(停止信号),产生停止标志

PROCESS (clk_sys,rst)

BEGIN

IF rst='0' THEN

Sda_S<='0';--启动标志复位

Sda_P<='0';-- 停止标志复位

ELSIF RISING_EDGE(clk_sys) THEN

Sda_S<=(NOT Sda_a ) AND Sda_b AND Scl_a ;--生成启动标志

Sda_P<=Sda_a AND ( NOT Sda_b ) AND Scl_a; --生成停止标志

END IF;

END PROCESS;

--生成总线忙标志

--检测到启动信号发生,但无停止信号发生时表示总线处于忙状态

PROCESS (clk_sys,rst)

BEGIN

IF rst='0' THEN

Busy_r<='0';

ELSIF RISING_EDGE(clk_sys) THEN

Busy_r<=(Sda_S OR busy_r) AND (NOT Sda_P);

END IF;

END PROCESS;

Busy<=busy_r;--忙标志输出

--产生仲裁丢失标志,

--当没有停止请求时,检测到停止信号,产生仲裁丢失标志

---当驱动SDA总线为高时,但检测SDA一直为低,产生仲裁丢失标志

PROCESS (clk_sys,rst)

BEGIN

IF rst='0' THEN

stop_cmd<='0';--停止命令信号

stop_cmd_r <='0';

Lose_r<='0';

ELSIF RISING_EDGE(clk_sys) THEN

IF cmd<= "0010" THEN --有停止命令

stop_Cmd<='1';

ELSE

stop_Cmd<='0';

END IF;

stop_Cmd_r <= stop_Cmd;

Lose_r<=(Sda_P AND (NOT stop_Cmd_r )) OR(NOT sda_a AND sda_chk AND sda_oen_r);--丢失标志

END IF;

END PROCESS;

Lose<=Lose_r;

--位传输状态机

Scl_oen<=scl_oen_r;

Sda_oen<=Sda_oen_r;

PROCESS(clk_sys,rst)

BEGIN

IF rst='0' THEN

Sta_p<=bit_idle;--初始准备状态

bit_finish<='0'; --1位信号发送或接收完成标志

Scl_oen_r<='1';--时钟输出使能

Sda_oen_r <='1';--数据输出使能

Sda_chk<='0';--不检查输出

ELSIF RISING_EDGE(clk_sys) THEN

IF Lose_r='1' THEN--数据传输信号丢失

Sta_p<=bit_idle;

bit_finish <='0';

Scl_oen_r <='1';

Sda_oen_r <='1';

Sda_chk<='0';

ELSE

bit_finish <='0';

IF clk_en='1' THEN

CASE sta_p IS

WHEN bit_idle=> --准备状态

Scl_oen_r <=scl_oen_r;--保持SCL在同一状态

Sda_oen_r <=sda_oen_r; --保持SDA在同一状态

Sda_chk<='0';

CASE cmd IS --状态命令字

WHEN "0001"=> sta_p<=start_a;--发送起始信号状态

WHEN "0010" => sta_p<=stop_a;-- 发送停止信号状态

WHEN "0100" => sta_p<=write_a;--写入1位数据

WHEN "1000" => sta_p<=read_a; --读出1位数据

WHEN OTHERS=> sta_p<=bit_idle;

END CASE;

--启动I2C状态,分5个时钟段产生起始信号

WHEN start_a=>

sta_p<=start_b;

Scl_oen_r <=scl_oen_r; --保持SCL

Sda_oen_r <='1'; --SDA处于高

Sda_chk<='0'; --不检查输出

WHEN start_b=>

sta_p<=start_c;

Scl_oen_r <='1';

Sda_oen_r <='1';

Sda_chk<='0';

WHEN start_c=>

sta_p<=start_d;

Scl_oen_r <='1';

Sda_oen_r <='0';

Sda_chk<='0';

WHEN start_d=>

sta_p<=start_e;

Scl_oen_r <='1';

Sda_oen_r <='0';

Sda_chk<='0';

WHEN start_e=> --开始状态5

sta_p<=bit_idle;--回到等待状态

bit_finish <='1';--起始信号传送完成,给出标志

Scl_oen_r <='0';

Sda_oen_r <='0';

Sda_chk<='0';

--停止I2C状态,分4个时钟段产生停止信号

WHEN stop_a=>

sta_p<=stop_b;

Scl_oen_r <='0';

Sda_oen_r <='0';

Sda_chk<='0';

WHEN stop_b=>

sta_p<=stop_c;

Scl_oen_r <='1';

Sda_oen_r <='0';

Sda_chk<='0';

WHEN stop_c=>

sta_p<=stop_d;

Scl_oen_r <='1';

Sda_oen_r <='0';

Sda_chk<='0';

WHEN stop_d=>

sta_p<=bit_idle;

bit_finish <='1';--停止信号传送完成,给出标志

Scl_oen_r <='1';

Sda_oen_r <='1';

Sda_chk<='0';

--读状态,分4个时钟段读1位信号

WHEN read_a=>

sta_p<= read_b;

Scl_oen_r <='0'; -- SCL处于低

Sda_oen_r <='1'; --SDA由从器件决定

Sda_chk<='0';

WHEN read_b=>

sta_p<= read_c;

Scl_oen_r <='1';

Sda_oen_r <='1';

Sda_chk<='0';

WHEN read_c=>

sta_p<= read_d;

Scl_oen_r <='1';

Sda_oen_r <='1';

Sda_chk<='0';

WHEN read_d=>

sta_p<=bit_idle;

bit_finish <='1';--读完1位数据,给出标志

Scl_oen_r <='0';

Sda_oen_r <='1';

Sda_chk<='0';

--写状态,分4个时钟段写1位信号

WHEN write_a=>

sta_p<= write_b;

Scl_oen_r <='0'; -- SCL处于低

Sda_oen_r <=bit_data_wr; --输入数据

Sda_chk<='0';

WHEN write_b=>

sta_p<= write_c;

Scl_oen_r <='1'; --

Sda_oen_r <=bit_data_wr;

Sda_chk<='1';--

WHEN write_c=> --写状态3

sta_p<= write_d;

Scl_oen_r <='1'; --

Sda_oen_r <= bit_data_wr;

Sda_chk<='1';

WHEN write_d=> --写状态4

sta_p<=bit_idle;

bit_finish <='1';--写完1位信号,给出标志

Scl_oen_r <='0';

Sda_oen_r <= bit_data_wr;

Sda_chk<='0';

WHEN OTHERS=>null;

END CASE;

END IF;

END IF;

END IF;

END PROCESS;

END two;

3. 字传输控制模块

(1)名称:byte_txd_rxd.vhd

(2)功能:实现字节数据的传输控制。

(3)

(4) VHDL描述

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_Arith.ALL;

USE IEEE.STD_LOGIC_Unsigned.ALL;

ENTITY byte_txd_rxd IS

PORT(

clk_sys: IN STD_LOGIC;

rst: IN STD_LOGIC;

ack_in: IN STD_LOGIC;

data_txd: IN STD_LOGIC_VECTOR(7 DOWNTO 0);

start,stop,write,read: IN STD_LOGIC;

lose: IN STD_LOGIC;

bit_data_rd:IN STD_LOGIC;--从位控制模块读入的一位数据

bit_finish: IN STD_LOGIC;--1位传送完成标志

cmd: OUT STD_LOGIC_VECTOR(3 DOWNTO 0);

bit_data_wr:OUT STD_LOGIC;--待写出的位数据

ack_finish,ack_out: OUT STD_LOGIC;

data_rxd: OUT STD_LOGIC_VECTOR(7 DOWNTO 0));

END byte_txd_rxd;

ARCHITECTURE three OF byte_txd_rxd IS

Type state_byte IS (byte_idle,byte_start,byte_stop, byte_write,byte_read,ack_wr,ack_rd); SIGNAL sta_c: state_byte;

SIGNAL ack_finish_r:STD_LOGIC;--完成1字节数据传输标志

SIGNAL en: STD_LOGIC;--使能信号

SIGNAL ld_en,shift_en:STD_LOGIC;--加载数据使能、移位数据使能

SIGNAL shift_reg: STD_LOGIC_VECTOR(7 DOWNTO 0);--数据移位寄存器SIGNAL cnt_rw: S TD_LOGIC_VECTOR(2 DOWNTO 0);--移位次数计数器SIGNAL cnt_done: STD_LOGIC;--完成1个字节数据移位完成标志

BEGIN

ack_finish<=ack_finish_r;

en<=(read OR write OR stop) AND (NOT Ack_finish_r);--操作使能

PROCESS (clk_sys,rst) --生成移位寄存器内容

BEGIN

IF rst='0' THEN

shift_reg<=(OTHERS=>'0');

ELSIF RISING_EDGE(clk_sys) THEN

IF ld_en='1' THEN --写数据时

shift_reg<=data_txd;--待发送数据加载到移位寄存器

ELSIF shift_en='1' THEN--读数据时

shift_reg<=shift_reg(6 DOWNTO 0)& bit_data_rd;--移位读入数据

END IF;

END IF;

END PROCESS;

PROCESS (clk_sys,rst) --进行读写位计数

BEGIN

IF rst='0' THEN

cnt_rw<="000";

ELSIF RISING_EDGE(clk_sys) THEN

IF Ld_en='1' THEN --加载新数据时

cnt_rw<="111";--设置计数初值为8次

ELSIF shift_en='1' THEN --移位1次

cnt_rw<=cnt_rw-1;--减1计数

END IF;

END IF;

END PROCESS;

cnt_done<='1' WHEN cnt_rw="000" ELSE '0';--读写完1个字节(计数8次),给出标志--字节传送状态控制

PROCESS (clk_sys,rst)

BEGIN

IF rst='0' THEN

cmd<="0000";--I2C总线处于空闲状态命令

bit_data_wr <='0'; --待写出的位数据

ld_en<='0';--禁止加载数据

shift_en<='0';--禁止移位

Sta_c<=Byte_idle;--初始准备状态

sck_finish_r<='0';-- 应答完成标志置0

sck_out<='0';--应答输出置0

ELSIF RISING_EDGE(clk_sys) THEN

IF Lose='1' THEN--数据传输信号丢失

cmd<="0000";

bit_data_wr <='0';

ld_en<='0';

shift_en<='0';

sta_c<=Byte_idle;

ack_finish_r<='0';

ack_out<='0';

ELSE --

bit_data_wr<=shift_reg(7); --取移位寄存器的最高位作为待写出位

shift_en<='0';--禁止移位

ld_en<='0';-- 禁止加载

ack_finish_r<='0'; -- 应答完成标志置0

CASE sta_c IS

WHEN Byte_idle=>--空闲状态

IF en='1' THEN--发生读/写/停止命令且无应答完成标志

ld_en<='1'; --重新加载写入数据初值,复位传送计数器

IF start='1' THEN

sta_c<=Byte_start;--起始状态

cmd<= "0001";--启动位模块发送起始位

ELSIF read='1' THEN

sta_c<=Byte_read;--读状态

cmd<= "1000"; --启动位模块读取1位数据ELSIF write='1' THEN

sta_c<=Byte_write;--写状态

cmd<="0100" ; --启动位模块写入1位数据ELSE

sta_c<=Byte_stop;-- --停止状态

cmd<= "0010"; --启动位模块发送停止位

ack_finish_r<='1';--产生传送完成标志

END IF;

END IF;

WHEN Byte_start=>

IF bit_finish='1' THEN --起始位发送完成标志

ld_en<='1'; --重新加载初值

IF read='1' THEN

sta_c<=Byte_read;

cmd<="1000";

ELSE

sta_c<=Byte_write;

cmd<="0100";

END IF;

END IF;

WHEN Byte_write=>

IF bit_finish ='1' THEN --写完1位标志

IF cnt_done='1' THEN--写完8位标志

sta_c<=ack_rd; --读应答状态

Cmd<="1000";-- 准备读应答位

ELSE

sta_c<=Byte_write;--保持写状态

cmd<= "0100";--准备继续写下1位

shift_en<='1'; --移位,准备下1位数据

END IF;

END IF;

WHEN Byte_read=>

IF bit_finish ='1' THEN --读完1位标志

shift_en<='1'; --移位,存储新读入的1位数据

IF cnt_done='1' THEN--读完8位标志

sta_c<=ack_wr; --写应答状态

cmd<= "0100";-- 准备写应答位

bit_data_wr<=ack_in;--给出待发送的应答信号ELSE

sta_c<=Byte_read;--保持读状态

Cmd<= "1000";-- 准备继续读下1位

END IF;

END IF;

WHEN ack_rd=>--读应答状态

IF bit_finish ='1' THEN --应答位读完成标志

ack_out<=bit_data_rd;--输出应答信号

ack_finish_r<='1'; --给出应答完成标志

data_rxd<=shift_reg;

IF stop='1' THEN

sta_c<=Byte_stop;

cmd<= "0010";--发停止位

ELSE

sta_c<=Byte_idle; --空闲状态

cmd<="0000";--等待

END IF;

END IF;

WHEN ack_wr=>--写应答状态

IF bit_finish ='1' THEN --应答位写完成标志

bit_data_wr<='1';--待写入的位信号为高

ack_finish_r<='1'; --给出应答完成标志

IF stop='1' THEN

sta_c<=Byte_stop;

cmd<= "0010";--发停止位

ELSE

sta_c<=Byte_idle; --空闲状态

cmd<="0000";--等待

END IF;

ELSE

bit_data_wr<=ack_in;

END IF;

WHEN Byte_stop=>--停止状态

IF bit_finish='1' THEN --停止位发送完成标志

sta_c<=Byte_idle;

Cmd<="0000";--等待

END IF;

END CASE;

END IF;

END IF;

END PROCESS;

END three;

4. AT24C256读写控制

(1) 名称:A T24C256_wr.vhd

(2) 功能:通过I2C总线对A T24C256指定单元进行读写。

(4) VHDL描述

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.ALL;

USE IEEE.STD_LOGIC_Arith.ALL;

USE IEEE.STD_LOGIC_Unsigned.ALL;

ENTITY A T24C256_rw IS

PORT(

clk_sys: IN STD_LOGIC;--24MHz系统时钟

rst,ena, clk_ena: IN STD_LOGIC;--复位,使能信号

rw: IN STD_LOGIC;

slave_addr: STD_LOGIC_VECTOR(6 DOWNTO 0);

sub_addr:STD_LOGIC_VECTOR(15 DOWNTO 0);

data_in: IN STD_LOGIC_VECTOR(7 DOWNTO 0);

ack_finish,ack_flag: IN STD_LOGIC;

data_rxd: IN STD_LOGIC_VECTOR(7 DOWNTO 0);

data_wr: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);

start,stop,write,read:OUT STD_LOGIC;

data_out: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);

rtx_f: OUT STD_LOGIC);

END A T24C256_rw;

ARCHITECTURE four OF A T24C256_rw IS

Type state_at IS (S0,S1,S2,S3,S4,S5,S6);

SIGNAL sta_n: state_at;

SIGNAL cmd_reg: STD_LOGIC_VECTOR(3 DOWNTO 0);--命令寄存器SIGNAL txd_reg: STD_LOGIC_VECTOR(7 DOWNTO 0);--数据发送寄存器SIGNAL rxd_reg: STD_LOGIC_VECTOR(7 DOWNTO 0);--数据接收寄存器BEGIN

start<=cmd_reg(0);

stop <=cmd_reg(1);

write <=cmd_reg(2);

read <=cmd_reg(3);

data_wr <=txd_reg;

data_out<=rxd_reg;

PROCESS(rst,clk_sys)

BEGIN

IF rst='0' THEN

cmd_reg<="0000";--命令寄存器清零

txd_reg<="00000000";--数据传输寄存器清零

Sta_n<=S0;

ELSIF RISING_EDGE(clk_sys) THEN

CASE sta_n IS

WHEN S0=>

IF ena='1' AND clk_ena='1' THEN

Sta_n<=S1;

Cmd_reg<="0101";--给出启动命令,准备写从机地址

txd_reg <=slave_addr&'0'; --给出从机地址,最低位为0

ELSE

Sta_n<=S0;

cmd_reg <="0000";

END IF;

WHEN S1=>

IF ack_finish='1' THEN--应答完成,1个字节传送完成

IF ack_Flag='1' THEN

cmd_reg <="0010";--非应答,发停止命令

rtx_f<='0'; --传送失败

Sta_n<=S0;

ELSE --应答

cmd_reg <="0100" ; --准备写从机子地址高8位

txd_reg<=sub_addr(15 DOWNTO 8) ; --给出从机子地址高8位

Sta_n<=S2;

END IF;

ELSE

Sta_n<=S1;

END IF;

WHEN S2=>

IF ack_finish='1' THEN

IF ack_Flag='1' THEN

cmd_reg <="0010";--非应答,发停止命令

rtx_f<='0'; --传送失败

Sta_n<=S0;

ELSE --应答

cmd_reg <="0100" ; --准备写从机子地址低8位

txd_reg<=sub_addr(7 DOWNTO 0); --给出从机子地址低8位

Sta_n<=S3;

END IF;

ELSE

Sta_n<=S2;

END IF;

WHEN S3=>

IF ack_finish='1' THEN

IF ack_Flag='1' THEN

cmd_reg <="0010";--非应答,发停止命令

rtx_f<='0'; --传送失败

Sta_n<=S0;

ELSE --应答

IF rw='0' THEN --向从机写1个数据

cmd_reg <="0100" ; --准备写数据

txd_reg<=data_in ; --给出待写数据值

Sta_n<=S4;

ELSE --从从机读1个数据

cmd_reg <="0101";--给出重新启动命令,准备写从机地址

txd_reg <=slave_addr & '1'; --给出从机地址,最低位为1

Sta_n<=S5;

END IF;

END IF;

ELSE Sta_n<=S3;

END IF;

WHEN S4=>

IF ack_finish='1' THEN

cmd_reg <="0010";--发停止命令,结束传送

rtx_f<='1'; --传送成功

Sta_n<=S0;

ELSE Sta_n<=S4;

END IF;

WHEN S5=>

IF ack_finish='1' THEN

IF ack_Flag='1' THEN

cmd_reg <="0010";--发停止命令,结束传送

rtx_f<='0'; --接收失败

相关主题
文本预览
相关文档 最新文档