资讯详情

【FPGA】DS18B20数字温度传感器实验

目录

  • 前言
  • 一丶看懂DS18B20数据手册
    • 1.DS18B20内部结构
    • 2.DS18B20的命令
      • ①ROM功能命令
      • ②RAM功能命令
    • 3.命令用法
    • 4.初始化
    • 5.读写时隙
      • ①写时隙
      • ②读时隙
  • 二、分析实验任务
    • 1.状态机
    • 2.温度解码
    • 3.模块原理图
  • 三、代码设计
    • 1.顶层模块
    • 2.DS18B20驱动
    • 3.温度转换模块
    • 4.数字管驱动
  • 四丶仿真
    • 1.Testbench
    • 2.仿真分析
  • 五、上板验证
  • 六丶源码

前言

提供数字温度传感器9-Bit到12-Bit用户可编程的摄氏温度测量精度和非易失性,具有温和低温触发报警功能。 DS18B20采用的(单总线)1通信只使用数据线(和地)与微控制器通信。 该传感器的为-55℃至 125℃,温度范围超过-10℃至85℃还有±0.5℃精度。DS18B20不需要外部电源就可以直接由数据线供电。

每片DS18B20都有一个,所以一个1-Wire多个可以在总线上连接DS18B20设备。因此,在分布式环境中使用微控制器控制多个设备DS18B20很简单。这些特征使它们在HVAC环境控制在建筑、设备和机械的温度监测系统以及温度过程控制系统中具有很大的优势。

一丶看懂DS18B20数据手册

我们将对照原味的“ 英文手册 ”来分析

实在看不懂还可以戳这里中文手册传送门!!!

1.DS18B20内部结构

在这里插入图片描述 全英语,算了吧。 别急,给出中文版的结构图,一目了然 DS18B20的内部结构主要由8部分组成:

那么,FPGA需要怎样控制才能让DS18B20并读取温度数据?

2.DS18B20的命令

温馨提示:命令解释有点麻烦。我们可以把这部分作为数据来查看。现在我们也可以直接去看命令用法

①ROM功能命令

ROM功能命令是 64位ROM具体内容如下图所示:

64位ROM中间的序列号在出厂前被光刻可视为DS18B20地址序列码。 每个人的排列顺序是:产品类型标号开始8位,,最后8位是前56位CRC循环冗余校准码(CRC=X8 X5 X4 1) 光刻ROM它的作用是让每一个DS18B20都不一样,这样一条总线就可以挂多个DS18B20目的。相应的命令如下五条:

  • 33H 该命令允许总线控制器(FPGA)读取DS18B8位系列编码,唯一的序列号和8位CRC码。 只有在总线上才存在DS18B该命令只能在20点使用。

  • 55H 发出这个命令后,然后发出64人ROM编码,让总线控制器(FPGA)在多点总线上定位一个特定的DS18B20。只有和64位ROM完全匹配序列DS18B20会做出反应。所有64位ROM序列不匹配DS18B20将等待复位脉冲。当总线上有单个或多个设备时,可以使用此命令。

  • CCH 该命令允许总线控制器(FPGA)不用提供64位ROM编码在单点总线(一个DS18B20)可以节省时间。如果总线上有不止一个从机,跳过ROM命令结束后,发送阅读命令。由于多个从机器同时发送信号,数据冲突发生在总线上(漏极开路上拉效果相当好 于相与)。

  • F0H 当系统首次启动时,总线控制器可能不知道总线上有多少器件或64位ROM编码。搜索ROM命令允许总线控制器用排除法识别总线上的所有DS18B20的64位编码。

  • ECH 发出此命令后,只有温度超过设定值的上限或下限DS18B20做出反应。只要需要注意, DS18B20不断电,报警状态将保持,直到再次测量的温度值达不到报警条件。

②RAM功能命令

RAM功能命令是操作,我们这里的RAM主要指,让我们来看看它的数据结构

