云计算百科
云计算领域专业知识百科平台

verilog实现IIC(集成电路总线)协议

IIC (Inter‑Integrated Circuit) 集成电路总线

文章目录

  • IIC (Inter‑Integrated Circuit) 集成电路总线
    • 一、IIC 总线概述
    • 二、物理层
    • 三、设备寻址:7+1 字节格式
    • 四、设备角色与功能
      • 主设备
      • 从设备
    • 五、通信速率
    • 六、协议层
      • 6.1 起始信号 & 停止信号
      • 6.2 数据位传输规则
      • 6.3 ACK 应答信号
      • 6.4 三种工作模式
      • 6.5 多主机与总线仲裁
    • 七、IIC 核心小结
    • 八、Verilog 实现 IIC 协议

摘要:IIC(Inter‑Integrated Circuit)是一种两线式双向串行总线,仅需 SDA(数据线)与 SCL(时钟线)两根信号线,配合外部上拉电阻即可实现主从设备间的板内短距离通信。本文从物理层、设备寻址(7 位地址 + 1 位读写位)、设备角色、通信速率与协议层(起始/停止信号、数据位传输、ACK 应答、多主机仲裁)逐层讲解 IIC 核心机制,并给出基于三段式状态机的 Verilog 完整实现与仿真代码,帮助读者从原理到代码全面掌握 IIC 协议。

一、IIC 总线概述

IIC(Inter‑Integrated Circuit,集成电路总线),主要用于连接微控制器与各类外围器件,实现芯片与芯片之间的通信。 可以在 CPU 与被控 IC、IC 与 IC 之间完成双向数据传输,高速 IIC 总线速率可达 400kbps 以上。

适用场景:主控制器与从器件的主从通信,适合小数据量、短距离板内通信; 约束特性:任意时刻总线只允许存在一个有效主机;从机与从机之间不能直接交换数据,必须经过主机转发。

二、物理层

