文章目录

  • 一、ds18b20温度传感器
  • 二、看ds18b20手册找关键
    • 1.引脚说明
    • 2.最高位字节和最低位字节数据
    • 3.ds18b20暂存器数据
    • 4.需要的命令
    • 5.主状态机
    • 6.从状态机
    • 7.初始化时序
    • 8.写时隙
    • 9.读时隙
    • 10.关键时间参数
    • 11.低字节先发
  • 三、状态机设计
    • 1.主状态机
      • 1.初始化阶段
      • 2.发送命令阶段
      • 3.读取数据阶段
    • 2.从状态机
    • 3.状态图
  • 四、代码部分
    • 1.==ds18b20_driver.v==
    • 2.==ds18b20_ctrl.v==
    • 3.==top.v==
    • 4.==seg_driver==
  • 五、仿真验证
  • 六、上板验证
  • 七、总结

一、ds18b20温度传感器

DS18B20 单线数字温度传感器,即“一线器件”,其具有独特的优点:

  • 采用单总线的接口方式 与微处理器连接时仅需要一条口线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量。
  • 测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C范围内,精度为 ± 0.5°C 。
  • 在使用中不需要任何外围元件。
  • 持多点组网功能 多个 DS18B20 可以并联在惟一的单线上,实现多点测温。
  • 供电方式灵活 DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
  • 测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。
  • 负压特性电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。
  • 掉电保护功能 DS18B20 内部含有 EEPROM ,在系统掉电以后,它仍可保存分辨率及报警温度的设定值

二、看ds18b20手册找关键

1.引脚说明

只有三个引脚,说明ds18b20是单总线

使用三态门的方式去实现单总线

  • dq_in

  • dq_out

  • dq_out_en

    // 三态门

    assign dq_in = dq;assign dq = dq_out_en?dq_out:1'bz;
    

    dq就是相对于主机来说的

    dq_in 就是ds18b20传感器发来的数据

    dq_out就是主机发给ds18b20的数据

    dq_out_en就是主机发送使能,1能发,0不能发

2.最高位字节和最低位字节数据

数据[10:0]是温度数据

数据[15:11]是温度的正负,1代表负,0代表正

3.ds18b20暂存器数据

DS18B20的每个暂存器都有8bit存储空间,用来存储相应数据,

  • byte0和byte1分别为温度数据的低位和高位,用来储存测量到的温度值,且这两个字节都是只读的;

  • byte2和byte3为TH、TL告警触发值的拷贝,可以在从片内的电可擦可编程只读存储器EEPROM中读出,也可以通过总线控制器发出的[48H]指令将暂存器中TH、TL的值写入到EEPROM,掉电后EEPROM中的数据不会丢失;

  • byte4的配置寄存器用来配置温度转换的精确度(最大为12位精度);

  • byte5、6、7为保留位,禁止写入;

  • byte8亦为只读存储器,用来存储以上8字节的CRC校验码。

4.需要的命令

命令Command 命令数据CMD 说明
SKIP ROM 8’hCC 跳过ROM命令,因为我们只有一个外设,不需要去搜索其他的外设,所以不需要其他的ROM命令
Convert T 8’h44 温度转换命令,将采集到的数据进 行温度转换
READ 8’hBE 温度读取命令,将温度转换后的数据进行读取

5.主状态机

主机的大致流程图

6.从状态机

ds18b20温度传感器外设的大致流程图

发送完第一个温度转换的命令后,需要先回到初始化状态,然后再发送第二个读取温度数据的命令

7.初始化时序

初始化时序图

主机控制总线给从机发送复位脉冲480us,主机释放总线从机等待15-60us,从机控制总线给主机发送存在脉冲60-240us

8.写时隙

写时隙(主机向从机传数据)

无论是写0还是写1,一开始都是主机控制总线拉低总线15us,如果是写0,需要在15us-60us内主机控制总线保持低电平,如果是写1,需要在15us-60us内主机释放总线,上拉电阻将总线拉高,

9.读时隙

读时隙(从机向主机传数据)