由上图可知DS18B20的高速缓存器共有,其中)对应字节地址0,)对应字节地址1,以此类推,字节地址为4。温度数据存储格式如下图所示:

DS18B20出厂时默认配置温度数据,其中,即,最低四位为

②FPGA读取温度数据时,一次读2字节共16位,读完后将低11位的二进制数转化为十进制数,再乘以0.实际温度值为0625。

③此外,还需要判断温度,这五位同时改变,。当前5位为1时,读取温度为负值时,需要取反加1,乘以0.只有0625才能获得实际温度值。当前五名为0时,读取的温度为正值,只要测量值乘以0.0625可获得实际温度值。

  • 44H 该命令启动温度转换。然后执行温度转换命令DS18B保持等待状态。如果总线控制器遵循此命令后的读取间隙DS18B如果20忙于时间转换,DS18B20将在总线上输出0,如果温度转换完成,则输出1。如果使用寄生电源,总线控制器必须在发出此命令后立即启动强拉,并保持500ms。低存入转换结果BYTE0、高位存BYTE1。

  • BEH 此命令读取临存器的内容。读取将从BYTE从0开始,一直持续到9字节(BYTE8,CRC)读完。如果不想读完所有字节,控制器可以在任何时间发出复位命令来终止读取。另外需要注意的是,字节内容都是最低位先传送。

  • 4EH 这个命令向DS18B20的高速缓存器中写入数据,开始位置在地址2。接下来写入的两个字节将被存到高速缓存器的字节地址位2和3的高、低温触发器。可以在任何时刻发出复位命令来终止写入。

  • 48H 这条命令把高速缓存器的内容拷贝到DS18B20的E2PROM存储器中,即把温度报警触发字节存入非易失性存储器里。如果总线控制器在这条命令之后跟着发出读时间隙,而DS18B20又正在忙于把暂存器拷贝到E2PROM存储器,DS18B20就会输出一个“0”,如果拷贝结束的话,DS18B20则输出“1”。如果使用寄生电源,总线控制器必须在这条命令发出后立即起动强上拉并最少保持10ms。

  • B8H 这条命令把E2PROM里的值拷回高速缓存器。这种拷回操作在DS18B20上电时自动执行,这样器件一上电高速缓存器里马上就存在有效的数据了。若在这条命令发出之后发出读时间隙,器件会输出温度转换忙的标识:“0”=忙,“1”=完成。

  • B4H 读DS18B20的供电方式。若把这条命令发给DS18B20后发出读时间隙,器件会返回它的电源模式:“0”=寄生电源,“1”=外部电源。

3.命令用法

阅读数据手册:

大致意思就是访问这个温度传感器有三个步骤:

1.初始化时序 2.使用ROM命令匹配总线上相应的传感器 3.使用RAM命令读取温度,最后回到初始化时序

下面介绍以上几条指令的用法。当进行操作时:

首先应将主机逐个与DS18B20挂接,;然后再将所有的DS18B20挂接到总线上,主机发出(55H)之后,主机紧接着提供的64位ROM编码(包括该DS18B20的48位序列号) 之后的操作就是针对该DS18B20的RAM命令。

如果主机只对一个DS18B20进行操作,就不需要读取ROM编码以及匹配ROM编码,(CCH命令),就可进行下一步对高速缓存器的操作。 主机发出对ROM的操作命令之后,就进一步发出对RAM的命令。这里的RAM主要是指高速缓存器

初始化➔发跳过ROM命令(CCH)➔发开始转换命令(44H)➔延时➔初始化➔发送跳过ROM命令(CCH)➔发读存储器命令(BEH)➔连续读出两个字节数据(即温度)➔结束或开始下一循环。

4.初始化

: 主机(FPGA)发送复位脉冲→主机释放总线→DS18B20发出存在脉冲(FPGA接收存在脉冲) 初始化序列见下图。:

