尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FPGA实战:手把手教你用Verilog驱动AT24C128和LM75,附完整状态机源码

FPGA实战:手把手教你用Verilog驱动AT24C128和LM75,附完整状态机源码 FPGA实战从零构建I2C主控制器驱动AT24C128与LM75在嵌入式系统开发中I2C总线因其简洁的两线制设计和多设备支持特性成为连接各类传感器的首选方案。本文将带您从零开始用Verilog构建一个完整的I2C主控制器实现与AT24C128 EEPROM和LM75温度传感器的通信。不同于简单的代码展示我们将深入探讨状态机设计、时序优化和实际工程中的各种坑。1. I2C协议精要与硬件选型I2C(Inter-Integrated Circuit)总线由Philips公司开发仅需SCL(时钟)和SDA(数据)两根线即可实现多设备通信。在开始编码前我们需要明确几个关键参数通信速率标准模式(100kHz)快速模式(400kHz)设备地址7位地址模式LM75通常为0x48-0x4FAT24C128为0x50-0x57电压电平3.3V或5V兼容器件特性对比特性LM75温度传感器AT24C128 EEPROM典型地址0x480x50数据位宽16位(温度值)8位(字节访问)特殊要求温度转换时间写周期5ms寄存器数量4个连续地址空间实际项目中建议在原理图设计阶段就确认好各设备的地址配置避免地址冲突。2. 状态机架构设计一个健壮的I2C控制器需要处理多种通信场景。我们采用分层状态机设计将控制流程分为顶层事务和底层比特传输两个层次。2.1 顶层状态机parameter MAIN_IDLE 0; // 空闲状态 parameter MAIN_START 1; // 起始条件 parameter MAIN_DEV_ADDR 2; // 发送设备地址 parameter MAIN_REG_ADDR 3; // 发送寄存器地址 parameter MAIN_WRITE 4; // 写数据状态 parameter MAIN_READ 5; // 读数据状态 parameter MAIN_STOP 6; // 停止条件2.2 底层比特传输状态机parameter BIT_START 0; parameter BIT_DATA_LOW 1; // SCL低电平期间准备数据 parameter BIT_DATA_HIGH 2; // SCL高电平期间采样数据 parameter BIT_ACK 3; // 应答周期 parameter BIT_STOP 4;状态转换关键点每个状态必须严格遵循时序要求从设备响应超时需要错误处理机制总线竞争检测与恢复3. Verilog实现详解3.1 模块接口定义module i2c_master ( input clk, // 系统时钟(50MHz) input reset, // 异步复位 output scl, // I2C时钟线 inout sda, // I2C数据线 input [6:0] dev_addr, // 设备地址 input [7:0] reg_addr, // 寄存器地址 input [7:0] data_in, // 写入数据 output [15:0] data_out, // 读取数据 input start, // 启动传输 output reg ready, // 传输完成 output reg error // 传输错误 );3.2 时序参数化设计// 100kHz时钟配置(50MHz系统时钟) parameter PRESCALE 250; // 500ns半周期 parameter T_BUF 50; // 启动/停止条件间隔 parameter T_SU_STA 50; // 启动条件建立时间 parameter T_HD_STA 50; // 启动条件保持时间关键时序约束SCL低电平时间 ≥ 4.7μsSCL高电平时间 ≥ 4.0μs数据建立时间 ≥ 250ns数据保持时间 ≥ 0ns3.3 核心状态机实现always (posedge clk or posedge reset) begin if (reset) begin state MAIN_IDLE; bit_state BIT_START; scl_out 1b1; sda_out 1b1; end else begin case (state) MAIN_START: begin if (bit_done) begin state MAIN_DEV_ADDR; data_shift {dev_addr, 1b0}; // 写命令 end end MAIN_DEV_ADDR: begin if (bit_done) begin if (!ack_received) begin state MAIN_STOP; error 1b1; end else if (write_op) begin state MAIN_REG_ADDR; data_shift reg_addr; end else begin // 读操作需要重新启动 state MAIN_START; end end end // 其他状态处理... endcase end end4. 实战调试技巧4.1 常见问题排查表现象可能原因解决方案无ACK响应设备地址错误/设备未就绪检查地址/测量设备电源数据采样不稳定建立保持时间不足增加SCL低电平时间只能单次通信未正确处理停止条件确保STOP后有足够总线空闲时间高字节数据错误字节序处理不当验证数据移位方向4.2 信号完整性优化上拉电阻选择3.3V系统通常4.7kΩ5V系统通常2.2kΩ长导线适当减小阻值PCB布局建议SCL/SDA走线尽量等长避免与高频信号平行走线必要时添加屏蔽层调试时可先用低速模式(100kHz)稳定后再尝试快速模式(400kHz)5. 功能验证与测试5.1 LM75温度读取测试initial begin // 初始化 reset 1; #100 reset 0; // 读取温度值 dev_addr 7h48; // LM75地址 reg_addr 8h00; // 温度寄存器 start 1; #20 start 0; wait(ready); $display(Temperature: %f, $itor(data_out[15:8]) $itor(data_out[7:5])*0.125); end5.2 AT24C128写入验证task write_eeprom; input [15:0] addr; input [7:0] data; begin // 写入地址 dev_addr 7h50; reg_addr addr[15:8]; data_in addr[7:0]; start 1; #20 start 0; wait(ready); // 写入数据 data_in data; start 1; #20 start 0; wait(ready); // 等待写入完成 #5000000; // 5ms延时 end endtask6. 性能优化进阶6.1 时钟拉伸处理某些从设备(如LM75)可能在温度转换时拉伸SCL时钟。我们需要在Verilog中添加检测逻辑// 检测SCL被从设备拉低 wire scl_stretched (scl_dir 1b0) (scl_in 1b0); always (posedge clk) begin if (scl_stretched) begin scl_counter 0; // 暂停计数器 end end6.2 多设备仲裁当系统中有多个主设备时需要实现总线仲裁监控SDA线与输出是否一致检测到冲突时立即释放总线随机延时后重试传输// 仲裁检测 wire arbitration_lost (sda_out ! sda_in) (sda_dir); always (posedge clk) begin if (arbitration_lost) begin state MAIN_IDLE; error 1b1; end end在完成基础功能后建议添加更多错误检测和恢复机制如从设备无响应超时总线死锁检测时钟频率自适应调整实际项目中I2C控制器的稳定性往往比功能丰富性更重要。一个经过充分测试的基础实现远胜过功能复杂但不可靠的设计。
返回列表