别再怕IIC时序了!用Verilog状态机清晰图解LM75/AT24C128的读写全过程
用Verilog状态机彻底解析IIC协议:从LM75温度读取到AT24C128存储操作实战
IIC(Inter-Integrated Circuit)总线是嵌入式系统中最常用的串行通信协议之一,但它的时序控制和状态跳转逻辑常常让开发者感到困惑。本文将用Verilog状态机的设计思路,带你彻底理解IIC协议的核心机制,并通过LM75温度传感器和AT24C128 EEPROM两个典型设备的操作实例,展示如何构建一个稳健可靠的IIC控制器。
1. IIC协议核心机制解析
IIC协议的精髓在于其简洁的两线制(SCL时钟线和SDA数据线)设计和严格定义的时序规范。要真正掌握IIC,必须理解以下几个关键概念:
基本信号类型:
- 起始条件(START):SCL为高电平时,SDA从高到低的跳变
- 停止条件(STOP):SCL为高电平时,SDA从低到高的跳变
- 数据有效性:SDA数据在SCL高电平期间必须保持稳定
- 应答机制(ACK/NACK):每个字节传输后接收方必须发送应答信号
关键时序参数:
| 参数 | 描述 | 典型值(100kHz) | 典型值(400kHz) |
|---|---|---|---|
| tSU;STA | 起始条件建立时间 | 4.7μs | 0.6μs |
| tHD;STA | 起始条件保持时间 | 4.0μs | 0.6μs |
| tSU;DAT | 数据建立时间 | 250ns | 100ns |
| tHD;DAT | 数据保持时间 | 0ns | 0ns |
| tSU;STO | 停止条件建立时间 | 4.0μs | 0.6μs |
注意:实际设计中应留有时序裕量,避免因信号传输延迟导致通信失败
2. Verilog状态机设计方法论
设计一个稳健的IIC控制器需要采用分层状态机架构,将复杂的通信过程分解为可管理的状态序列。
2.1 顶层状态设计
顶层状态控制整个通信流程:
parameter MAIN_IDLE = 'd20; // 空闲状态 parameter MAIN_STAR = 'd21; // 起始条件 parameter MAIN_DEV0 = 'd22; // 发送设备地址(写) parameter MAIN_ADDR = 'd23; // 发送内存地址 parameter MAIN_REST = 'd24; // 重复起始条件 parameter MAIN_DEV1 = 'd25; // 发送设备地址(读) parameter MAIN_R8BI = 'd26; // 读取数据字节 parameter MAIN_W8BI = 'd27; // 写入数据字节 parameter MAIN_STOP = 'd28; // 停止条件2.2 底层比特级控制
每个顶层状态又细分为底层状态,精确控制每个时钟周期:
// 写数据状态序列 parameter W1BY_SCLL = 'd6; // SCL低电平期间准备数据 parameter W1BY_SCLH = 'd7; // SCL高电平期间保持数据 parameter W1AK_SCLL = 'd8; // 等待ACK的SCL低电平 parameter W1AK_SCLH = 'd9; // 采样ACK的SCL高电平 // 读数据状态序列 parameter R1BY_SCLL = 'd11; // SCL低电平期间释放SDA parameter R1BY_SCLH = 'd12; // SCL高电平期间采样数据 parameter R1AK_SCLL = 'd13; // 发送ACK的SCL低电平 parameter R1AK_SCLH = 'd14; // 发送ACK的SCL高电平2.3 状态跳转逻辑示例
以下是写操作的状态跳转核心代码:
always @(posedge clk or posedge rst) begin if(rst) begin cur_state <= MAIN_IDLE; end else begin case(cur_state) MAIN_IDLE: if(req) cur_state <= MAIN_STAR; MAIN_STAR: if(down_ack) cur_state <= MAIN_DEV0; MAIN_DEV0: if(down_ack) cur_state <= (err_ack) ? MAIN_STOP : MAIN_ADDR; MAIN_ADDR: if(down_ack) cur_state <= (err_ack) ? MAIN_STOP : (wr || ADDR_NUM==0) ? MAIN_W8BI : MAIN_REST; // ...其他状态跳转逻辑 endcase end end3. LM75温度传感器操作实战
LM75是一款广泛使用的数字温度传感器,通过IIC接口提供9位到12位的温度数据。
3.1 LM75关键特性
- 温度测量范围:-55°C 到 +125°C
- 精度:±2°C(-25°C 到 +100°C)
- 温度寄存器格式:16位,高9位有效,LSB=0.125°C
- 设备地址:固定部分1001xxx,可通过引脚配置低三位
寄存器映射:
| 寄存器地址 | 功能描述 |
|---|---|
| 0x00 | 温度值(只读) |
| 0x01 | 配置寄存器 |
| 0x02 | 超温阈值 |
| 0x03 | 迟滞温度 |
3.2 读取温度值的状态机流程
发送设备地址(写模式):
- 状态序列:MAIN_STAR → MAIN_DEV0
- 设备地址:7'b1001xxx + 1'b0(写)
发送温度寄存器地址(0x00):
- 状态序列:MAIN_ADDR → W1BY_SCLL → W1BY_SCLH (循环8次)
重复起始条件:
- 状态序列:MAIN_REST → START_SCLL → START_SCLH
发送设备地址(读模式):
- 状态序列:MAIN_DEV1
- 设备地址:7'b1001xxx + 1'b1(读)
读取温度数据:
- 状态序列:MAIN_R8BI → R1BY_SCLL → R1BY_SCLH (循环8次)
- 最后发送NACK表示读取结束
停止条件:
- 状态序列:MAIN_STOP → STOP_SCLL → STOP_SCLH
提示:LM75的温度数据格式为补码形式,转换时需特别注意符号位处理
4. AT24C128 EEPROM操作详解
AT24C128是128Kbit(16K×8)的串行EEPROM,具有页写和顺序读功能。
4.1 设备特性与注意事项
- 支持100kHz(1.8V)和400kHz(2.5V)两种速度
- 页写模式:最多64字节/页
- 写入周期时间:典型5ms
- 设备地址:1010xxx,其中xxx由A2,A1,A0引脚决定
重要限制:
- 两次写入操作之间必须留有足够时间(通常5ms)
- 单字节写入和页写入的时序要求不同
- 超过页边界时会回卷到页首
4.2 写操作状态机设计
单字节写入的状态序列:
开始 → 设备地址(写) → 应答 → 高字节地址 → 应答 → 低字节地址 → 应答 → 数据字节 → 应答 → 停止对应的Verilog状态跳转:
MAIN_STAR → MAIN_DEV0 → MAIN_ADDR → W1BY_SCLL → W1BY_SCLH → ... → MAIN_W8BI → W1BY_SCLL → W1BY_SCLH → MAIN_STOP4.3 读操作特殊处理
顺序读操作需要特别注意"伪写入"阶段:
- 先以写模式发送内存地址
- 发送重复起始条件
- 切换为读模式并接收数据
状态序列示例:
开始 → 设备地址(写) → 应答 → 地址高字节 → 应答 → 地址低字节 → 应答 → 重复开始 → 设备地址(读) → 应答 → 读取数据(带ACK/NACK) → ... → 停止5. 关键时序参数的Verilog实现
精确控制时序是IIC可靠通信的核心。以下是400kHz模式下的典型实现:
parameter tSYSCLK = 20; // 系统时钟周期20ns(50MHz) parameter tCLK = 4000/tSYSCLK; // SCL周期2500ns(400kHz) parameter tLOW = 2000/tSYSCLK; // SCL低电平时间1000ns parameter tHIGH = tCLK-tLOW; // SCL高电平时间1500ns parameter tHDDAT = 1000/tSYSCLK; // 数据保持时间 parameter tSUDAT = tLOW-tHDDAT; // 数据建立时间 // 时序控制计数器 always @(posedge clk or posedge rst) begin if(rst) delay_cnt <= 0; else if(state_change) delay_cnt <= 0; else delay_cnt <= delay_cnt + 1; end总线释放时机:
- 主设备发送完最后一个ACK后,应在50ns内释放SDA
- 从设备切换方向时,主设备应等待足够时间(通常300-400ns)
// 总线释放实现示例 R1AK_SCLL: begin if(delay_cnt==tHDDAT) begin sda_is_out <= 1; // 准备发送ACK/NACK sda_o <= (data_cnt==DATA_NUM); // 最后一个字节发NACK end end在实际项目中调试IIC通信时,最常遇到的问题往往与时序裕量不足或总线竞争有关。特别是在多主设备系统中,必须严格遵循总线仲裁规则,确保不会出现两个设备同时驱动总线的情况。