一个复位脉冲跟着一个存在脉冲表明DS18B20已经准备好(适当的ROM命令和RAM操作命令)。主机平,保持低电平时间,以产生复位脉冲。接着主机,4.7K的,延时15~60us,此时DS18B2060~240us,以产生低电平存在脉冲以应答主机。

5.读写时隙

初始化完成之后,主机就可以向从机读写数据。

读写数据涉及到读写时隙的概念。在单总线通信协议中,读写时隙的概念十分重要,,每一个时隙总线。 无论是在读时隙还是写时隙,它们都,数据线的下降沿使从设备触发其内部的延时电路,使之与主机同步。在写时隙内,该延迟电路决定从设备采样数据线的时间延迟。

①写时隙

单总线通信协议中写时隙有两种:写1和写0。 主机采用写1时隙向从机写入1,而采用写0时隙向从机写入0。所有写时隙,且在两次独立的写时隙之间至少需要

两种写时隙均起始于主机拉低数据总线。

:在主机拉低数据线后,只需要在整个时隙间保持低电平即可(至少60us)。 :主机拉低总线后,接着必须在15us之内释放总线,由上拉电阻将总线拉至高电平;在写时隙开始后15us~60us期间,单总线器件采样总电平状态。如果在此期间采样值为高电平,则逻辑1写入器件;如果为0,写入逻辑0,时隙图如下图所示:

②读时隙

对于读时隙,单总线器件仅在主机,才向主机传输数据。 主机发出读数据命令后,必须马上产生读时隙,以便从机能够传输数据。所有读时隙,且在两次独立的读时隙之间

每个读时隙都,至少拉低总线1us。

在主机发出读时隙之后,单总线器件才开始在总线上发送0或1。

若从机发送1,则保持总线为高电平;

若发出0,则拉低总线。 当发送0时,从机在,由上拉电阻将总线拉回至空闲高电平状态。 从机发出的数据在起始时隙之后,,因此,并且在时隙起始后的15us之内采样总线状态,时隙图如下图所示:

二丶分析实验任务

1.使用状态机编写温度传感器驱动 2.在数码管上实时显示温度

1.状态机

首先我们分析温度传感器驱动需要哪些状态

我们访问此传感器并获取温度 首先需要进行①,而初始化又包括 然后②,发送此命令之后就能访RAM问高速缓存器了,而温度值就存储在里面 之后③,手册中说明了默认配置温度数据为12位,查表可知,转换12位的温度数据需要最多750ms,所以我们在发送了温度转换命令之后需要延时750ms

,也就是读高速缓存器命令,从低位开始读 ⑤,温度数据存储在 ,所以我们只需要读取这两个字节的数据即可

注意:发送指令以及读取温度数据存在 读写数据操作,这就需要用到读写时隙,所以上面列出的步骤中省略的 产生读写时隙可以作为” 从状态机” ,而总的步骤作为“ 主状态机 ”

  • M_IDLE:空闲状态,等待开始通信;
  • M_RST:发送复位脉冲;
  • M_REL:释放总线;
  • M_RACK:接收存在脉冲;
  • M_RSKP:发送跳过 ROM 指令;
  • M_SCON:发送温度转换命令;
  • M_WAIT:等待 750ms;
  • M_SRTM:发送温度读取指令;
  • M_RTMP:读取温度值;

  • S_IDLE:空闲状态,等待传输请求;
  • S_LOW:发数据前先拉低 1us;
  • S_SEND:发送 1bit 数据;
  • S_SAMP:接收 1bit 数据;
  • S_RELE:释放总线;
  • S_DONE:发送/接收一次数据完成;

我们这里将从状态机分为两类,即写时隙和读时隙

:写数据时主机向从机发数据

  • 首先进入S_LOW状态,拉低总线,保持(>=1us)
  • 然后进入S_SEND状态,由主机发送数据,单总线器件采样总电平状态(15us~60us)
  • 最后,进入S_RELE状态,主机释放总线(>=1us)
  • 释放完成,进入S_DONE状态

