扫码加入

  • 方案介绍
  • 附件下载
  • 相关推荐
申请入驻 产业图谱

DS18B20温度采集与数码管显示的设计Verilog代码Quartus开发板

5小时前
112
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

2-2601161G121Z5.docx

共1个文件

名称:DS18B20温度采集与数码管显示的设计Verilog代码Quartus开发板

软件:QuartusII

语言:Verilog

代码功能

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

FPGA代码Verilog/VHDL代码资源下载:www.hdlcode.com

本代码已在开发板验证,开发板如下,其他开发板可以修改管脚适配:

开发板.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

 

 

 

  • 2-2601161G121Z5.docx
    下载

相关推荐