无论是读0还是读1,一开始都是主机控制总线拉低>1us,如果是读0,在2us以后,主机释放总线,从机控制总线拉低,而且需要在2us< and <15us内,主机采集数据,如果是读1,

10.关键时间参数

这里有几个时间注意一下

用的是12位精准度,所以温度转换的时间750ms,还有几个时间根据时序图去对照着看

时间名称
Temperature Conversion Time 750ms 温度转换时间
Reset Time Low 480us 主机控制总线发送复位脉冲时间
Presence Detect High 15-60us 主机释放总线
Presence Detect Low 60-240us 从机控制总线方发存在脉冲

11.低字节先发

低字节(LSB FIRST)先发

根据图5,图6,图7,图8和图9的时序写出相应的状态图,可以分为主状态机和从状态机

三、状态机设计

这里可以使用一个状态机就可以实现了,只不过状态转移条件稍微多一点

如果使用主从状态去实现,对读写时隙可以细分,稍微方便一点

1.主状态机

1.初始化阶段

红色是IDLE

黄色是RESET PULSE 主机控制总线发送复位脉冲

绿色是RELEASE 主机释放总线 上拉电阻

蓝色是PRESENCE PULSE 从机控制总线发送存在脉冲

2.发送命令阶段

SKIP ROM COMMAND 主机向从机发送跳过ROM命令

CONVERT TEMPERATURE COMMAND主机向从机发送温度转换命令

WAIT TEMPERATURE COVERT 等待温度转换的时间

READ SCRATCHPAD COMMAND主机向从机发送读取存储器数据命令

3.读取数据阶段

READ TEMPERATURE 主机读从机发来的数据

DONE 主机读取完全部的数据

2.从状态机

从状态机就是细分了读写时隙

我们先找一下读写时隙的相同点,

红色是LOW 主机控制总线拉低

绿色是RELEASE 主机释放总线,上拉电阻拉高

然后是读写时隙的不同点

写时隙

紫色是MASTER WRITE 主机向从机发送1bit的0数据

深绿色也是MASTER WRITE 主机向从机发送1bit的1数据

读时隙

蓝色是MASTER SAMPLE 主机采样从机发送的1bit的0数据

橘色也是MASTER SAMPLE 主机采样从机发送的1bit的1数据

3.状态图

主状态机图

从状态图

完整状态图

四、代码部分

1.ds18b20_driver.v