:读数据时从机向主机发送数据

  • 首先进入S_LOW状态,拉低总线,保持(>=1us)
  • 然后进入S_SAMP状态,由从机发送数据(主机接收数据),主机采样数据(<=15us)
  • 最后,进入S_RELE状态,主机释放总线(>=1us)
  • 释放完成,进入S_DONE状态

如下图所示我们综合出来的从状态机转移图

2.温度解码

DS18B20在出厂时,其中,即温度值共11位,最低四位为小数位。 FPGA在读取温度数据时,一次会读2字节共16位,读完后将低11位的二进制数转化为十进制数后再乘以0.0625得到所测的实际温度值。 另外还需要,前5个数字为符号位,这5位同时变化,我们只需要判断其中任何一位就可以了。 前5位为1时,读取的温度为负值,则测到的数值需要才可得到实际温度值。前5位为0时,读取的温度为正值,只要将测得的数值乘以0.0625即可得到实际温度值。

3.模块原理图

三丶代码设计

1.顶层模块

注意:因为我们使用单总线通信,这里dq端口既是输入又是输出

处理方式:使用三态门

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

  • dq:单总线
  • en:主机发送使能
  • dq_out:在en使能的时候,将dq_out的数据通过dq总线发送到从机
  • dq_in:在en使能关闭的时候,将从机通过dq总线发送的数据输入到主机
module temp_detect (
    input                    clk     ,
    input                    rst_n   ,

    inout                    dq      ,   //传感器总线---单总线

    output       [5:0]       sel     ,   //数码管位选
    output       [7:0]       seg         //数码管段选
);

    wire                     dq_out       ; 
    wire                     dq_in        ;
    wire                     dq_out_en    ;
    wire                     temp_sign    ;  //温度正负
    wire         [23:0]      temp_out     ;  //温度值
    wire                     temp_out_vld ;  //温度值有效
    wire         [23:0]      dout         ;
    wire                     dout_vld     ;


    assign dq = dq_out_en ? dq_out : 1'bz;  //如果输出使能,则将dq_out的值赋给dq输出,反之则为高阻态输出
    assign dq_in=dq;    //接收dq输入信号

    //例化模块

    ds18b20_driver  u_ds18b20_driver(
        .clk                (clk         ),
        .rst_n              (rst_n       ),
        .dq_in              (dq_in       ),
        .dq_out             (dq_out      ),
        .dq_out_en          (dq_out_en   ),
        .temp_out           (temp_out    ),
        .temp_sign          (temp_sign   ),
        .temp_out_vld       (temp_out_vld)
    );


    control u_control(
        .clk                (clk         ),
        .rst_n              (rst_n       ),
        .temp_out           (temp_out    ),
        .temp_sign          (temp_sign   ),
        .temp_out_vld       (temp_out_vld),
        .dout               (dout        ),
        .dout_vld           (dout_vld    )
    );


    seg_driver  u_seg_driver(
        .clk                (clk         ),
        .rst_n              (rst_n       ),
        .temp_sign          (temp_sign   ),
        .dout               (dout        ),
        .dout_vld           (dout_vld    ),
        .sel                (sel         ),
        .seg                (seg         )
    );


endmodule //temp_detect

2.DS18B20驱动

代码量有亿点点大😥 我们梳理一下大纲 总的来说

  • 设置了一个1微妙的计数器作为基础单位,因为我们通信中的延时都是1微妙的倍数;
  • 一个主状态机计数器,控制各个状态的延时时间;
  • 一个从状态机计数器,控制读写时隙各个状态的延时时间;
  • 一个比特计数器,因为主机与从机之间的通信是用命令来控制的,而这些命令都是8位的2进制数,读取温度的时候又需要读取两个字节(16位)的数据,所以需要一个比特计数器来控制读写的数据位数

