I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态

I2C总线基本工作原理:

  以启动信号START来掌管总线,以停止信号STOP来释放总线;

  每次通讯以START开始,以STOP结束;

 

  启动信号START后紧接着发送一个地址字节,其中7位为被控器件的地址码,一位为读/写控制位R/W,R. /W位为0表示由主控向被控器件写数据,R/W为1表示由主控向被控器件读数据;

  当被控器件检测到收到的地址与自己的地址相同时,在第9个时钟期间反馈应答信号;

  每个数据字节在传送时都是高位(MSB)在前;

  怎么判断i2c总线空闲状态

  I2C总线写通讯过程:

  1. 主控在检测到总线空闲的状况下,首先发送一个START信号掌管总线;

  2. 发送一个地址字节(包括7位地址码和一位R/W);

  3. 当被控器件检测到主控发送的地址与自己的地址相同时发送一个应答信号(ACK);

  4. 主控收到ACK后开始发送第一个数据字节;

  5. 被控器收到数据字节后发送一个ACK表示继续传送数据,发送NACK表示传送数据结束;

  6. 主控发送完全部数据后,发送一个停止位STOP,结束整个通讯并且释放总线;

 

  总线信号分析

  1. 总线空闲状态

  I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

怎么判断i2c总线空闲状态

  2. 启动信号START

  时钟信号SCL保持高电平,数据信号SDA的电平被拉低(即负跳变)。启动信号必须是跳变信号,而且在建立该信号前必修保证总线处于空闲状态;

  3. 停止信号STOP

  时钟信号SCL保持高电平,数据线被释放,使得SDA返回高电平(即正跳变),停止信号也必须是跳变信号。

