FPGA驱动DS18B20温度传感器的设计与实现

1. 项目背景与核心挑战

在工业自动化、环境监测和智能家居等领域,温度测量始终是基础且关键的一环。DS18B20作为Dallas Semiconductor(现Maxim Integrated)推出的经典数字温度传感器,凭借其单总线接口、高精度和宽量程等特性,成为众多嵌入式系统的首选。然而,当我们需要在FPGA平台上实现DS18B20驱动时,面临的挑战与传统MCU方案截然不同。

FPGA的并行处理能力与可编程特性使其在实时性要求高的场景中具有独特优势,但同时也带来了时序控制的复杂性。DS18B20的单总线协议对时序精度要求极为严苛——复位脉冲宽度需控制在480μs至960μs之间,位读写间隔必须精确到微秒级。这种精度要求对FPGA设计提出了三个核心挑战:

  1. 状态机设计需要兼顾协议完整性和时序精确性
  2. 单总线接口的电气特性与FPGA I/O标准需要匹配
  3. 温度数据的校验与处理需要硬件加速

2. DS18B20协议深度解析

2.1 单总线通信机制

DS18B20采用单线制双向通信,这根数据线(DQ)需要外接4.7kΩ上拉电阻。其通信过程分为四个阶段:

  1. 初始化序列:主设备发出480μs以上的低电平复位脉冲,随后释放总线。DS18B20会在15-60μs内拉低总线60-240μs作为应答。

    // 复位脉冲生成示例 always @(posedge clk) begin if (state == RESET_START) dq <= 1'b0; else if (counter >= RESET_DURATION) dq <= 1'b1; end
  2. ROM命令阶段:常用的0xCC(跳过ROM)或0x55(匹配ROM)命令,用于选择目标设备。

  3. 功能命令阶段:关键指令包括:

    • 0x44:启动温度转换(转换时间与分辨率相关)
    • 0xBE:读取暂存器内容
    • 0x4E:写入TH/TL报警阈值
  4. 数据传输:LSB优先的串行传输,每个时隙包含60μs的有效窗口。

2.2 温度数据格式

DS18B20输出的16位温度值中,高5位为符号位(全1表示负温度),低4位为小数部分。标准分辨率下(12位模式),温度值计算公式为:

Temperature = (raw_data >> 4) + (0.0625 * (raw_data & 0xF))

在FPGA中实现时,建议将小数部分单独处理:

signal temp_int : signed(7 downto 0); signal temp_frac : unsigned(3 downto 0); temp_int <= signed(raw_data(11 downto 4)); temp_frac <= unsigned(raw_data(3 downto 0));

3. FPGA驱动架构设计

3.1 整体状态机设计

采用三段式状态机实现协议控制:

  1. 顶层状态机:控制主要流程阶段

    graph TD A[IDLE] -->|启动| B(RESET) B --> C(WAIT_PRESENCE) C --> D(ROM_CMD) D --> E(FUNC_CMD) E --> F(DATA_TRANSFER) F --> G(DONE)
  2. 读写子状态机:处理位级别的时序

    • 写时隙:保持低电平15μs后输出数据位
    • 读时隙:拉低总线后15μs内采样
  3. 时序控制模块:基于系统时钟生成精确时序

    // 50MHz时钟下的时序计数器 parameter WRITE_SLOT = 750; // 15μs always @(posedge clk) begin if (timer_en) timer <= timer + 1; else timer <= 0; end

3.2 关键接口设计

  1. 三态总线控制:

    dq <= 'Z' when (output_en = '0') else '0' when (drive_low = '1') else '1';
  2. CRC校验单元(可选):

    // 查表法CRC8校验 always @(posedge clk) begin if (crc_en) crc <= crc_table[crc ^ data_in]; end

4. Verilog实现详解

4.1 顶层模块定义