①主状态机模块 宏观上来设置主机与从机之间通过单总线的通信过程,忽略收发数据的细节(也就是读写时隙),大致又分为两步:1.首先向从机发送温度转换命令;2.之后发送读取温度命令。

②从状态机模块 从微观上来描述主机发送指令或者主机读取温度产生的读写时隙,其中写时隙:首先从空闲状态进入拉低总线状态(代表开始读写了),然后发送1bit数据,之后释放总线,最后确定写数据是否结束,就看比特计数器是否记满8bit; 读时隙:首先从空闲状态进入拉低总线状态(代表开始读写了),然后读取1bit数据,之后释放总线,最后确定读数据是否结束,就看比特计数器是否记满16bit;

③温度转换模块 这个模块就比较简单了,主要任务就是我们与温度传感器通信之后得到的

module ds18b20_driver (
    input               clk              ,
    input               rst_n            ,
    input               dq_in            ,
    output   reg        dq_out           ,
    output   reg        dq_out_en        ,
    output   reg [23:0] temp_out         ,
    output   reg        temp_sign        ,
    output   reg        temp_out_vld     
);

//主状态机参数
localparam 
    M_IDLE = 9'b000_000_001  ,  //空闲状态,等待开始通信 
    M_REST = 9'b000_000_010  ,  //发送复位脉冲 
    M_RELE = 9'b000_000_100  ,  //释放总线 
    M_RACK = 9'b000_001_000  ,  //接收存在脉冲 
    M_RSKP = 9'b000_010_000  ,  //发送跳过 ROM 指令 
    M_CONT = 9'b000_100_000  ,  //发送温度转换命令 
    M_WAIT = 9'b001_000_000  ,  //等待 750ms 
    M_RCMD = 9'b010_000_000  ,  //发送温度读取指令 
    M_RTMP = 9'b100_000_000  ;  //读取温度值 

//从状态机参数
localparam 
    S_IDLE = 6'b000_001      ,  //空闲状态,等待传输请求 
    S_LOW  = 6'b000_010      ,  //发数据前先拉低 1us 
    S_SEND = 6'b000_100      ,  //发送 1bit 数据 
    S_SAMP = 6'b001_000      ,  //接收 1bit 数据 
    S_RELE = 6'b010_000      ,  //释放总线 
    S_DONE = 6'b100_000      ;  //发送/接收一次数据完成

//定义需要的命令
localparam 
    CMD_RSKP  = 8'hCC,  //跳过ROM指令
    CMD_CONT  = 8'h44,  //温度转换
    CMD_RTMP  = 8'hBE;  //读暂存器

//定义常用的时间
parameter 
    TIME_1US  = 50,      //1微秒 --- 基本单位
    //主状态机延时
    TIME_RST  = 500,     //复位脉冲 500us (480~690)
    TIME_REL  = 20,      //主机释放总线 20us (15~60)
    TIME_PRE  = 200,     //主机接收存在脉冲 200us (60~240)
    TIME_WAIT = 750000,  //主机发完温度转换命令 等待750ms
    //从状态机的延时
    TIME_LOW  = 2,       //主机拉低总线 2us (>=1)
    TIME_RW   = 60,      //主机读、写1bit 60us (>=60)
    TIME_REC  = 3;       //主机读写完1bit释放总线 3us (>=1)

//定义状态机
reg     [8:0]   m_state_c;  //主现态
reg     [8:0]   m_state_n;  //主次态

reg     [5:0]   s_state_c;  //Slave--从机
reg     [5:0]   s_state_n;

//定义计数器
reg     [19:0]  m_cnt;      //复位脉冲,释放总线,存在脉冲,温度转换
wire            m_add_cnt;
wire            m_end_cnt;
reg     [19:0]  X;          //控制主状态机各个状态计数的最大值

