• 正文
  • 相关推荐
申请入驻 产业图谱

DS18B20温度采集与数码管显示 Verilog QuartusII

01/19 09:31
182
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

项目信息

名称:DS18B20温度采集与数码管显示 Verilog QuartusII

软件:QuartusII

语言:Verilog

代码功能

该工程实现DS18B20单总线温度采集与数码管显示:驱动模块按照初始化、发送跳过ROM命令、启动温度转换、等待转换完成、读取温度寄存器等步骤与传感器通信,得到原始温度数据并进行符号与数值处理;显示模块把温度数据组织为数码管动态扫描的段码与位选信号,并支持通过拨码开关切换显示内容。

开发板.png

代码实现思路

核心难点是单总线严格的时序。工程通过对系统时钟分频得到1us节拍,并在该节拍下实现微秒计时器,从而精确生成复位脉冲、写时隙与读时隙。状态机按DS18B20的标准流程推进:初始化检测存在脉冲;写入命令字节时逐位控制dq拉低/释放;读取温度时按位采样并拼接成16位原始数据,再进行符号与量化处理输出。顶层把温度值交给数码管扫描模块,最终实现稳定、可观察的温度显示。

代码结构

顶层temp_disp只做模块集成:ds18b20_dri负责传感器通信与温度计算,display负责动态数码管扫描与显示组织。ds18b20_dri内部进一步拆分为:1us时钟与微秒计数;主状态机(初始化/写字节/等待/读字节);以及写位/读位的流程控制计数器。这样把“时序生成”和“流程控制”分开,既便于调试,也方便根据不同主频调整分频参数。

 

1、工程文件

 

2、程序文件

 

 

3、程序编译

 

4、RTL图

管脚分配

 

5、仿真图

整体仿真图

(使用force生成温度)

Testbench

仿真图

DS18B20模块仿真图

Testbench

仿真图

显示模块仿真图

Testbench

仿真图

 

文件/模块一览

temp_disp_bddisplay.v:display

temp_disp_bdtemp_disp_bddisplay.v:display

temp_disp_simdisplay.v:display

部分代码

temp_disp_simds18b20_dri.v

// Descriptions:        DS18B20驱动模块
//****************************************************************************************//

module ds18b20_dri(
//module clock
input              clk        ,         // 时钟信号(50MHz)
input              rst_n      ,         // 复位信号

//user interface
inout              dq         ,         // DS18B20的DQ引脚数据
output reg [19:0]temp_data,         // 转换后得到的温度值
output reg         sign                 // 符号位
);

//parameter define
localparamROM_SKIP_CMD = 8'hcc;           // 跳过 ROM 命令
localparamCONVERT_CMD= 8'h44;           // 温度转换命令
localparamREAD_TEMP    = 8'hbe;           // 读 DS1820 温度暂存器命令
//state define
localparaminit         = 3'd1 ;           // 初始化状态
localparamrom_skip     = 3'd2 ;           // 加载跳过ROM命令
localparamwr_byte      = 3'd3 ;           // 写字节状态
localparamtemp_convert = 3'd4 ;           // 加载温度转换命令
localparamdelay        = 3'd5 ;           // 延时等待温度转换结束
localparamrd_temp      = 3'd6 ;           // 加载读温度命令
localparamrd_byte      = 3'd7 ;           // 读字节状态

//reg define
reg     [ 4:0]         cnt         ;        // 分频计数器
reg                    clk_1us     ;        // 1MHz时钟
reg     [19:0]         cnt_1us     ;        // 微秒计数
reg     [ 2:0]         cur_state   ;        // 当前状态
reg     [ 2:0]         next_state;        // 下一状态
reg     [ 3:0]         flow_cnt    ;        // 流转计数
reg     [ 3:0]         wr_cnt      ;        // 写计数
reg     [ 4:0]         rd_cnt      ;        // 读计数
reg     [ 7:0]         wr_data     ;        // 写入DS18B20的数据
reg     [ 4:0]         bit_width   ;        // 读取的数据的位宽
reg     [15:0]         rd_data     ;        // 采集到的数据
reg     [15:0]         org_data    ;        // 读取到的原始温度数据
reg     [10:0]         data1       ;        // 对原理温度进行符号处理
reg     [ 3:0]         cmd_cnt     ;        // 发送命令计数
reg                    init_done   ;        // 初始化完成信号
reg                    st_done     ;        // 完成信号
reg                    cnt_1us_en;        // 使能计时
reg                    dq_out      ;        // DS18B20的dq输出