怎么判断i2c总线空闲状态

  4. 数据传送

  SCL线呈现高电平期间,SDA线上的电平必须保持稳定,低电平表示0(此时的线电压为地电压),高电平表示1(此时的电压由元器件的VDD决定)。只有在SCL线为低电平期间,SDA上的电平允许变化。

  5. 应答信号ACK

  I2C总线的数据都是以字节(8位)的方式传送的,发送器件每发送一个字节之后,在时钟的第9个脉冲期间释放数据总线,由接收器发送一个ACK(把数据总线的电平拉低)来表示数据成功接收。

  6. 无应答信号NACK

  在时钟的第9个脉冲期间发送器释放数据总线,接收器不拉低数据总线表示一个NACK,NACK有两种用途:

  a. 一般表示接收器未成功接收数据字节;

  b. 当接收器是主控器时,它收到最后一个字节后,应发送一个NACK信号,以通知被控发送器结束数据发送,并释放总线,以便主控接收器发送一个停止信号STOP。

  I2C总线是由Philips公司开发的两线式串行总线,用于连接微控制器和外围设备。

  I2C总线支持多主控模式,任何能够进行发送和接收的设备都可以成为主设备。主控能够控制数据的传输和时钟频率,在任意的时刻只能有一个主控。

  组成I2C总线的两个信号为数据线SDA和时钟线SCL。为避免总信号线的混乱,要求各设备连接到总线的输出端必须是开漏输出或集电极开路输出的结构。根据这种结构的“线与”逻辑,I2C总线上任意器件输出低电平都会使相应总线上的信号线变低。

  总线空闲时,上拉电阻使SDA和SCL线都保持高电平。

  数据线 SDA 的电平状态必须在时钟线 SCL 处于高电平期间保持稳定不变。SDA 的电平状态只有在 SCL 处于低电平期间才允许改变。但是在 I2C总线的起始和结束时例外。

  当SCL稳定在高电平时,SDA由高到低的变化将产生一个开始位,而由低到高的变化则产生一个停止位。开始位和停止位都是由I2C主设备产生的。如果从设备采用7位地址,则主设备在发起传输前,需先发送一字节的地址信息,前7位为设备地址,最后1位为读写标志。之后每次传输的数据也是一个字节,从MSB位(Most Significant Bit 最高有效位,对应有LSB: Least Significant Bit 最低有效位)开始传输。每个字节传完后,在SCL的第9个上升沿到来之前,接受方应该发出一个ACK位。

  应答位的时钟脉冲仍由主机产生,而应答位的数据状态则遵循“谁接收谁产生”的原则,即总是由接收器产生应答位。主机向从机发送数据时,应答位由从机产生;主机从从机接收数据时,应答位由主机产生。I2C总线标准规定:应答位为 0 表示接收器应答(ACK) ,常常简记为 A;为 1 则表示非应答(NACK) ,常常简记为NA。发送器发送完 LSB 之后,应当释放 SDA 线(拉高 SDA,输出晶体管截止) ,以等待接收器产生应答位。

  在切换数据的传输方向时,可以不必先产生停止条件再开始下次传输,而是直接再一次产生开始条件。I2C 总线在已经处于忙的状态下,再一次直接产生起始条件的情况被称为重复起始条件。例如:访问某一具有 I2C总线接口的 E2PROM 存储器时,主机先向存储器输入存储单元的地址信息(发送数据) ,然后再读取其中的存储内容(接收数据)。

  带有 I2C 总线的器件除了有从机地址(Slave Address)外,还可能有子地址。从机地址是指该器件在 I2C 总线上被主机寻址的地址, 而子地址是指该器件内部不同部件或存储单元的编址。 与从机地址一样,子地址实际上也是像普通数据那样进行传输的,传输格式仍然是与数据相统一的,区分传输的到底是地址还是数据要靠收发双方具体的逻辑约定。子地址的长度必须由整数个字节组成,可能是单字节(8 位子地址) ,也可能是双字节(16 位子地址) ,还可能是 3 字节以上,这要看具体器件的规定。

  • 11
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个基本的Verilog代码示例,用于I2C总线的读取和写入。这里假设I2C总线SCL钟频率为100 kHz,可以根据需要进行修改。 ``` module i2c_master ( input wire i_clk, // 钟 input wire i_reset, // 复位信号 inout wire io_sda, // 数据线 output wire o_scl // 钟线 ); // 定义I2C总线状态 localparam S_IDLE = 3'b000; // 空闲状态 localparam S_START = 3'b001; // 起始状态 localparam S_ADDR = 3'b010; // 地址状态 localparam S_READ = 3'b011; // 读取状态 localparam S_WRITE = 3'b100; // 写入状态 localparam S_STOP = 3'b101; // 停止状态 // 定义I2C总线数据传输方向 localparam D_WRITE = 1'b0; // 写入 localparam D_READ = 1'b1; // 读取 // 定义I2C总线地址 localparam I2C_ADDRESS = 7'h50; // I2C设备地址 // 定义I2C总线钟周期 localparam T_HALF = 5; // 半个钟周期,用于序控制 // 定义I2C总线控制信号 reg [2:0] state; // 状态 reg [7:0] data_out; // 输出数据 reg [7:0] data_in; // 输入数据 reg [6:0] address; // 地址 reg rw; // 读/写 reg busy; // 忙标志位 reg done; // 完成标志位 // 状态转移 always @ (posedge i_clk) begin if (i_reset) begin state <= S_IDLE; address <= 0; data_out <= 0; data_in <= 0; rw <= D_WRITE; busy <= 0; done <= 0; end else begin case (state) S_IDLE: begin // 空闲状态 o_scl <= 1; io_sda <= 1; if (!done) begin state <= S_START; end end S_START: begin // 起始状态 o_scl <= 1; io_sda <= 0; state <= S_ADDR; end S_ADDR: begin // 地址状态 o_scl <= 1; if (busy) begin state <= S_READ; end else begin io_sda <= 1; if (rw == D_WRITE) begin // 写入 data_out <= address; state <= S_WRITE; end else begin // 读取 data_out <= (I2C_ADDRESS << 1) | D_READ; state <= S_READ; end end end S_READ: begin // 读取状态 o_scl <= 1; if (io_sda == 0 ### 回答2: 以下是一个用于实现I2C总线读写的完整Verilog代码: ```verilog module i2c ( input wire clk, input wire resetn, input wire scl, inout wire sda, input wire read_write, input wire [7:0] slave_address, inout wire [7:0] data_in, output wire [7:0] data_out, inout wire ack ); reg [7:0] data_reg; reg [7:0] control_reg; reg data_valid; reg ack_reg; wire read_mode; wire write_mode; wire start_condition; wire stop_condition; wire address_received; wire data_received; wire data_requested; // I2C状态机定义 parameter IDLE = 0; parameter START_BIT = 1; parameter ADDRESS_BIT = 2; parameter ACK_BIT = 3; parameter DATA_BIT = 4; parameter SEND_ACK = 5; parameter READ_DATA = 6; parameter STOP_BIT = 7; reg [2:0] state_reg; assign read_mode = ~read_write; assign write_mode = read_write; assign start_condition = (~sda & scl); assign stop_condition = (sda & scl); assign address_received = (state_reg == ADDRESS_BIT); assign data_received = (state_reg == DATA_BIT); assign data_requested = (state_reg == SEND_ACK || state_reg == READ_DATA); // I2C状态机逻辑 always @(posedge clk or negedge resetn) begin if (~resetn) begin state_reg <= IDLE; data_valid <= 0; ack_reg <= 0; end else begin case (state_reg) IDLE: if (start_condition) state_reg <= START_BIT; START_BIT: if (scl) state_reg <= ADDRESS_BIT; ADDRESS_BIT: if (~scl) state_reg <= ACK_BIT; ACK_BIT: if (scl) state_reg <= DATA_BIT; DATA_BIT: if (~scl) state_reg <= SEND_ACK; SEND_ACK: if (scl) state_reg <= READ_DATA; READ_DATA: if (~scl) state_reg <= STOP_BIT; STOP_BIT: if (stop_condition) state_reg <= IDLE; endcase end end // 数据处理逻辑 always @(posedge clk or negedge resetn) begin if (~resetn) begin ack_reg <= 0; data_valid <= 0; data_reg <= 0; end else begin case (state_reg) IDLE: if (start_condition) ack_reg <= 0; ADDRESS_BIT: if (~scl) ack_reg <= 1; DATA_BIT: if (~scl) ack_reg <= 1; END_DATA_BIT: if (~scl) ack_reg <= 1; READ_DATA: if (~scl) data_valid <= 1; else if (scl) data_valid <= 0; STOP_BIT: if (stop_condition) ack_reg <= 0; endcase if (address_received || data_received) data_valid <= 1; else if (address_received || data_requested) data_valid <= 0; if (data_valid) data_reg <= data_in; end end // I2C总线物理层逻辑 always @(posedge clk or negedge resetn) begin if (~resetn) begin sda <= 1; ack <= 1; end else begin case (state_reg) START_BIT: sda <= 0; ADDRESS_BIT: sda <= slave_address[0]; DATA_BIT: sda <= data_reg[0]; READ_DATA: sda <= data_out[0]; STOP_BIT: sda <= 1; endcase if ((state_reg == ACK_BIT && ack_reg) || (state_reg == SEND_ACK && !ack_reg)) ack <= 1; else ack <= 0; end end endmodule ``` 此Verilog代码实现了I2C总线的读写操作。主要模块包括I2C状态机逻辑模块、数据处理逻辑模块和I2C总线物理层逻辑模块。它定义了I2C总线的各个状态(如IDLE、START_BIT、ADDRESS_BIT等等)和相应的状态转换逻辑。该代码还处理了数据的读写、ACK的发送、中断条件的检测等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值