reg     [5:0]   s_cnt;      //从状态机各个状态的时间
wire            s_add_cnt;
wire            s_end_cnt;
reg     [5:0]   Y;          //控制从状态机各个状态计数的最大值

reg     [5:0]   cnt_1us;    //1us计数器
wire            add_cnt_1us;
wire            end_cnt_1us;

reg     [4:0]   cnt_bit;    //bit计数器 --- 计数发送数据的bit数
wire            add_cnt_bit;
wire            end_cnt_bit;

reg     [7:0]   cmd_r;      //寄存待发送指令
reg             slave_ack;  //接收存在脉冲
reg     [15:0]  temp_out_r; //寄存读取的温度
reg             flag;       //0:发温度转换命令 1:发温度读取命令
reg     [10:0]  temp_data;  //对补码进行操作生成原码
wire    [23:0]  temp_data_r;//解码之后的实际温度值

//定义状态转移条件
wire            m_idle2m_rest;  //发送复位脉冲
wire            m_rest2m_rele;  //释放总线
wire            m_rele2m_rack;  //接收存在脉冲 --- 由从机通过dq总线发送
wire            m_rack2m_rskp;  //发送跳过 ROM 指令
wire            m_rskp2m_cont;  //发送温度转换命令 
wire            m_rskp2m_rcmd;  //发送温度读取指令 
wire            m_cont2m_wait;  //发送温度转换命令 
wire            m_wait2m_rest;  //发送复位脉冲 
wire            m_rcmd2m_rtmp;  //读取温度值
wire            m_rtmp2m_idle;  //返回空闲状态

wire            s_idle2s_low ;  //拉低总线 --- 读写数据前
wire            s_low2s_send ;  //写数据 --- 主机向从机发数据
wire            s_low2s_samp ;  //读数据 --- 从机向主机发数据
wire            s_send2s_rele;  //释放总线
wire            s_samp2s_rele;  //释放总线
wire            s_rele2s_low ;  //拉低总线 --- 继续写数据或者读数据
wire            s_rele2s_done;  //读写一次数据结束 


//主状态机
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        m_state_c<=M_IDLE;
    end
    else
        m_state_c<=m_state_n;
end

always @(*) begin
    case(m_state_c)
        M_IDLE:begin 
            if(m_idle2m_rest)
                m_state_n = M_REST;
            else 
                m_state_n = m_state_c;
            end 
        M_REST:begin 
            if(m_rest2m_rele)
                m_state_n = M_RELE;
            else 
                m_state_n = m_state_c;
        end
        M_RELE:begin 
            if(m_rele2m_rack)
                m_state_n = M_RACK;
            else 
                m_state_n = m_state_c;
        end 
        M_RACK:begin 
            if(m_rack2m_rskp)
                m_state_n = M_RSKP;
            else 
                m_state_n = m_state_c;
        end 
        M_RSKP:begin 
            if(m_rskp2m_cont)
                m_state_n = M_CONT;
            else if(m_rskp2m_rcmd)
                m_state_n = M_RCMD;
            else 
                m_state_n = m_state_c;
        end 
        M_CONT:begin 
            if(m_cont2m_wait)
                m_state_n = M_WAIT;
            else 
                m_state_n = m_state_c;
        end 
        M_WAIT:begin 
            if(m_wait2m_rest)
                m_state_n = M_REST;
            else 
                m_state_n = m_state_c;
        end 
        M_RCMD:begin 
            if(m_rcmd2m_rtmp)
                m_state_n = M_RTMP;
            else 
                m_state_n = m_state_c;
        end 
        M_RTMP:begin 
            if(m_rtmp2m_idle)
                m_state_n = M_IDLE;
            else 
                m_state_n = m_state_c;
        end         
        default:m_state_n = M_IDLE;
    endcase
end