//wire define
wire    [19:0]         data2       ;        // 对处理后的进行转换处理

//*****************************************************
//**                    main code
//*****************************************************

assign dq = dq_out;

//分频生成1MHz的时钟信号
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt     <= 5'b0;
clk_1us <= 1'b0;
end
else if(cnt < 5'd24) begin
cnt     <= cnt + 1'b1;
clk_1us <= clk_1us;
end
else begin
cnt     <= 5'b0;
clk_1us <= ~clk_1us;
end
end

//微秒计时
always @ (posedge clk_1us or negedge rst_n) begin
if (!rst_n)
cnt_1us <= 20'b0;
else if (cnt_1us_en)
cnt_1us <= cnt_1us + 1'b1;
else
cnt_1us <= 20'b0;
end

//状态跳转
always @ (posedge clk_1us or negedge rst_n) begin
if(!rst_n)
cur_state <= init;
else
cur_state <= next_state;
end

//组合逻辑状态判断转换条件
always @( * ) begin
case(cur_state)
init: begin                             // 初始化状态
if (init_done)
next_state = rom_skip;
else
next_state = init;
end
rom_skip: begin                         // 加载跳过ROM命令
if(st_done)
next_state = wr_byte;
else
next_state = rom_skip;
end
wr_byte: begin                          // 发送命令
if(st_done)
case(cmd_cnt)                   // 根据命令序号,判断下个状态
4'b1: next_state = temp_convert;
4'd2: next_state = delay;
4'd3: next_state = rd_temp;
4'd4: next_state = rd_byte;
default:
next_state = temp_convert;
endcase
else
next_state = wr_byte;
end
temp_convert: begin                     // 加载温度转换命令
if(st_done)
next_state = wr_byte;
else
next_state = temp_convert;
end
delay: begin                            // 延时等待温度转换结束
if(st_done)
next_state = init;
else
next_state = delay;
end
rd_temp: begin                          // 加载读温度命令
if(st_done)
next_state = wr_byte;
else
next_state = rd_temp;
end
rd_byte: begin                          // 读数据线上的数据
if(st_done)
next_state = init;
else
next_state = rd_byte;
end
default: next_state = init;
endcase
end

//整个操作步骤为初始化、发送跳过ROM操作命令、发送温度转换指令、
//再初始化、再发送跳过ROM操作指令、发送读数据指令。
always @ (posedge clk_1us or negedge rst_n) begin
if(!rst_n) begin
flow_cnt     <=4'b0;
init_done    <=1'b0;
cnt_1us_en   <=1'b1;
dq_out       <=1'bZ;
st_done      <=1'b0;
rd_data      <= 16'b0;
rd_cnt       <=5'd0;
wr_cnt       <=4'd0;
cmd_cnt      <=3'd0;
bit_width <= 5'd16;                                                                      //指定读数据个数
org_data<= 16'd0;
end
else begin
st_done <= 1'b0;
case (next_state)
init:begin                              //初始化
init_done <= 1'b0;
case(flow_cnt)
4'd0:
flow_cnt <= flow_cnt + 1'b1;
4'd1: begin                                                                      //发出500us复位脉冲
cnt_1us_en <= 1'b1;
if(cnt_1us < 20'd500)
dq_out <= 1'b0;
else begin
cnt_1us_en <= 1'b0;
dq_out <= 1'bz;
flow_cnt <= flow_cnt + 1'b1;
end
end
4'd2:begin                                                                                    //释放总线,等待30us
cnt_1us_en <= 1'b1;
if(cnt_1us < 20'd30)
dq_out <= 1'bz;
else
flow_cnt <= flow_cnt + 1'b1;
end
4'd3: begin                                                                                    //检测响应信号
if(!dq)
flow_cnt <= flow_cnt + 1'b1;
else
flow_cnt <= flow_cnt;
end
4'd4: begin                                                                                    //等待初始化结束
if(cnt_1us == 20'd500) begin
cnt_1us_en <= 1'b0;
init_done<= 1'b1;                            //初始化完成
flow_cnt   <= 4'd0;
end

 

【来源:www.hdlcode.com

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录