// ds18b20驱动模块
module ds18b20_driver(input           clk,input           rst_n,// dq单总线input           dq_in,output  reg     dq_out,output  reg     dq_out_en,// 传出的数据output  [23:0]  dout,output          dout_vld
);// 各个状态不同的时间
parameter   TIME_1US   = 50,// 1usRESET_TIME = 480,// 480usM_RELEA_TIME = 20,// 15-60usPRESE_TIME = 200,// 60-240usWAITC_TIME = 750000,// 750msLOW_TIME   = 2,// >1usWRRD_TIME  = 60,//S_RELEA_TIME = 3;// > 1usparameter   SKROM_CMD = 8'hCC,// 跳过ROM命令CONTEM_CMD = 8'h44,// 转换温度命令RDTEM_CMD = 8'hBE;// 读取温度命令// 主状态机
localparam  M_IDLE  = 10'b00000_00001,// 默认状态M_RESET = 10'b00000_00010,// 主机发送复位脉冲M_RELEA = 10'b00000_00100,// 主机释放脉冲M_PRESE = 10'b00000_01000,// 从机发送存在脉冲M_SKROM = 10'b00000_10000,// 主机发送跳过ROM命令M_CTCMD = 10'b00001_00000,// 主机发送温度转换命令M_WAITC = 10'b00010_00000,// 温度转换等待M_RDCMD = 10'b00100_00000,// 主机发送温度读取命令M_RDTEM = 10'b01000_00000,// 主机读取温度数据M_DONE  = 10'b10000_00000;// 从状态机
localparam  S_IDLE  = 6'b000_001,// 默认状态S_LOW   = 6'b000_010,// 无论读写总线拉低S_MASWR = 6'b000_100,// 写时隙发送1bitS_MASRD = 6'b001_000,// 读时隙采样1bitS_RELEA = 6'b010_000,// 无乱读写释放总线S_DONE  = 6'b100_000;// 1bit数据读写完// 主状态机状态
reg     [9:0]       m_state_c;
reg     [9:0]       m_state_n;
// 状态转移条件
wire                m_idle2m_reset ;
wire                m_reset2m_relea;
wire                m_relea2m_prese;
wire                m_prese2m_skrom;
wire                m_skrom2m_ctcmd;
wire                m_skrom2m_rdcmd;
wire                m_ctcmd2m_waitc;
wire                m_waitc2m_reset;
wire                m_rdcmd2m_rdtem;
wire                m_rdtem2m_done ;// 从状态机状态
reg     [5:0]       s_state_c;
reg     [5:0]       s_state_n;
// 状态转移条件
wire                s_idle2s_low   ;
wire                s_low2s_maswr  ;
wire                s_low2s_masrd  ;
wire                s_maswr2s_relea;
wire                s_masrd2s_relea;
wire                s_relea2s_done ;
wire                s_done2s_low   ;
wire                s_done2s_idle  ;// 1us计数器作为时间基准
reg     [5:0]       cnt_1us;
wire                add_cnt_1us;
wire                end_cnt_1us;// 各个状态不同时间
reg     [19:0]      cnt;
wire                add_cnt;
wire                end_cnt;
reg     [19:0]      X;// 字节计数器
reg     [4:0]       cnt_bit;
wire                add_cnt_bit;
wire                end_cnt_bit;// 跳过ROM命令到温度转换命令还是温度读取命令的标志
reg                 flag;
// 从机发送的存在脉冲
reg                 slave_ack;
// 不同状态的command
reg     [7:0]       command;
// 16bit的原始温度数据
reg     [15:0]      origin_data;
// 原始温度数据处理
reg     [10:0]      temper_data;
// 最后接收的温度数据
wire    [23:0]      rx_data;
// 主状态机
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginm_state_c <= M_IDLE; end else begin m_state_c <= m_state_n;end
endalways @(*)begin case (m_state_c)M_IDLE      :begin if(m_idle2m_reset)beginm_state_n = M_RESET;endelse beginm_state_n = m_state_c;end endM_RESET      :begin if(m_reset2m_relea)beginm_state_n = M_RELEA;endelse beginm_state_n = m_state_c;end endM_RELEA      :begin if(m_relea2m_prese)beginm_state_n = M_PRESE;endelse beginm_state_n = m_state_c;end endM_PRESE      :begin if(m_prese2m_skrom)beginm_state_n = M_SKROM;endelse beginm_state_n = m_state_c;end endM_SKROM      :begin if(m_skrom2m_ctcmd)beginm_state_n = M_CTCMD;endelse if(m_skrom2m_rdcmd)beginm_state_n = M_RDCMD;endelse beginm_state_n = m_state_c;end endM_CTCMD      :begin if(m_ctcmd2m_waitc)beginm_state_n = M_WAITC;endelse beginm_state_n = m_state_c;end endM_WAITC      :begin if(m_waitc2m_reset)beginm_state_n = M_RESET;endelse beginm_state_n = m_state_c;end endM_RDCMD      :begin if(m_rdcmd2m_rdtem)beginm_state_n = M_RDTEM;endelse beginm_state_n = m_state_c;end endM_RDTEM      :begin if(m_rdtem2m_done)beginm_state_n = M_IDLE;endelse beginm_state_n = m_state_c;end endM_DONE      : m_state_n = M_IDLE;default: m_state_n = M_IDLE;endcase
endassign m_idle2m_reset  = m_state_c == M_IDLE  && (1'b1);
assign m_reset2m_relea = m_state_c == M_RESET && (end_cnt);// 主机控制总线发送复位脉冲480us
assign m_relea2m_prese = m_state_c == M_RELEA && (end_cnt);// 主机释放总线20us
assign m_prese2m_skrom = m_state_c == M_PRESE && (end_cnt) && (~slave_ack);// 从机控制总线发送存在脉冲200us并且接收到低电平的存在脉冲
assign m_skrom2m_ctcmd = m_state_c == M_SKROM && (end_cnt_bit) && (flag == 0);// 8bit跳过ROM命令发送完,并且温度转换
assign m_skrom2m_rdcmd = m_state_c == M_SKROM && (end_cnt_bit) && (flag == 1);// 8bit跳过ROM命令发送完,并且温度读取
assign m_ctcmd2m_waitc = m_state_c == M_CTCMD && (end_cnt_bit);// 8bit温度转换命令发送完
assign m_waitc2m_reset = m_state_c == M_WAITC && (end_cnt);// 等待温度转换400us
assign m_rdcmd2m_rdtem = m_state_c == M_RDCMD && (end_cnt_bit);// 8bit温度读取命令发送完
assign m_rdtem2m_done  = m_state_c == M_RDTEM && (end_cnt_bit);// 16bit温度数据读取完// 从状态机
always @(posedge clk or negedge rst_n)begin if(!rst_n)begins_state_c <= S_IDLE; end else begin s_state_c <= s_state_n;end
endalways @(*)begin case (s_state_c)S_IDLE      :begin if(s_idle2s_low)begins_state_n = S_LOW;endelse begins_state_n = s_state_c;end endS_LOW      :begin if(s_low2s_maswr)begins_state_n = S_MASWR;endelse if(s_low2s_masrd)begins_state_n = S_MASRD;endelse begins_state_n = s_state_c;end endS_MASWR      :begin if(s_maswr2s_relea)begins_state_n = S_RELEA;endelse begins_state_n = s_state_c;end endS_MASRD      :begin if(s_masrd2s_relea)begins_state_n = S_RELEA;endelse begins_state_n = s_state_c;end endS_RELEA      :begin if(s_relea2s_done)begins_state_n = S_DONE;endelse begins_state_n = s_state_c;end endS_DONE      :begin if(s_done2s_low)begins_state_n = S_LOW;endelse if(s_done2s_idle)begins_state_n = S_IDLE;endelse begins_state_n = s_state_c;end enddefault: s_state_n = S_IDLE;endcase
endassign s_idle2s_low     = s_state_c == S_IDLE  && (((m_state_c == M_SKROM) || (m_state_c == M_CTCMD) || (m_state_c == M_RDCMD) || (m_state_c == M_RDTEM)));// 到读写时候
assign s_low2s_maswr    = s_state_c == S_LOW   && (((m_state_c == M_SKROM) || (m_state_c == M_CTCMD) || (m_state_c == M_RDCMD)) && (end_cnt));// 发送命令先拉低总线2us
assign s_low2s_masrd    = s_state_c == S_LOW   && ((m_state_c == M_RDTEM) && (end_cnt));// 读取数据先拉低总线2us
assign s_maswr2s_relea  = s_state_c == S_MASWR && (end_cnt);// 写1bit数据60us
assign s_masrd2s_relea  = s_state_c == S_MASRD && (end_cnt);// 读1bit数据60us
assign s_relea2s_done   = s_state_c == S_RELEA && (end_cnt);// 1bit数据读写完释放总线2us
assign s_done2s_low     = s_state_c == S_DONE  && (~end_cnt_bit);// 8bit或者16bite没有全部读写完
assign s_done2s_idle    = s_state_c == S_DONE  && (end_cnt_bit);// 8bit或者16bit全部读写完
// 1us计数器
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_1us <= 0;end else if(add_cnt_1us)begin if(end_cnt_1us)begin cnt_1us <= 0;endelse begin cnt_1us <= cnt_1us + 1;end endelse  begincnt_1us <= cnt_1us;end
end assign add_cnt_1us = 1'b1;
assign end_cnt_1us = add_cnt_1us && cnt_1us == TIME_1US - 1;// 各个状态不同时间计数器
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt <= 0;end else if(add_cnt)begin if(end_cnt)begin cnt <= 0;endelse begin cnt <= cnt + 1;end endelse  begincnt <= cnt;end
end assign add_cnt = end_cnt_1us;
assign end_cnt = add_cnt && cnt == X - 1;// 各个状态不同时间
always @(*)begin if(m_state_c == M_RESET)beginX = RESET_TIME;endelse if(m_state_c == M_RELEA)beginX = M_RELEA_TIME;endelse if(m_state_c == M_PRESE)beginX = PRESE_TIME;endelse if(m_state_c == M_WAITC)beginX = WAITC_TIME;endelse if(s_state_c == S_LOW)beginX = LOW_TIME;endelse if((s_state_c == S_MASWR) || (s_state_c == S_MASRD))beginX = WRRD_TIME;endelse if(s_state_c == S_RELEA)beginX = S_RELEA_TIME;end
end// 字节计数器
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 0;end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 0;endelse begin cnt_bit <= cnt_bit + 1;end endelse  begincnt_bit <= cnt_bit;end
end assign add_cnt_bit = s_relea2s_done;// 1bit数据度写完,并且释放总线时间结束
assign end_cnt_bit = add_cnt_bit && cnt_bit == ((m_state_c == M_RDTEM)?(16 - 1):(8 - 1));// 跳过ROM命令到温度转换命令还是温度读取命令的标志
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag <= 0;end else if(m_waitc2m_reset)begin flag <= 1'b1;end else if(m_rdtem2m_done)begin flag <= 1'b0;end
end// 单总线dq
// dq_in从机向主机发送存在脉冲
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginslave_ack <= 1'b1;end else if(m_state_c == M_PRESE && cnt == 60 && end_cnt_1us)begin slave_ack <= dq_in;end else if(m_prese2m_skrom)beginslave_ack <= 1'b1;end
end// dq_out_en主机向从机发送使能
always @(posedge clk or negedge rst_n)begin if(!rst_n)begindq_out_en <= 0;end else if(m_idle2m_reset || m_waitc2m_reset || s_idle2s_low || s_done2s_low || m_prese2m_skrom || m_skrom2m_ctcmd || m_skrom2m_rdcmd || s_low2s_maswr)begin dq_out_en <= 1'b1; end else if(m_reset2m_relea || s_maswr2s_relea || s_low2s_masrd || m_rdcmd2m_rdtem || s_low2s_masrd)begin dq_out_en <= 1'b0;end
end// dq_out主机向从机发送的数据
always @(posedge clk or negedge rst_n)begin if(!rst_n)begindq_out <= 0;end else if(m_idle2m_reset || m_waitc2m_reset || s_idle2s_low || s_done2s_low)begin dq_out <= 0;end else if(s_low2s_maswr)begin dq_out <= command[cnt_bit];end
end// 不同状态的command
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincommand <= 0;end else if(m_prese2m_skrom)begin command <= SKROM_CMD;end else if(m_skrom2m_ctcmd)begin command <= CONTEM_CMD;end else if(m_skrom2m_rdcmd)begincommand <= RDTEM_CMD;end
end// dq_in从机向主机发送16bit的温度数据
// 1bit数据在2-15us以内采集
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginorigin_data <= 0;end else if(s_state_c == S_MASRD && cnt == 13 && end_cnt_1us)begin origin_data[cnt_bit] <= dq_in;end
end// 接收到的数据进行处理
// 是一个10进制的数据
always @(posedge clk or negedge rst_n)begin if(!rst_n)begintemper_data <= 0;end else if(m_rdtem2m_done)beginif(origin_data[15])begin temper_data <= ~origin_data[10:0] + 1'b1;end else begin temper_data <= origin_data[10:0];end end
end// 得到的数据带有3位小数
assign rx_data = temper_data * 625;assign dout = rx_data;
assign dout_vld = m_rdtem2m_done;endmodule

2.ds18b20_ctrl.v

module ds18b20_ctrl(input           clk,input           rst_n,input   [23:0]  din,input           din_vld,output  [23:0]  dout
);reg     [23:0]      rx_data;
wire    [3:0]       rx_data_r0;
wire    [3:0]       rx_data_r1;
wire    [3:0]       rx_data_r2;
wire    [3:0]       rx_data_r3;
wire    [3:0]       rx_data_r4;
wire    [3:0]       rx_data_r5;always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrx_data <= 0;end else if(din_vld)begin rx_data <= din;end
endassign rx_data_r0 = rx_data%10;
assign rx_data_r1 = (rx_data/10)%10;
assign rx_data_r2 = (rx_data/100)%10;
assign rx_data_r3 = (rx_data/1000)%10;
assign rx_data_r4 = (rx_data/10000)%10;
assign rx_data_r5 = (rx_data/100000)%10;assign dout ={rx_data_r5,rx_data_r4,rx_data_r3,rx_data_r2,rx_data_r1,rx_data_r0};endmodule

3.top.v

module top(input           clk,input           rst_n,inout           dq,output  [7:0]   seg_dig,output  [5:0]   seg_sel,output          uart_tx
);
wire            dq_in;
wire            dq_out;
wire            dq_out_en;
wire    [23:0]  tem_data;
wire            tem_data_vld;
wire    [23:0]  seg_data;
wire    [7:0]   uart_tx_data;// 三态门
assign dq_in = dq;
assign dq = dq_out_en?dq_out:1'bz;assign uart_tx_data = seg_data[23:16];// ds18b20驱动模块
ds18b20_driver u_ds18b20_driver(/* input            */.clk          (clk      ),/* input            */.rst_n        (rst_n    ),/* input            */.dq_in        (dq_in    ),/* output           */.dq_out       (dq_out   ),/* output           */.dq_out_en    (dq_out_en),/* output  [23:0]   */.dout         (tem_data ),/* output           */.dout_vld     (tem_data_vld )
);// 串口发送模块
uart_tx u_uart_tx(/* input            */.clk          (clk     ),/* input            */.rst_n        (rst_n   ),/* input            */.baud_sel     (0),// 波特率的选择/* input   [7:0]    */.din          (uart_tx_data),// 串并转换的数据/* input            */.din_vld      (tem_data_vld ),// 串并转换的数据有效/* output           */.dout         (uart_tx   ),// 发送模块发送的1bit数据/* output           */.busy         (busy    ) // 发送模块忙标志
);
// ds18b20控制模块
ds18b20_ctrl u_ds18b20_ctrl(/* input            */.clk          (clk     ),/* input            */.rst_n        (rst_n   ),/* input   [23:0]   */.din          (tem_data),/* input            */.din_vld      (tem_data_vld ),/* output  [23:0]   */.dout         (seg_data )
);seg_driver u_seg_driver(/* input                        */.clk          (clk    ),/* input                        */.rst_n        (rst_n  ),/* input           [23:0]       */.data         (seg_data),/* output   reg    [7:0]        */.seg_dig      (seg_dig),/* output   reg    [5:0]        */.seg_sel      (seg_sel)
);endmodule

4.seg_driver

// 数码管驱动
module seg_driver(input                       clk,input                       rst_n,input           [23:0]      data,output   reg    [7:0]       seg_dig,output   reg    [5:0]       seg_sel
);localparam  ZERO  = 7'b100_0000,ONE   = 7'b111_1001,TWO   = 7'b010_0100,THREE = 7'b011_0000,FOUR  = 7'b001_1001,FIVE  = 7'b001_0010,SIX   = 7'b000_0010,SEVEN = 7'b111_1000,EIGHT = 7'b000_0000,NINE  = 7'b001_0000;parameter SCAN_TIME = 50_000;// 扫描计数器1ms
reg     [17:0]      scan_cnt;
wire                add_scan_cnt;
wire                end_scan_cnt;reg     [3:0]       num;// 小数点
reg                 point;// 扫描计数器1ms
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginscan_cnt <= 0;end else if(add_scan_cnt)begin if(end_scan_cnt)begin scan_cnt <= 0;endelse begin scan_cnt <= scan_cnt + 1;end endelse  beginscan_cnt <= scan_cnt;end
end assign add_scan_cnt = 1'b1;
assign end_scan_cnt = add_scan_cnt && scan_cnt == SCAN_TIME - 1;// 计数器扫描位选
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginseg_sel <= 6'b111110;end else if(end_scan_cnt)begin seg_sel <= {seg_sel[4:0],seg_sel[5]};end else begin seg_sel <= seg_sel;end
end// 根据位选来给数据
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginnum <= 4'b0;point <= 1'b0;end else begin case (seg_sel)6'b111110   :   begin num <= data[3:0];point <= 1'b1;end6'b111101   :   begin num <= data[7:4];point <= 1'b1;end6'b111011   :   begin num <= data[11:8];point <= 1'b1;end6'b110111   :   begin num <= data[15:12];point <= 1'b1;end6'b101111   :   begin num <= data[19:16];point <= 1'b0;end6'b011111   :   begin num <= data[23:20];point <= 1'b1;end                                                 default: ;endcaseend
end// 根据num来对段选赋值
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginseg_dig <= 8'hff;end else begin case (num)0   :   seg_dig <={point,ZERO};1   :   seg_dig <={point,ONE};2   :   seg_dig <={point,TWO};3   :   seg_dig <={point,THREE};4   :   seg_dig <={point,FOUR};5   :   seg_dig <={point,FIVE};6   :   seg_dig <={point,SIX};7   :   seg_dig <={point,SEVEN};8   :   seg_dig <={point,EIGHT};9   :   seg_dig <={point,NINE};default: ;endcaseend
end
endmodule

五、仿真验证

仿真验证只是看看ds18b20的驱动的状态转移是否正确

`timescale 1ns/1nsmodule ds18b20_driver_tb();
//激励信号定义
reg             tb_clk      ;
reg             tb_rst_n    ;
reg             tb_dq_in    ;//输出信号定义
wire            tb_dq_out   ;
wire            tb_dq_out_en;
wire    [7:0]   tb_dout     ;
wire            tb_dout_vld ;//时钟周期参数定义                         parameter       CLOCK_CYCLE = 20;    ds18b20_driver u_ds18b20_driver(/* input            */.clk          (tb_clk      ),/* input            */.rst_n        (tb_rst_n    ),/* input            */.dq_in        (tb_dq_in    ),/* output  reg      */.dq_out       (tb_dq_out   ),/* output  reg      */.dq_out_en    (tb_dq_out_en),   /* output  [7:0]    */.dout         (tb_dout     ),/* output           */.dout_vld     (tb_dout_vld )
);
//产生时钟
initial         tb_clk = 1'b0;
always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;          integer i;
//产生激励
initial  begin                                  tb_rst_n = 1'b1;                              tb_dq_in = 0;                              #(CLOCK_CYCLE*2);                           tb_rst_n = 1'b0;                          #(CLOCK_CYCLE*20);                          tb_rst_n = 1'b1;  // #(CLOCK_CYCLE*1000);repeat(5)beginfor(i=0;i<10000;i=i+1)begintb_dq_in = {$random};#(CLOCK_CYCLE*10);end#(CLOCK_CYCLE*10);end#(CLOCK_CYCLE*500);                   $stop;                      end
endmodule       


我这里750ms改成了75ns

六、上板验证

七、总结

这个ds18b20不需要什么协议,算是第二个做出来的成就,这个ds18b20让我学会了如何看手册,一步步的去找关键点。
注意一下符号的优先级,我就死在&& 和 || 上 调试了半天。

【FPGA】ds18b20温度传感器相关推荐

  1. FPGA DS18B20温度传感器的开发

    verilog代码: module DS18B20(Clk,nRst,En,Data,DQ);input Clk; //输入时钟50MHzinput nRst; //输入复位input En; // ...

  2. DS18B20温度传感器FPGA实现

    一. 简介 通过原理图可以看出,DS18B20温度传感器只有一条总线,可想而知,其结构的简单化,导致了其操作的复杂化. 更多关于该传感器的一些特性参数,以及性能指标,可以详细阅读官网提供的数据手册. ...

  3. 嵌入式设计与开发项目-DS18B20温度传感器程序设计

    嵌入式设计与开发项目-DS18B20温度传感器程序设计 一.实现的功能 二.根据功能实现代码 1.主文件main.c 2.DS18B20的头文件"ds18b20.h" 3.DS18 ...

  4. AutoLeaders控制组——51单片机学习笔记(DS18B20温度传感器、LCD1602、直流电机+PWM)

    本篇内容是观看B站江科大自化协UP主的教学视频所做的笔记,对其中内容有所引用,并结合自己的单片机板块进行了更改调整. 以下笔记内容以一个视频为一个片段(内容较多,可能不适合速食,望见谅) 一些内容涉及 ...

  5. 【51单片机】AT24C02存储器(I²C总线)/DS18B20温度传感器(单总线)

    目录 一.AT24C02存储器 1.AT24C02存储器介绍 2.存储器简化模型 3.AT24C02存储器原理图 二.I²C总线 1.I²C总线的介绍 2.I²C电路 3.I²C时序图 3.1I²C开 ...

  6. 基于汇编语言的DS18B20温度传感器设计

    1 概述 1.1 课题内容 利用温度传感器DS18B20与MCS-51单片机结合来测量温度,通过一根单总线连接,即可直接读出被测温度,读出或写入信息只需要一根数据线.读出的数据用LED数码管显示,显示 ...

  7. 51单片机使用LCD1602显示DS18B20温度传感器温度

      使用LCD1602显示DS18B20温度传感器温度.关于DS18B20和LCD的原理,我就不再叙述了,大家自行查找,网上可以找到好多.   使用Proteus仿真.(需要仿真和Keil工程文件的可 ...

  8. C51---13 DS18B20温度传感器

    C51---13 DS18B20温度传感器 DS18B20介绍 引脚及电路 内部结构图 存储器的结构 单总线介绍 单总线电路规范 单总线时序结构❗ DS18B20操作流程 DS18B20数据帧 温度存 ...

  9. DS18B20温度传感器 ------ 自学笔记

    目录 一.简介 二.DS18B20的特点 三.DS18B20实物图 四.DS18B20的内部结构 4.1.64位(激)光刻只读存储器 4.2.DS18B20温度转换规则 4.3.DS18B20温度传感 ...

  10. 智能温度系统(C51+DS18B20温度传感器+LM016L显示屏)

    单片机课程设计,C51+DS18B20温度传感器+LM016L显示屏 重点在于两个外设的时序控制 模块化的设计结构清晰明了 一.题目 温度测量系统的设计 二.要求 1.温度测量范围:-55℃ ~ 12 ...

最新文章

  1. 信而泰推出100G多速率测试模块:填补中国通信产业链短板
  2. VC++学习(17):进程间通信
  3. stackover flow载入巨慢
  4. ACK容器服务发布virtual node addon,快速部署虚拟节点提升集群弹性能力
  5. 【解题报告】Leecode 559. N 叉树的最大深度——Leecode每日一题
  6. kafka 不同分区文件存储_大白话 + 13 张图解 Kafka
  7. 基于Spring MVC的ECharts动态数据实时展示
  8. LintCode 69---二叉树的层次遍历
  9. 半透明渲染新技术摘录
  10. 推荐算法在招聘商业化场景中的应用实践
  11. 团队-团队编程项目作业-开发环境搭建过程
  12. ios人脸照片_iOS10照片人脸识别功能是什么?iOS10照片人脸识别功能使用教程
  13. Amos实操教程 | 中介效应检验
  14. ACCESS实例1——简易文档管理器
  15. bootdo项目war包部署流程
  16. Dzz任务板初版完成笔记-仿trello可私有部署的一款轻量团队任务协作工具。
  17. 巧用千寻位置GNSS软件| 点放样操作指南
  18. HDU 4416 (后缀自动机)
  19. CleanMyMac X4.10.6mac上非常强大的系统清理工具
  20. 前端-超链接,相对路径

热门文章

  1. Android 自定义 省份、车牌号键盘。
  2. python 无头浏览器_python3使用无头浏览器
  3. python如何安装numpy模块?
  4. UiPath Excel 向下填充
  5. Android实现断点下载功能
  6. java推荐算法_Java编程实现基于用户的协同过滤推荐算法代码示例
  7. 玩转5G之--网络布线2 详细解说
  8. sliksvn下载与安装
  9. 数字图像处理第五章——图像复原与重建
  10. n元均匀直线matlab,均匀直线阵天线的分析