assign m_idle2m_rest = m_state_c == M_IDLE && (1'b1);                                //状态机一开始就进入复位状态,等待复位脉冲
assign m_rest2m_rele = m_state_c == M_REST && (m_end_cnt);                           //主机输出低电平,保持低电平时间至少480us(500us)
assign m_rele2m_rack = m_state_c == M_RELE && (m_end_cnt);                           //释放总线,由上拉电阻拉高总线,延时15~60us(20us)
assign m_rack2m_rskp = m_state_c == M_RACK && (m_end_cnt && slave_ack == 0);         //从机发送存在脉冲60~240us(200us),主机在60us处采样
assign m_rskp2m_cont = m_state_c == M_RSKP && (s_state_c == S_DONE && flag == 0);    //首先进行温度转换
assign m_rskp2m_rcmd = m_state_c == M_RSKP && (s_state_c == S_DONE && flag == 1);    //然后读取温度
assign m_cont2m_wait = m_state_c == M_CONT && (s_state_c == S_DONE);                 //温度转换
assign m_wait2m_rest = m_state_c == M_WAIT && (m_end_cnt);                           //12位的温度数据进行转换需要延时最多750ms
assign m_rcmd2m_rtmp = m_state_c == M_RCMD && (s_state_c == S_DONE);                 //发送读温度指令
assign m_rtmp2m_idle = m_state_c == M_RTMP && (s_state_c == S_DONE);                 //读取温度,之后恢复空闲状态 --- 进行下一次温度读取

//从状态机
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        s_state_c <= S_IDLE;
    end
    else
        s_state_c <= s_state_n;
end

always @(*) begin
    case (s_state_c)
        S_IDLE:begin 
            if(s_idle2s_low)
                s_state_n = S_LOW;
            else 
                s_state_n = s_state_c;
            end  
        S_LOW :begin 
            if(s_low2s_send)
                s_state_n = S_SEND;
            else if(s_low2s_samp)
                s_state_n = S_SAMP;
            else 
                s_state_n = s_state_c;
            end  
        S_SEND:begin 
            if(s_send2s_rele)
                s_state_n = S_RELE;
            else 
                s_state_n = s_state_c;
        end  
        S_SAMP:begin 
            if(s_samp2s_rele)
                s_state_n = S_RELE;
            else 
                s_state_n = s_state_c;
        end  
        S_RELE:begin 
            if(s_rele2s_low)
                s_state_n = S_LOW;
            else if(s_rele2s_done)
                s_state_n = S_DONE;
            else 
                s_state_n = s_state_c;
        end  
        S_DONE:begin               //进入s_done状态,下一个时钟周期上升沿将回到初始状态
                s_state_n = S_IDLE;
        end  
        default:s_state_n = S_IDLE;
    endcase
end

assign s_idle2s_low  =  s_state_c == S_IDLE && (m_state_c == M_RSKP || m_state_c == M_CONT || m_state_c == M_RTMP || m_state_c == M_RCMD );                //需要在总线上传输数据时产生读写时隙
assign s_low2s_send  =  s_state_c == S_LOW  && (s_end_cnt && (m_state_c == M_RSKP ||
 m_state_c == M_CONT || m_state_c == M_RCMD));                  //发命令 
assign s_low2s_samp  =  s_state_c == S_LOW  && (s_end_cnt && (m_state_c == M_RTMP)); //读温度值
assign s_send2s_rele =  s_state_c == S_SEND && (s_end_cnt);     //发送数据
assign s_samp2s_rele =  s_state_c == S_SAMP && (s_end_cnt);     //采样 --- 15us内有效
assign s_rele2s_low  =  s_state_c == S_RELE && (s_end_cnt && ~end_cnt_bit);  //还有需要读写的bit,继续回到起始位,拉低总线
assign s_rele2s_done =  s_state_c == S_RELE && (s_end_cnt &&  end_cnt_bit);   //已经读写完成

//cnt_1us
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_1us<=0;
    end
    else if(add_cnt_1us) begin
        if (end_cnt_1us) begin
            cnt_1us<=0 

标签: ii5919传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台