1. DS18B20驱动开发概述
DS18B20作为单总线数字温度传感器,在嵌入式领域应用广泛。但在FPGA平台上用Verilog实现其驱动,需要精确把控微秒级时序。本文将基于Vivado 2017.4开发环境,详细解析驱动设计中的关键技术要点。
单总线协议的特殊性在于它采用时分复用的方式,在同一条线上实现供电、数据传输和时钟同步。这意味着我们的Verilog代码必须严格遵循DS18B20的时序规范,包括复位脉冲、存在脉冲、读写时隙等关键操作。与单片机通过延时函数控制时序不同,FPGA需要构建精确的时钟计数机制来实现相同功能。
2. 硬件接口设计
2.1 顶层模块定义
驱动模块的端口设计需要特别注意三态总线的处理:
verilog复制module ds18b20_driver (
input clk_1MHz, // 1MHz主时钟(时序基准)
output reg dq_out, // 控制总线输出
input dq_in, // 总线输入监测
output [15:0] temp_data, // 温度值输出
output data_valid // 数据有效标志
);
关键提示:实际部署时必须在顶层例化IOBUF原语,正确处理双向信号。Xilinx器件中可以使用IOBUF原语实现三态控制。
2.2 时钟选择依据
选择1MHz时钟作为基准主要基于以下考量:
- DS18B20的典型操作时序都在微秒级
- 1MHz时钟周期正好1us,方便时序计算
- 在大多数FPGA平台上容易生成(如通过MMCM分频)
例如,复位脉冲需要480us低电平,在1MHz时钟下只需计数到480即可:
verilog复制if(cnt == 480) begin // 480us低电平复位
state <= WAIT_PRESENCE;
cnt <= 0;
end
3. 状态机设计与实现
3.1 状态定义
驱动核心是一个状态机,完整覆盖DS18B20的操作流程:
verilog复制localparam [3:0]
IDLE = 4'd0, // 空闲状态
RESET_PULSE = 4'd1, // 复位脉冲
WAIT_PRESENCE = 4'd2, // 等待存在脉冲
WRITE_SCRATCH = 4'd3, // 写暂存器
CONVERSION = 4'd4, // 温度转换
READ_LOOP = 4'd5; // 读取数据
3.2 状态转换逻辑
每个状态的转换都依赖精确的时钟计数:
verilog复制always @(posedge clk_1MHz) begin
case(state)
RESET_PULSE:
if(cnt == 480) begin
state <= WAIT_PRESENCE;
cnt <= 0;
end else begin
cnt <= cnt + 1;
dq_out <= 1'b0;
end
WAIT_PRESENCE:
if(dq_in == 1'b0) begin
state <= WRITE_SCRATCH;
cnt <= 0;
end
// 其他状态转换...
endcase
end
调试经验:状态机卡死最常见的原因是计数器清零时机不当。建议在每个状态转换点添加明确的清零操作。
4. 关键时序实现细节
4.1 写时隙控制
DS18B20的写操作分为写1和写0两种时隙:
verilog复制// 写0时隙生成
if(write_zero) begin
dq_out <= 1'b0;
if(cnt == 60) begin // 保持60us低电平
dq_out <= 1'b1;
cnt <= 0;
write_done <= 1'b1;
end else begin
cnt <= cnt + 1;
end
end
写1时隙要求主设备在15us内释放总线,整个时隙持续60-120us。实际测试表明,采用60us作为下限兼容性最佳。
4.2 读时隙处理
读取数据时需要特别注意采样时机:
verilog复制// 读取字节处理
always @(posedge bit_done) begin
if(bit_counter <= 7) begin
temp_buffer[bit_counter] <= dq_in_reg;
end
bit_counter <= bit_counter + 1;
end
这里使用bit_done边沿触发而非时钟沿,可以有效避免建立时间问题。DS18B20的数据传输是低位在前,因此bit_counter从0开始累加正好对应数据位的从低到高存储。
5. Vivado工程配置要点
5.1 约束文件设置
单总线引脚必须正确配置上拉电阻:
tcl复制set_property PULLUP true [get_ports dq_io]
set_property IOSTANDARD LVCMOS33 [get_ports dq_io]
5.2 在线调试技巧
使用ILA抓取总线波形时,建议监控以下信号:
- 主时钟clk_1MHz
- 总线信号dq_in/dq_out
- 状态机当前状态
- 关键计数器值
调试时可将ILA触发条件设置为状态转换点,便于观察各阶段的时序关系。
6. 性能优化与实测结果
6.1 温度转换时间
DS18B20的转换时间与分辨率相关:
- 9位分辨率:93.75ms
- 12位分辨率:750ms
驱动中通过状态机等待足够时间确保转换完成:
verilog复制CONVERSION:
if(cnt == 750000) begin // 等待750ms
state <= READ_LOOP;
cnt <= 0;
end else begin
cnt <= cnt + 1;
end
6.2 精度测试
在25°C至30°C范围内进行多点测试,实测误差在±0.5℃以内。为提高精度,可以:
- 采用12位分辨率模式
- 添加软件滤波算法
- 确保电源稳定(寄生供电时特别注意)
7. 常见问题排查
7.1 总线始终为低
可能原因及解决方案:
- 忘记配置上拉电阻 → 添加XDC约束
- 三态控制不当 → 检查IOBUF例化
- 传感器未正确连接 → 检查硬件连接
7.2 读取数据错误
典型排查步骤:
- 确认采样时机是否符合规范
- 检查字节组装顺序(低位在前)
- 验证CRC校验(必要时)
7.3 状态机卡死
调试建议:
- 检查所有状态转换条件
- 确认计数器清零逻辑
- 添加超时保护机制
在实际项目中,我发现在状态机中添加超时跳转可以显著提高鲁棒性。例如,在任何状态停留超过预期时间2倍时自动返回IDLE状态。