module ds18b20_driver ( input wire clk_50m, // 50MHz系统时钟 input wire rst_n, // 低电平复位 inout wire dq, // 单总线接口 output reg [11:0] temp, // 12位温度值 output reg valid // 数据有效标志 ); // 状态编码 localparam [3:0] IDLE = 4'd0, RESET = 4'd1, WAIT_PRES = 4'd2, SKIP_ROM = 4'd3, CONV_T = 4'd4, READ_SCR = 4'd5, READ_BYTE = 4'd6, DONE = 4'd7; reg [3:0] state; reg [15:0] timer; reg [7:0] shift_reg; reg [3:0] bit_cnt;

4.2 核心状态机实现

always @(posedge clk_50m or negedge rst_n) begin if (!rst_n) begin state <= IDLE; temp <= 12'hFFF; valid <= 1'b0; end else begin case (state) IDLE: begin if (start) begin state <= RESET; timer <= 0; end end RESET: begin if (timer == RESET_TIME) state <= WAIT_PRES; end // 其他状态转换... READ_BYTE: begin if (bit_cnt == 8) begin if (byte_cnt == 8) state <= DONE; else state <= READ_SCR; end end DONE: begin valid <= 1'b1; state <= IDLE; end endcase end end

4.3 位读写时序控制

// 写单个比特 task write_bit; input bit data; begin dq_dir <= 1; // 设置为输出 dq_out <= 0; // 启动时隙 #15; // 保持15μs低电平 dq_out <= data; // 输出数据位 #45; // 保持总计60μs dq_dir <= 0; // 释放总线 end endtask // 读单个比特 task read_bit; begin dq_dir <= 1; dq_out <= 0; #2; // 短暂拉低 dq_dir <= 0; // 释放总线 #15; // 等待15μs后采样 bit_value <= dq_in; #45; // 总计60μs时隙 end endtask

5. 实测优化与问题排查

5.1 典型时序问题

  1. 复位无响应

    • 检查上拉电阻值(推荐4.7kΩ±5%)
    • 测量复位脉冲实际宽度(示波器观察)
    • 验证FPGA的I/O电压是否与DS18B20匹配(3.3V或5V)
  2. 数据校验错误

    • 增加CRC校验模块
    • 检查采样点是否在有效窗口中央
    • 适当降低系统时钟频率测试(如从50MHz降到25MHz)

5.2 性能优化技巧

  1. 温度转换并行化:

    // 启动多个传感器同时转换 task start_conversion_all; begin reset_pulse(); write_byte(8'hCC); // 跳过ROM write_byte(8'h44); // 启动转换 release_bus(); end endtask
  2. 动态分辨率调整:

    // 设置分辨率(9-12位) task set_resolution; input [1:0] res; begin write_scratchpad(8'h00, 8'h00, {6'b001111, res}); end endtask
  3. 时序容错处理:

    // 自适应时序调整 if (presence_pulse_width < 60) timing_adjust <= 1'b1;

6. 扩展应用设计

6.1 多传感器网络

通过ROM匹配实现多节点管理:

  1. 枚举总线上的所有传感器ROM码
  2. 建立ROM码查找表
  3. 轮询各节点温度值
type rom_table is array(0 to 7) of std_logic_vector(63 downto 0); signal sensor_roms : rom_table; signal current_sensor : integer range 0 to 7;

6.2 温度报警系统

利用内置TH/TL寄存器实现硬件报警:

// 设置报警阈值 task set_alarm; input [7:0] th, tl; begin write_scratchpad(th, tl, 8'h7F); // 12位分辨率 copy_scratchpad(); // 保存到EEPROM end endtask

6.3 与软核处理器协同

在FPGA内嵌Nios II或MicroBlaze软核时,可通过Avalon或AXI接口暴露驱动控制:

// C语言控制示例 void read_temperature(float *temp) { IOWR(DS18B20_BASE, 0, 1); // 启动转换 while(IORD(DS18B20_BASE, 1)); // 等待完成 *temp = (float)IORD(DS18B20_BASE, 2) * 0.0625; }

7. 实测数据与性能分析

在Xilinx Artix-7 FPGA平台上的实测结果:

指标12位模式9位模式
单次转换时间750ms93.75ms
时序误差±0.5μs±1μs
资源占用(LUT)243198
最大采样频率1.3Hz10.6Hz
温度精度(-10~85℃)±0.5℃±2℃

在环境温度突变时的响应曲线显示,FPGA方案相比典型MCU实现具有更稳定的采样间隔(抖动<1μs),特别适合多传感器同步采集场景。通过流水线设计,可以实现在转换期间进行前次数据的处理,进一步提升系统效率。