FPGA project : DS18B20

2023-09-21 23:59:44

本想着一天发一个实验的,这个ds18b20,耗时两天。代码写了两次,呜呜~

由于第二次写代码没画时序图,所以代码和时序图一些参数有些不一致,但问题不大。

这里有几件事情值得一提:

1:关于状态机的编写,我觉得还是三段式比较好。

2:关于生成其他时钟信号,用来做触发边沿。我不喜欢用这种方法(提一个概念“全局时钟网络”)。所以用产生一个1us base基础计时器,产生一个1us的标志信号。之后的计数器与该计数器级联,记得把<end_cnt_base>这个标志信号加上。

我犯下的错误:

1:在画时序图是,没有画<end_cnt_base>标志信号,直接默认时钟为周期为1us,造成了混乱。所以以后要注意。

2:&& 逻辑写成了 || 逻辑

3:三态门输出 Z 写成了 1

4:数据位宽定义错误,因为少思考了一个数据对应的位宽。

4:读取温度时,少记一位。注意data_bit跳转条件,和发指令时不一样的。

 

 

module ds18b20(
    input   wire            sys_clk     ,
    input   wire            sys_rst_n   ,

    inout   wire            dq          ,

    output  reg     [19:0]  data        ,
    output  reg             sign  
);

    // localparam   指令,先发低位。
    localparam      WR_CMD_WORD = 16'h44CC    ,
                    RD_CMD_WORD = 16'hBECC    ;
    localparam      INIT        =  6'b000_001 ,
                    WR_CMD      =  6'b000_010 ,
                    WAIT        =  6'b000_100 ,
                    INIT_AGIN   =  6'b001_000 ,
                    RD_CMD      =  6'b010_000 ,
                    RD_TEMP     =  6'b100_000 ;
    // wire signal define
    wire            end_cnt_base      ;
    wire            INITtoWR_CMD      ;
    wire            WR_CMDtoWAIT      ;
    wire            WAITtoINIT_AGIN   ;
    wire            INIT_AGINtoRD_CMD ;
    wire            RD_CMDtoRD_TEMP   ;
    wire            RD_TEMPtoINIT     ;
    // reg  signal define
    reg     [5:0]   cnt_base     ;
    reg             dq_en        ;
    reg             dq_out       ;
    reg     [5:0]   state_c  /*synthesis preserve*/;
    reg     [5:0]   state_n  /*synthesis preserve*/;
    reg     [19:0]  cnt          ;
    reg     [4:0]   data_bit     ;
    reg             flag_respond ;
    reg             data_done    ;
    reg     [15:0]  data_temp    ; // 读取高速缓存器的byte0和byte1,一共16位。
    
    /****************************************************************************************/
    // reg     [5:0]       cnt_base ;
    // wire                end_cnt_base ;
    always @(posedge sys_clk or negedge sys_rst_n) 
        if(~sys_rst_n)
            cnt_base <= 6'd0 ;
        else if(end_cnt_base)
            cnt_base <= 6'd0 ;
        else 
            cnt_base <= cnt_base + 1'b1 ;
    assign  end_cnt_base = cnt_base == 49;
    // reg     [5:0]       state_c ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            state_c <= INIT;
        else 
            state_c <= state_n ;
    // reg     [5:0]       state_n ;
    always @(*)
        case (state_c)
        INIT       :if(INITtoWR_CMD)
                        state_n <= WR_CMD ;
                    else 
                        state_n <= INIT ;
        WR_CMD     :if(WR_CMDtoWAIT)
                        state_n <= WAIT ;
                    else 
                        state_n <= WR_CMD ;
        WAIT       :if(WAITtoINIT_AGIN)
                        state_n <= INIT_AGIN ;
                    else 
                        state_n <= WAIT ;
        INIT_AGIN  :if(INIT_AGINtoRD_CMD)
                        state_n <= RD_CMD ;
                    else 
                        state_n <= INIT_AGIN ;
        RD_CMD     :if(RD_CMDtoRD_TEMP)
                        state_n <= RD_TEMP ;
                    else 
                        state_n <= RD_CMD ;
        RD_TEMP    :if(RD_TEMPtoINIT)
                        state_n <= INIT ;
                    else 
                        state_n <= RD_TEMP ;
        default    :    state_n <= INIT ;
        endcase
    // 状态转移条件
    assign  INITtoWR_CMD        = (state_c == INIT      ) && (end_cnt_base && flag_respond == 1'b1 && cnt == 999);
    assign  WR_CMDtoWAIT        = (state_c == WR_CMD    ) && (end_cnt_base ==1'b1 && cnt == 60 && data_bit == 15) ;
    assign  WAITtoINIT_AGIN     = (state_c == WAIT      ) && (end_cnt_base && cnt == 749_999)  ;
    assign  INIT_AGINtoRD_CMD   = (state_c == INIT_AGIN ) && (end_cnt_base && flag_respond == 1'b1 && cnt == 999);
    assign  RD_CMDtoRD_TEMP     = (state_c == RD_CMD    ) && (end_cnt_base ==1'b1 && cnt == 60 && data_bit == 15)  ;
    assign  RD_TEMPtoINIT       = (state_c == RD_TEMP   ) && (end_cnt_base ==1'b1 && cnt == 60 && data_done == 1'b1);

    // reg     [19:0]       cnt ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            cnt <= 20'd0 ;
        else case (state_c)
        INIT      : if(cnt == 999 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        WR_CMD    : if(cnt == 60 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        WAIT      : if(cnt == 749_999 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        INIT_AGIN : if(cnt == 999 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        RD_CMD    : if(cnt == 60 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        RD_TEMP   : if(cnt == 60 && end_cnt_base == 1'b1)
                        cnt <= 20'd0 ;
                    else if(end_cnt_base == 1'b1)
                        cnt <= cnt + 1'b1 ;
        default   :     cnt <= 20'd0 ;
        endcase
    // reg     [3:0]       data_bit ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data_bit <= 5'd0 ;
        else case (state_c)
        INIT      : data_bit <= 5'd0 ;
        WR_CMD    : if(end_cnt_base == 1'b1 && cnt == 60 && data_bit == 15)
                        data_bit <= 5'd0 ;
                    else if(end_cnt_base == 1'b1 && cnt == 60)
                        data_bit <= data_bit + 1'b1 ;
                    else 
                        data_bit <= data_bit ;
        WAIT      : data_bit <= 5'd0 ;
        INIT_AGIN : data_bit <= 5'd0 ;
        RD_CMD    : if(end_cnt_base == 1'b1 && cnt == 60 && data_bit == 15)
                        data_bit <= 5'd0 ;
                    else if(end_cnt_base == 1'b1 && cnt == 60)
                        data_bit <= data_bit + 1'b1 ;
                    else 
                        data_bit <= data_bit ;
        RD_TEMP   : if(end_cnt_base == 1'b1 && cnt == 10 && data_bit == 16) // 第十微秒的时候采样。
                        data_bit <= 5'd0 ;
                    else if(end_cnt_base == 1'b1 && cnt == 10)
                        data_bit <= data_bit + 1'b1 ;
                    else 
                        data_bit <= data_bit ;
        default   :     data_bit <= 5'd0 ;
        endcase

    // reg                 flag_respond ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            flag_respond <= 1'b0 ;
        else if(state_c != INIT && state_c != INIT_AGIN)
            flag_respond <= 1'b0 ;
        else if((state_c == INIT || state_c == INIT_AGIN) && cnt == 590 && dq == 1'b0)
            flag_respond <= 1'b1 ;
        else 
            flag_respond <= flag_respond ;

    // reg                 data_done ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data_done <= 1'b0 ;
        else if(state_c != RD_TEMP)
            data_done <= 1'b0 ;
        else if(state_c == RD_TEMP && end_cnt_base == 1'b1 && data_bit == 16)
            data_done <= 1'b1 ;
        else 
            data_done <= data_done ;
    
    // reg     [15:0]      data_temp ;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data_temp <= 16'd0 ;
        else if(state_c == RD_TEMP && end_cnt_base == 1'b1 && cnt == 13)
            data_temp <= {dq,data_temp[15:1]} ;
        else 
            data_temp <= data_temp ;

    // reg                 dq_en  ;
    // reg                 dq_out ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            dq_en  <= 1'b0 ;
            dq_out <= 1'b0 ;
        end else begin
            case (state_c)
            INIT     :  begin
                            if(cnt >= 0 && cnt <= 499) begin
                                dq_en  <= 1'b1 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end     
                        end
            WR_CMD   :  begin
                            if(cnt == 60) begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                if(WR_CMD_WORD[data_bit] == 1'b1) begin
                                    if(cnt >= 0 && cnt <= 14) begin
                                        dq_en  <= 1'b1 ;
                                        dq_out <= 1'b0 ;
                                    end else begin
                                        dq_en  <= 1'b0 ;
                                        dq_out <= 1'b0 ;
                                    end
                                end else begin
                                    dq_en  <= 1'b1 ;
                                    dq_out <= 1'b0 ;
                                end
                            end     
                        end
            WAIT     :  begin
                            dq_en  <= 1'b1 ;
                            dq_out <= 1'b1 ;
                        end
            INIT_AGIN:  begin
                            if(cnt >= 0 && cnt <= 499) begin
                                dq_en  <= 1'b1 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end     
                        end
            RD_CMD   :  begin
                            if(cnt == 60) begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                if(RD_CMD_WORD[data_bit] == 1'b1) begin
                                    if(cnt >= 0 && cnt <= 14) begin
                                        dq_en  <= 1'b1 ;
                                        dq_out <= 1'b0 ;
                                    end else begin
                                        dq_en  <= 1'b0 ;
                                        dq_out <= 1'b0 ;
                                    end
                                end else begin
                                    dq_en  <= 1'b1 ;
                                    dq_out <= 1'b0 ;
                                end
                            end     
                        end
            RD_TEMP  :  begin
                            if(cnt == 0 || cnt == 1) begin
                                dq_en  <= 1'b1 ;
                                dq_out <= 1'b0 ;
                            end else begin
                                dq_en  <= 1'b0 ;
                                dq_out <= 1'b0 ;
                            end
                        end
            default:    begin
                            dq_en  <= 1'b0 ;
                            dq_out <= 1'b0 ;
                        end
            endcase
        end
    end

/***********************************************************************/
    // wire            dq          
    assign dq = (dq_en == 1'b1) ? dq_out : 1'bz ;

    // reg     [19:0]  data        
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            data <= 20'd0 ;
        else if(state_c == RD_TEMP && data_done == 1'b1) 
                if(data_temp[15] == 1'b0)
                    data <= data_temp[10:0] * 10'd625;
                else 
                    data <= (~data_temp[10:0]  + 1'b1 ) * 10'd625;
        else 
            data <= data ;

    // reg             sign 
    always @(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            sign <= 1'b0 ;
        else if(state_c == RD_TEMP && data_done == 1'b1)
            sign <= data_temp[15];
        else 
            sign <= sign ;
            
endmodule
module top(
    input       wire        sys_clk   ,
    input       wire        sys_rst_n ,

    inout       wire        dq        ,

    output      wire        ds        ,
    output      wire        oe        ,
    output      wire        shcp      ,
    output      wire        stcp    
);

    wire   [19:0]  data_w   /*synthesis keep */;
    wire           sign_w   ;
    wire   [05:00] point_w  ;
    wire           seg_en_w ;
    assign         seg_en_w= 1'b1       ;
    assign         point_w = 6'b010_000 ;



ds18b20 ds18b20_insert(
    .sys_clk                ( sys_clk   ) ,
    .sys_rst_n              ( sys_rst_n ) ,

    .dq                     ( dq        ) ,

    .data                   ( data_w    ) ,
    .sign                   ( sign_w    )      
);

seg_595_dynamic seg_595_dynamic_insert(
    .sys_clk                ( sys_clk   ) ,
    .sys_rst_n              ( sys_rst_n ) ,
    .data                   ( data_w    ) ,
    .point                  ( point_w   ) ,
    .sign                   ( sign_w    ) ,
    .seg_en                 ( seg_en_w  ) ,

    .ds                     ( ds        ) ,
    .oe                     ( oe        ) ,
    .shcp                   ( shcp      ) ,
    .stcp                   ( stcp      )    
);

endmodule

更多推荐

大数据分布式处理框架Hadoop

大数据是什么大数据容量常以TB、PB、甚至EB为单位,远超传统数据库的承载能力,无论入库还是查询都出现性能瓶颈。Hadoop是什么Hadoop是开源的分布式计算技术框架,用于处理大规模数据和实现分布式存储。Hadoop核心组件HDFS(HadoopDistributedFileSystem分布式文件系统):是Hadoo

学习Nano编辑器:入门指南、安装步骤、基本操作和高级功能

文章目录使用Nano编辑器入门指南引言1.1关于Nano编辑器1.2Nano的起源和特点安装Nano2.1在Debian/Ubuntu系统上安装Nano2.2在CentOS/RHEL系统上安装Nano2.3在其他Linux发行版上安装Nano启动Nano3.1命令行启动Nano3.2打开文件Nano的基本操作4.1光标

如何批量为文件夹命名

如果你想要命名一些这样名字具有规律性的文件夹,当文件的数量增多,一个一个命名是非常耗费时间的。很容易想到,如果使用EXCEL,只需往下拉,就能很轻松的拉出1到5。那么,我们如何利用EXCEL来对文件夹进行快速的批量命名呢?以上图为例子,人名可能是我们已知的,可以从表格直接复制过来。而客户名1到客户名5,我们可以直接使用

大数据Flink(六十四):Flink运行时架构介绍

文章目录Flink运行时架构介绍一、系统架构二、​​​​​​​​​​​​​​整体构成三、作业管理器(JobManager)四、任务管理器(TaskManager)Flink运行时架构介绍我们已经对Flink的主要特性和部署提交有了基本的了解,那它的内部又是怎样工作的,集群配置设置的一些参数又到底有什么含义呢?接下来我们

基于vue的黑马前端项目小兔鲜

目录项目学习初始化项目建立项目引入elementpluselementPlus主题设置配置axios路由引入静态资源自动导入scss变量Layout页组件结构快速搭建字体图标渲染一级导航渲染吸顶导航交互实现Pinia优化重复请求Home页分类实现banner轮播图新鲜好物实现人气推荐实现懒加载指令实现产品列表实现Goo

正确设置PyTorch训练时使用的GPU资源

背景:最近在使用HuggingFace的transformersapi来进行预训练大模型的微调,机器是8卡的GPU,当我调用trainer.train()之后,发现8个GPU都被使用了,因为这个机器上面还有其他人跑的模型,当我进行训练的时候,GPU的使用率就接近了100%,这样导致其他人的模型响应速度特别的慢,因为他们

微信小程序如何刷新当前页面

微信小程序是一种快速发展的移动应用程序开发平台,它提供了许多功能和特性,使开发者能够轻松创建功能丰富的小程序。在开发小程序时,有时我们需要刷新当前页面来更新数据或重新加载页面内容。本文将解释如何在微信小程序中刷新当前页面的代码。引言微信小程序的流行使得越来越多的开发者将其作为构建移动应用的首选平台。然而,与传统的网页开

快速了解Apipost

随着数字化转型的加速,API(应用程序接口)已经成为企业间沟通和数据交换的关键。而在API开发和管理过程中,API文档、调试、Mock和测试的协作显得尤为重要。Apipost正是这样一款一体化协作平台,旨在解决这些问题,提高API开发效率和质量。Apipost提供API文档管理功能,让后端开发人员可以在开发完接口调试的

cookie信息无法获取问题研究

背景在oneapi这个前后端都有的开源项目中,我想接入chatnextweb到oneapi的后端。由于需要二开chatnextweb,添加登录注册功能,考虑到java后端的性能问题和内存占用,决定不重启写个服务,而是将登录注册接入到oneapi的登录注册api,没错,和oneapi的前端公用一套登录注册熬了个大夜后,终

GLTF编辑器:在线模型材质编辑工具

GLTF编辑器是一个功能强大、易于使用的在线3D模型编辑和查看工具,它支持多种格式的3D模型导入并将模型导出为GLB格式,除了可以对3D模型进行基本属性的修改之外,还支持对模型原点重置以及模型材质纹理修改。对于3D开发者和设计师来说,GLTF编辑器是一个非常有用的工具,可以帮助他们更方便地处理3D模型数据。1、首先介绍

VR全景技术在教育中的应用:VR教学的“因材施教”

随着科技的不断进步和发展,VR全景技术在教育领域的应用,给传统教育模式带来了新的变革和机遇,同时也促进了教育的创新和进步。VR教学模式可以打破传统教育的限制,通过模拟各种场景,让学生身临其境地学习多样化知识,感受不同国家的风土人情、拓展自身视野,这种具备沉浸感的学习体验可以很好的激发学生的学习兴趣和动力。VR教学可以构

热文推荐