IIC 是两线式双向串行总线,只需要两根信号线:在这里插入图片描述

  • SDA(Serial Data):串行数据线,负责传输实际收发的数据。
  • SCL(Serial Clock Line):串行时钟线,由主机产生时钟,控制数据收发时序。
  • 总线硬件要求:SDA、SCL 两根信号线必须外接上拉电阻,阻值根据通信速率、总线容性负载选择,常用取值3.3kΩ ~ 10kΩ。总线空闲时两根线被上拉电阻拉为高电平;器件内部为开漏输出结构,依靠高阻态实现线与逻辑。

    总线上挂载的每一个 IIC 从设备,都拥有唯一设备地址,主机依靠地址区分不同从机,保证访问准确。

    三、设备寻址:7+1 字节格式

    IIC 读写寻址字节一共 8bit:7bit从机设备地址 + 1bit读写方向位在这里插入图片描述

    • bit7~bit1:7 位从机设备地址,用来寻找总线上目标从机
    • bit0:读写方向位
      • 0:主机向从机写数据
      • 1:主机从从机读数据

    注意:IIC 器件内部 IO 为开漏结构,总线空闲时 SDA、SCL 处于高阻态,依靠外部上拉电阻拉高电平。

    四、设备角色与功能

    主设备

  • 产生 SCL 时钟信号
  • 产生起始信号、停止信号
  • 发起总线访问、发送寻址字节
  • 从设备

  • 检测总线上的设备地址,匹配自身地址后响应
  • 检测起始位、停止位,配合主机完成应答与数据收发
  • IIC 支持多主机模式(multimastering),一条总线可以挂多个主机; 重点:同一时间只允许一个主机掌握总线控制权。 多主机场景依靠总线仲裁机制,避免多个主机同时发送信号造成冲突。在这里插入图片描述

    五、通信速率

    • 标准模式:最高 100kHz
    • 快速模式:最高 400kHz
    • 超高速模式:最高3.4MHz

    通信属性:同步、串行、半双工

    • 同步:通信时序完全跟随 SCL 时钟;
    • 串行:数据按 bit 逐位传输;
    • 半双工:同一时刻只能单向传输,不能同时收发。

    六、协议层

    6.1 起始信号 & 停止信号

    • 起始信号 (S):SCL 为高电平时,SDA 由高电平跳变到低电平,表示通信开始。
    • 口诀:sda先拉低,scl后拉低。在这里插入图片描述
    • 停止信号 §:SCL 为高电平时,SDA 由低电平跳变到高电平,表示通信结束,总线回到空闲状态。
    • 口诀:sda后拉高,scl先拉高。在这里插入图片描述

    只有 SCL 处于高电平期间,SDA 的跳变才代表起始 / 停止;SCL 低电平时,允许 SDA 改变电平,用来传输数据 bit。

    6.2 数据位传输规则

    SCL 高电平阶段:SDA 电平必须保持稳定,接收端采样 SDA 得到数据; SCL 低电平阶段:允许 SDA 电平翻转,准备下一位数据。 每传输 1bit 数据,对应一个 SCL 时钟周期。 口诀:低电平切换数据,高电平保持。在这里插入图片描述

    6.3 ACK 应答信号

    每发送完 8bit(1 字节)数据之后,接收方需要拉低 SDA 产生应答 ACK;

    • ACK(应答):接收方将 SDA 拉低,告诉发送方接收正常;
    • NACK(非应答):SDA 保持高电平,代表无应答,通常表示从机未收到、结束读操作。在这里插入图片描述

    6.4 三种工作模式

    • 写模式:开始信号 →主机发从机地址 + 写位 → 从机 ACK → 主机发送寄存器地址/或者直接从头开始写数据 → 从机 ACK → 主机发送数据 → 从机 ACK… → 停止信号在这里插入图片描述
    • 读模式:开始信号 → 主机发从机地址 + 读位 → 从机ACK → 主机读取数据(变现为不工作,高阻态,通过上拉电阻输入数据)→ 主机ACK → 读取下一个数据 →主机ACK…→主机NACK→停止信号在这里插入图片描述
    • 先写后读模式:开始信号 → 主机发从机地址 + 写位 → 指定寄存器或先从头写入数据→…→从机ACK → 重新发起起始→发送从机地址 + 读位 → 从机 ACK → 从机输出数据 → 主机ACK…→ 主机 NACK → 发出停止信号结束读取。在这里插入图片描述

    6.5 多主机与总线仲裁

    多个主机同时抢占总线时,仲裁逻辑: 主机一边发送数据,一边实时监听 SDA 总线电平; 如果自己输出高电平,但总线被别的主机拉为低电平,代表仲裁失败,该主机立刻停止发送,让出总线,等待总线空闲后重新发起通信。

    七、IIC 核心小结

  • 硬件:SDA+SCL,开漏输出,必须外部上拉电阻;空闲总线为高电平;
  • 寻址:7 位设备地址 + 1 位读写位;从机之间不能直接通信;
  • 信号:起始、停止、应答 ACK/NACK,SCL 高电平采样数据,SCL低电平SDA转换;
  • 支持多主机,但同一时刻仅有一个主机有效,依靠总线仲裁解决冲突;
  • 半双工同步串行,适合板内短距离小数据外设(OLED、DS18B20、EEPROM 等)。
  • 八、Verilog 实现 IIC 协议

    说明:为本篇初稿实现,支持 IIC 写、读、组合读写(重复起始),内部采用三段式状态机,使用三态门处理 SDA/SCL 双向端口。

    module top (
    input wire clk ,
    input wire rst_n ,
    input wire start_iic ,//协议开始信号
    input wire worr ,//方向信号
    input wire [7:0] sendnum ,//器件规定主机的写入数据量
    input wire [7:0] recvnum ,//规定主机的读出数据量
    input wire [7:0] data_i_iic ,//外部给到的数据
    output wire [7:0] data_o_iic ,//从机里面读到、输出的数据
    output wire done_w ,//完成一次写数据的握手信号
    output wire done_r ,//完成一次读数据的握手信号
    output wire done_iic ,//完成一次iic通信的握手信号
    output wire wrong ,//报警信号
    inout wire scl ,//时钟总线
    inout wire sda //数据总线
    );
    //参数
    parameter sysclk = 50_000_000 ,//系统时钟
    iiclk = 100_000 ,//iic速率
    delay = sysclk/iiclk ,//发一比特所用周期数10us
    MID = delay/2 ,//5us
    Q_MID = delay/4 ,//2.5us
    TQ_MID = MID + Q_MID ,//12.5us
    ID_W = 8'b1010_0000 ,//设备ID+方向
    ID_R = 8'b1010_0001 ;//设备ID+方向

    //状态定义
    localparam IDLE = 'd1 ,
    START1 = 'd2 ,
    IDW = 'd3 ,
    ACK1 = 'd4 ,
    WDATA = 'd5 ,
    ACK2 = 'd6 ,
    STOP = 'd7 ,
    IDR = 'd8 ,
    ACK3 = 'd9 ,
    RDATA = 'd10 ,
    ACK4 = 'd11 ,
    START2 = 'd12 ;

    reg [3:0] state_c,state_n;

    //状态转移
    wire IDLE_START1 ,
    START1_IDW ,
    IDW_ACK1 ,
    ACK1_WDATA ,
    WDATA_ACK2 ,
    ACK2_WDATA ,
    ACK2_STOP ,//第一种工作模式:IDLE -> START1 -> IDW -> ACK1 -> WDATA <–> ACK2 ->STOP ->ILDE
    START1_IDR ,
    IDR_ACK3 ,
    ACK3_RDATA ,
    RDATA_ACK4 ,
    ACK4_RDATA ,
    ACK4_STOP ,//第二种工作模式:IDLE -> START1 -> IDR -> ACK3 -> RDATA <–> ACK4 ->STOP ->ILDE
    ACK2_START2 ,
    START2_IDR ,//第三种工作方式:IDLE -> START1 -> IDW -> ACK1 -> WDATA <–> ACK2 -> IDR -> ACK3 -> RDATA <–> ACK4 ->STOP ->ILDE
    ACK1_STOP ,//从机错误应答情况
    ACK3_STOP ,//从机错误应答情况
    STOP_IDLE ;

    //内部信号
    //计数器
    reg [9:0] cnt_time ;//时间计数
    reg [3:0] cnt_bit ;//比特计数
    //寄存信号
    reg [1:0] start_reg ;//协议开始,两个位宽是为了后续根据需求选择长短信号
    reg worr_reg ;//工作模式1/2选择
    reg [7:0] sendnum_reg ;
    reg [7:0] recvnum_reg ;
    reg [7:0] data_reg ;
    //数据量计数
    reg [7:0] sendcnt ;//发送计数
    reg [7:0] recvcnt ;//接收计数
    //数据暂存和应答信号
    reg [7:0] data_temp ;
    reg ack_flag ;//应答信号
    //三态门信号
    reg scl_en ;
    reg scl_out ;
    wire scl_in ;

    reg sda_en ;
    reg sda_out ;
    wire sda_in ;

    //三态门
    assign scl = scl_en ? scl_out : 1'bz;
    assign scl_in = scl;

    assign sda = sda_en ? sda_out : 1'bz;
    assign sda_in = sda;

    //输入数据寄存
    always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
    start_reg <= 2'b00;
    end
    else begin
    start_reg <= {start_reg[0],start_iic};
    end
    end

    //状态机第一段
    always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
    state_c <= IDLE;
    end
    else begin
    state_c <= state_n;
    end
    end

    //状态机第二段
    always @(*) begin
    if (rst_n == 0) begin
    state_n = IDLE;
    end
    else begin
    case (state_c)
    IDLE : state_n = (IDLE_START1) ? START1: IDLE ;
    START1 : state_n = (START1_IDW ) ? IDW : (START1_IDR) ? IDR : START1;
    IDW : state_n = (IDW_ACK1 ) ? ACK1 : IDW ;
    ACK1 : state_n = (ACK1_STOP ) ? STOP : (ACK1_WDATA) ? WDATA : ACK1;
    WDATA : state_n = (WDATA_ACK2 ) ? ACK2 : WDATA ;
    ACK2 : state_n = (ACK2_STOP ) ? STOP : (ACK2_START2)?START2 :(ACK2_WDATA ) ? WDATA : ACK2;
    STOP : state_n = (STOP_IDLE ) ? IDLE : STOP ;
    IDR : state_n = (IDR_ACK3 ) ? ACK3 : IDR ;
    ACK3 : state_n = (ACK3_STOP ) ? STOP : (ACK3_RDATA ) ? RDATA : ACK3;
    RDATA : state_n = (RDATA_ACK4 ) ? ACK4 : RDATA ;
    ACK4 : state_n = (ACK4_STOP ) ? STOP : (ACK4_RDATA ) ? RDATA : ACK4;
    START2 : state_n = (START2_IDR ) ? IDR : START2 ;
    default: state_n = IDLE;
    endcase
    end
    end

    assign IDLE_START1 = (state_c == IDLE ) && start_reg == 2'b01;
    assign START1_IDW = (state_c == START1) && cnt_time == delay + Q_MID – 1 && worr_reg == 0;
    assign START1_IDR = (state_c == START1) && cnt_time == delay + Q_MID – 1 && worr_reg == 1;
    assign IDW_ACK1 = (state_c == IDW ) && cnt_time == delay – 1 && cnt_bit == 7;
    assign ACK1_STOP = (state_c == ACK1 ) && cnt_time == delay – 1 && ack_flag == 1;
    assign ACK1_WDATA = (state_c == ACK1 ) && cnt_time == delay – 1 && ack_flag == 0;
    assign WDATA_ACK2 = (state_c == WDATA ) && cnt_time == delay – 1 && cnt_bit == 7;
    assign ACK2_STOP = (state_c == ACK2 ) && cnt_time == delay – 1 && (sendcnt == sendnum && recvnum == 0 && ack_flag == 0)||ack_flag == 1;
    assign ACK2_WDATA = (state_c == ACK2 ) && cnt_time == delay – 1 && sendcnt < sendnum && ack_flag == 0;
    assign IDR_ACK3 = (state_c == IDR ) && cnt_time == delay – 1 && cnt_bit == 7;
    assign ACK3_STOP = (state_c == ACK3 ) && cnt_time == delay – 1 && ack_flag == 1;
    assign ACK3_RDATA = (state_c == ACK3 ) && cnt_time == delay – 1 && ack_flag == 0;
    assign RDATA_ACK4 = (state_c == RDATA ) && cnt_time == delay – 1 && cnt_bit == 7;
    assign ACK4_STOP = (state_c == ACK4 ) && cnt_time == delay – 1 && recvcnt == recvnum;
    assign ACK2_START2 = (state_c == ACK2 ) && cnt_time == delay – 1 && sendcnt == sendnum && recvnum != 0;
    assign ACK4_RDATA = (state_c == ACK4 ) && cnt_time == delay – 1 && recvcnt < recvnum;
    assign START2_IDR = (state_c == START2) && cnt_time == delay + Q_MID – 1 ;
    assign STOP_IDLE = (state_c == STOP ) && cnt_time == delay + Q_MID – 1 ;

    //状态机第三段
    always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
    //计数
    cnt_time <= 0;
    cnt_bit <= 0;
    //寄存
    worr_reg <= 0;
    sendnum_reg <= 0;
    recvnum_reg <= 0;
    data_reg <= 0;
    //数据量
    sendcnt <= 0;
    recvcnt <= 0;

    data_temp <= 0;
    ack_flag <= 0;
    //三态门
    scl_en <= 0;
    sda_en <= 0;
    scl_out <= 0;
    sda_out <= 0;
    end
    else begin
    case (state_c)
    IDLE :begin//寄存信号,主机不工作
    //计数
    cnt_time <= 0;
    cnt_bit <= 0;
    //寄存
    worr_reg <= worr;
    sendnum_reg <= sendnum;
    recvnum_reg <= recvnum;
    data_reg <= data_i_iic;
    //数据量计数
    sendcnt <= 0;
    recvcnt <= 0;

    data_temp <= 0;
    ack_flag <= 0;
    //三态门
    scl_en <= 0;
    sda_en <= 0;
    scl_out <= 1;//象征为高阻,但实际上不会被输出
    sda_out <= 1;//象征为高阻,但实际上不会被输出
    end
    START1,START2:begin//开始时序:主机工作,sda先拉低,scl后拉低
    //计数
    if (cnt_time == delay + Q_MID – 1) begin//计数12.5us
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    cnt_bit <= 0;

    //三态门
    scl_en <= 1;
    sda_en <= 1;

    if (cnt_time >= delay) begin
    scl_out <= 0;
    end
    else begin
    scl_out <= 1;
    end
    if (cnt_time >= MID) begin
    sda_out <= 0;
    end
    else begin
    sda_out <= 1;
    end
    end
    IDW :begin//主机工作:发送从机地址
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    if (cnt_time == delay – 1) begin
    if (cnt_bit == 7) begin
    cnt_bit <= 0;
    end
    else begin
    cnt_bit <= cnt_bit + 1;
    end
    end

    //三态门
    scl_en <= 1;
    sda_en <= 1;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    if (cnt_time == 1) begin
    sda_out <= ID_W[7 – cnt_bit];//高位优先
    end
    end
    ACK1,ACK3:begin//采集应答信号、维持时钟输出
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    cnt_bit <= 0;
    //寄存

    if (cnt_time == MID) begin//采样点
    ack_flag <= sda_in;
    end

    //三态门
    scl_en <= 1;
    sda_en <= 0;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    sda_out <= 1;
    end
    WDATA :begin//主机工作:写数据、数据量计数保持
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    if (cnt_time == delay – 1) begin
    if (cnt_bit == 7) begin
    cnt_bit <= 0;
    end
    else begin
    cnt_bit <= cnt_bit + 1;
    end
    end

    //三态门
    scl_en <= 1;
    sda_en <= 1;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    if (cnt_time == 0) begin
    sda_out <= data_reg[7 – cnt_bit];//高位优先
    end
    end
    ACK2 :begin//采集应答信号、维持时钟输出、对数据量进行计数
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    cnt_bit <= 0;
    //寄存

    if (cnt_time == 0) begin//完成一次数据写入,计数+1
    sendcnt <= sendcnt + 1;
    end

    //更新数据
    data_reg <= data_i_iic;

    if (cnt_time == MID) begin//采样点
    ack_flag <= sda_in;
    end

    //三态门
    scl_en <= 1;
    sda_en <= 0;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    sda_out <= 1;
    end
    STOP :begin//停止时序:主机工作,sda后拉高,scl先拉高
    //计数
    if (cnt_time == delay + Q_MID – 1) begin//计数12.5us
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    cnt_bit <= 0;

    //三态门
    scl_en <= 1;
    sda_en <= 1;

    if (cnt_time >= Q_MID) begin
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    if (cnt_time >= TQ_MID) begin
    sda_out <= 1;
    end
    else begin
    sda_out <= 0;
    end
    end
    IDR :begin//主机工作:发送从机地址
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    if (cnt_time == delay – 1) begin
    if (cnt_bit == 7) begin
    cnt_bit <= 0;
    end
    else begin
    cnt_bit <= cnt_bit + 1;
    end
    end

    //三态门
    scl_en <= 1;
    sda_en <= 1;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    if (cnt_time == 1) begin
    sda_out <= ID_R[7 – cnt_bit];//高位优先
    end
    end
    RDATA :begin//从机工作,主机读数据、数据量计数保持
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    if (cnt_time == delay – 1) begin
    if (cnt_bit == 7) begin
    cnt_bit <= 0;
    end
    else begin
    cnt_bit <= cnt_bit + 1;
    end
    end

    if (cnt_time == MID) begin
    data_temp[7-cnt_bit] <= sda_in;
    end

    //三态门
    scl_en <= 1;
    sda_en <= 0;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    sda_out <= 1;
    end
    ACK4 :begin//发出应答信号
    //计数
    if (cnt_time == delay – 1) begin//周期计数
    cnt_time <= 0;
    end
    else begin
    cnt_time <= cnt_time + 1;
    end
    cnt_bit <= 0;
    //寄存

    if (cnt_time == 0) begin//完成一次数据写入,计数+1
    recvcnt <= recvcnt + 1;
    end

    //三态门
    scl_en <= 1;
    sda_en <= 1;

    if (cnt_time >=Q_MID && cnt_time <= TQ_MID-1) begin//两边高中间低
    scl_out <= 1;
    end
    else begin
    scl_out <= 0;
    end
    if (recvcnt == recvnum) begin
    sda_out <= 1;
    end
    else begin
    sda_out <= 0;
    end
    end
    default: begin
    //计数
    cnt_time <= 0;
    cnt_bit <= 0;
    //寄存
    worr_reg <= 0;
    sendnum_reg <= 0;
    recvnum_reg <= 0;
    data_reg <= 0;
    //数据量
    sendcnt <= 0;
    recvcnt <= 0;

    data_temp <= 0;
    ack_flag <= 0;
    //三态门
    scl_en <= 0;
    sda_en <= 0;
    scl_out <= 0;
    sda_out <= 0;
    end
    endcase
    end
    end

    //输出信号
    assign data_o_iic = (state_c == ACK4) ? data_temp : 0;
    assign done_r = (state_c == ACK4 && cnt_time == MID) ? 1 : 0;
    assign done_w = (state_c == ACK2 && cnt_time == MID) ? 1 : 0;
    assign done_iic = (state_c == STOP && cnt_time == MID) ? 1 : 0;
    assign wrong = (state_c == STOP && cnt_time == MID && (sendcnt!=sendnum || recvcnt!=recvnum ));

    endmodule

    • 仿真代码和波形

    module tb ();

    reg clk ;
    reg rst_n ;
    reg start_iic ;
    reg [7:0] data_i_iic ;

    wire [7:0] data_o_iic ;
    wire done_w ;
    wire done_r ;
    wire done_iic ;
    wire wrong ;
    tri0 scl ;
    tri0 sda ;

    initial begin
    clk <= 0;
    rst_n <= 0;
    start_iic <= 0;
    #20
    rst_n <= 1;
    #100
    start_iic <= 1;
    #100
    start_iic <= 0;
    end

    always #10 clk = ~clk;

    always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
    data_i_iic <= 8'h22;
    end
    else if(done_w)begin
    data_i_iic <=data_i_iic + 1;
    end
    end

    top top_inst(
    .clk (clk ),
    .rst_n (rst_n ),
    .start_iic (start_iic ),
    .worr (0 ),
    .sendnum (4 ),
    .recvnum (3 ),
    .data_i_iic (data_i_iic),
    .data_o_iic (data_o_iic),
    .done_w (done_w ),
    .done_r (done_r ),
    .done_iic (done_iic ),
    .wrong (wrong ),
    .scl (scl ),
    .sda (sda )
    );

    endmodule

    在这里插入图片描述

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » verilog实现IIC(集成电路总线)协议
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!