FPGA开发——DS18B20读取温度并且在数码管上显示

news2024/12/30 2:28:47

一、简介

        在上一篇文章中我们对于DS18B20的相关理论进行了详细的解释,同时也对怎样使用DS18B20进行了一个简单的叙述。在这篇文章我们通过工程来实现DS18B20的温度读取并且实现在数码管伤显示。

1、基本实现思路

根据不同时刻的操作,我们可以使用一个状态机来实现温度的读取。

如图所示,通过 初始化——>ROM指令写入——>温度转换命令写入——>二次初始化——>二次ROM指令写入——>温度读取命令写入——>温度读取等一系列操作就可以实现DS18B20的温度读取。

2、状态转换框图

将实现思路划分成6个状态,从而减少代码量。

二、工程实现

1、设计文件的编写

(1)DS18B20

        新建一个ds18b20.v文件,如下:在这里需要用到的计数器非常多,如果对于每个状态都使用一个计数器的话,所占用的资源就会非常多,这里我们可以根据状态进行划分,实现同一个计数器在不同状态进行不同计数的方法,也就是分时复用的思路对于计数器进行带编写。并且在实现代码中,我们将跳过ROM指令和温度转换指令写在一起,将跳过ROM指令和温度读取指令写在一起,通过同一个位宽的bit计数器就可以进行命令的写入。

module ds18b20_driver( 
    input				clk		        ,
    input				rst_n	        ,
    //ds182b20 port
    inout               dq              ,//单总线(双向口)
    //user port
    output  reg         sign            ,//符号位,正数为0,负数为1
    output  reg [19:0]  dout       ,
    output  reg         dout_vld   
);								 
//-------------<参数定义>---------------------------------------------------------
//状态机参数定义
    localparam  INIT        = 6'b0000_01,//主机初始化状态:主机发送复位脉冲-->主机释放总线-->主机接收存在脉冲(ds18b20接收到存在脉冲后拉低总线)
                WRCMD       = 6'b0000_10,//主机发送跳过ROM命令状态
                WAIT        = 6'b0001_00,//等待温度转换完成状态
                INIT_AGAIN  = 6'b0010_00,//二次初始化
                RDCMD       = 6'b0100_00,//主机发送读取温度命令状态
                RDTEM       = 6'b1000_00;//主机读取温度(2字节)状态

//时间参数定义
    parameter   TIME_1US = 50;//1us
    parameter   TM_INIT = 720   ,//初始化时间750us:主机发送复位脉冲至少480us(取500us)-->主机释放总线15-60us(取20us)-->主机接收存在脉冲60-240us(取200us)
                TM_LOW  = 2     ,//读写时隙,拉低总线至少1us(取2us)
                TM_60US = 60    ,//读写时隙至少60us
                TM_3US  = 3     ,//连续两个读或写时隙至少间隔1us的恢复时间
                TM_WAIT = 750_000 ;//温度转换最大750ms(精度12bits)

//命令参数定义
    localparam  CMD_SKROM = 8'hCC,//跳过ROM命令
                CMD_CONVE = 8'h44,//温度转换命令
                CMD_RDCMD = 8'hBE;//读取温度命令

//-------------<内部信号定义>-----------------------------------------------------
    wire                dq_in       ;//双向端口输入
    reg                 dq_out      ;//双向端口输出
    reg                 dq_out_en   ;//双向端口输出使能
    
    reg     [5:0]       state_c     ;//状态机现态
    reg     [5:0]       state_n     ;//状态机次态

    reg		[7:0]	    cnt_1us	    ;//1us基准计数器
    wire				add_cnt_1us ;
    wire				end_cnt_1us ;
    reg     [19:0]      xx          ;
    reg		[19:0]	    cnt_xx 	    ;//复用计数器
    wire				add_cnt_xx  ;
    wire				end_cnt_xx  ;
    reg		[4:0]	    cnt_bit	    ;//比特计数器
    wire				add_cnt_bit ;
    wire				end_cnt_bit ;

    reg                 presen_pulse;//存在脉冲
    reg                 flag        ;//标志信号     发起温度转换,为0;读取温度,为1
    reg     [15:0]       wr_data     ;//写入数据(命令)
    reg     [15:0]      rd_data     ;//读出的温度数据

    wire                init2wrcmd      ;
    wire                wrcmd2wait      ;
    wire                wait2initagain   ;
    wire                initagain2rdcmd  ;
    wire                rdcmd2rdtem     ;
    wire                rdtem2init      ;
    
    assign  dq = dq_out_en ? dq_out : 1'bz;//输出使能为1时输出;为0时高阻态
    assign  dq_in = dq                    ;//高阻态时,将双向总线的数据赋值给输入


//--state_c(三段式状态机)
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            state_c <= INIT;
        end 
        else begin 
            state_c <= state_n;
        end 
    end

    always @(*) begin
        case(state_c)
            INIT : begin
                if(init2wrcmd)begin 
                    state_n = WRCMD;
                end
                else begin 
                    state_n = state_c;
                end
            end
            WRCMD : begin
                if(wrcmd2wait)begin 
                    state_n = WAIT;
                end
                else begin 
                    state_n = state_c;
                end
            end
            WAIT : begin
                if(wait2initagain)begin 
                    state_n = INIT_AGAIN;
                end
                else begin 
                    state_n = state_c;
                end
            end
            INIT_AGAIN : begin
                if(initagain2rdcmd)begin 
                    state_n = RDCMD;
                end
                else begin 
                    state_n = state_c;
                end
            end
            RDCMD : begin
                if(rdcmd2rdtem)begin 
                    state_n = RDTEM;
                end
                else begin 
                    state_n = state_c;
                end
            end
            RDTEM : begin
                if(rdtem2init)begin 
                    state_n = INIT;
                end
                else begin 
                    state_n = state_c;
                end
            end
            default : state_n = INIT;
        endcase
    end
    assign init2wrcmd      = (state_c == INIT      ) && end_cnt_xx && !presen_pulse;
    assign wrcmd2wait      = (state_c == WRCMD     ) && end_cnt_bit ;
    assign wait2initagain  = (state_c == WAIT      ) && end_cnt_xx;
    assign initagain2rdcmd = (state_c == INIT_AGAIN) && end_cnt_xx && !presen_pulse;
    assign rdcmd2rdtem     = (state_c == RDCMD     ) && end_cnt_bit;
    assign rdtem2init      = (state_c == RDTEM     ) && end_cnt_bit;

//--cnt_1us
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_1us <= 'd0;
        end 
        else if(add_cnt_1us)begin 
            if(end_cnt_1us)begin 
                cnt_1us <= 'd0;
            end
            else begin 
                cnt_1us <= cnt_1us + 1'b1;
            end 
        end
        else 
            cnt_1us <= cnt_1us;

    end 
    
    assign add_cnt_1us = 1'b1;
    assign end_cnt_1us = add_cnt_1us && cnt_1us == TIME_1US - 1;

//--cnt_xx
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_xx <= 'd0;
        end 
        else if(add_cnt_xx)begin 
            if(end_cnt_xx)begin 
                cnt_xx <= 'd0;
            end
            else begin 
                cnt_xx <= cnt_xx + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_xx = end_cnt_1us;
    assign end_cnt_xx = add_cnt_xx && cnt_xx == xx - 1;

//xx  
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            xx <= 'd0;
        end 
        else if((state_c == INIT) ||(state_c == INIT_AGAIN))begin 
            xx <= TM_INIT;
        end 
        else if(state_c == WAIT)begin
            xx <= TM_WAIT;
        end
        else begin                      //除了INIT和WAIT两个状态,其它几个状态都在读或写(IDLE状态未考虑,计数器在IDLE状态下不工作)
            xx <= TM_LOW + TM_60US + TM_3US;//读写1bit数据需要的时间
        end 
    end

//--cnt_bit
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_bit <= 'd0;
        end 
        else if(add_cnt_bit)begin 
            if(end_cnt_bit)begin 
                cnt_bit <= 'd0;
            end
            else begin 
                cnt_bit <= cnt_bit + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_bit = end_cnt_xx && (state_c == WRCMD || state_c == RDCMD || state_c == RDTEM);
    assign end_cnt_bit = add_cnt_bit && cnt_bit == 16-1;

//--presen_pulse
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            presen_pulse <= 'd0;
        end 
        else if(((state_c == INIT) ||(state_c == INIT_AGAIN))&& (cnt_xx == 550) && (end_cnt_1us))begin 
            presen_pulse <= dq_in;
        end 
    end
//--wr_data 
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            wr_data <= 'd0;
        end 
        else if(state_c == WRCMD)begin 
            wr_data <= 16'h44cc;
        end 
        else if(state_c == RDCMD)begin 
            wr_data <= 16'hbecc;
        end
        else begin 
            wr_data <= 'd0;
        end 
    end
//--dq_out、dq_out_en 
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            dq_out_en <= 'd0;
            dq_out <= 'd0;
        end 
        else if((state_c == INIT ||state_c == INIT_AGAIN) && (cnt_xx < 20'd500))begin 
            dq_out_en <= 1'b1;
            dq_out <= 1'b0;
        end 
        else if(state_c == WRCMD || state_c == RDCMD)begin 
            if(cnt_xx <TM_LOW)begin 
                dq_out_en <= 1'b1;
                dq_out <= 1'b0;
            end
            else if(cnt_xx >= TM_LOW && cnt_xx < (TM_LOW+TM_60US))begin 
                if(wr_data[cnt_bit] == 0)begin  //写0时隙
                    dq_out_en <= 1'b1;
                    dq_out <= 1'b0;
                end
                else if(wr_data[cnt_bit] == 1)begin //写1时隙
                    dq_out_en <= 1'b0;
                    dq_out <= 1'b0;
                end
            end
            else begin              //记住不能省略
                dq_out_en <= 1'b0;
                dq_out <= 1'b0;
            end
        end
        else if(state_c == RDTEM)begin 
            if(cnt_xx < TM_LOW)begin 
                dq_out_en <= 1'b1;
                dq_out <= 1'b0;
            end
            else begin 
                dq_out_en <= 1'b0;
                dq_out <= 1'b0;
            end
        end
        else begin 
            dq_out_en <= 1'b0;
            dq_out <= 1'd0;
        end
    end

//--rd_data
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            rd_data <= 'd0;
        end 
        else if(state_c == RDTEM && cnt_xx == 20'd12 )begin 
            rd_data[cnt_bit] <= dq_in;
        end 
    end

//--dout、dout_vld、sign
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            dout <= 'd0;
            sign <= 'd0;
        end 
        else if(state_c == RDTEM && end_cnt_bit)begin 
            if(rd_data[15] == 1'b0)begin //读出的温度数据机器码符号位为0,温度为正
                dout <= rd_data[10:0]*20'd625;
                sign <= 1'b0;
            end
            else begin                  //读出的温度数据机器码符号位为1,温度为负 
                dout <= (~rd_data[10:0] + 1'b1)*20'd625;  //考虑位宽溢出的问题
                sign <= 1'b1;
            end
        end 
    end
    
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            dout_vld <= 1'b0;
        end 
        else 
            dout_vld <= rdtem2init;
    end

endmodule

(2)数码管

新建一个seg_driver.v文件,如下:

module seg_driver(
    input clk,
    input rst_n,
    input [23:0] din,
    input        sign,

    output reg [5:0] sel,
    output reg [7:0] dig

);
//参数定义
parameter TIME_1MS  =50_000;
localparam    ZERO  =7'b100_0000,
              ONE   =7'b111_1001,
              TWO   =7'b010_0100,
              TEREE =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,
              P     =7'b000_1100,
              N     =7'b100_1000,
              NULL  =7'b111_1111;

//内部信号定义
reg  [15:0]   cnt_1ms;
wire          add_cnt_1ms;
wire          end_cnt_1ms;

reg    [5:0]  seg_r;
reg           flag;//小数点标志位
reg    [23:0] dis_data;
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_1ms <= 'd0;
    end 
    else if(add_cnt_1ms)begin 
        if(end_cnt_1ms)begin 
            cnt_1ms <= 'd0;
        end
        else begin 
            cnt_1ms <= cnt_1ms + 1'b1;
        end 
    end
end 

assign add_cnt_1ms =1'b1 ;
assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == TIME_1MS-1;

//数码管位选
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        sel <= 6'b111_110;
    end 
    else if(end_cnt_1ms)begin 
        sel <={sel[4:0],sel[5]};
    end 
end
//小数点位置 0为亮,1为灭
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        flag <= 'd1;
    end 
    else begin 
        case (sel)
            6'b110_111:flag <= 1'b0; //第三个数码管位置
            default: flag<= 'd1;
        endcase
    end 
end

//数码管显示数据分布
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        dis_data <= 'd0;
    end 
    else begin 
        case (sel)
            6'b111_110:dis_data <= din[7:4];
            6'b111_101:dis_data <= din[11:8];
            6'b111_011:dis_data <= din[15:12];
            6'b110_111:dis_data <= din[19:16];
            6'b101_111:dis_data <= din[23:20];
            6'b011_111:dis_data <=(sign ?4'ha:4'hb) ; 
            default: ;
        endcase
    end 
end

//数据显示
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        dig <= NULL;
    end 
    else begin 
        case (dis_data)
            0   :dig<={flag,ZERO };
            1   :dig<={flag,ONE  };
            2   :dig<={flag,TWO  };
            3   :dig<={flag,TEREE};
            4   :dig<={flag,FOUR };
            5   :dig<={flag,FIVE };
            6   :dig<={flag,SIX  };
            7   :dig<={flag,SEVEN};
            8   :dig<={flag,EIGHT};
            9   :dig<={flag,NINE };
            4'ha:dig<={flag,N    };
            4'hb:dig<={flag,P    };
            default:dig<= NULL;
        endcase
    end 
end
endmodule

2、数据处理文件的编写

当我们进行温度读取时,需要对原始数据进行处理之后采用将其显示在数码管中,所以这里还需要一个处理数据文件进行数据转换,新建一个data.v文件,如下:

module data(
    input  clk,
    input rst_n,
    input [19:0] din,
    input        din_vld,
    output   [23:0] dout
);
wire  [7:0]  data_r_int;
wire  [15:0]  data_r_float;
reg  [3:0]   data_r1;
reg  [3:0]   data_r2;
reg  [3:0]   data_r3;
reg  [3:0]   data_r4;
reg  [3:0]   data_g ;
reg  [3:0]   data_s ;
reg          din_vld_r;
assign  data_r_int=din/10000;
assign  data_r_float=din%10000;

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
      din_vld_r   <= 'd0;
    end 
    else 
        din_vld_r <= din_vld;
end
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        data_r1<='d0;
        data_r2<='d0;
        data_r3<='d0;
        data_r4<='d0;
        data_g <='d0;
        data_s <='d0;
    end
    else if(din_vld_r)begin
        data_s <=data_r_int/10;
        data_g <=data_r_int%10;
        data_r1<=data_r_float/1000;
        data_r2<=data_r_float/100%10;
        data_r3<=data_r_float/10%10;
        data_r4<=data_r_float%10;
    end

end
assign dout={data_s,data_g,data_r1,data_r2,data_r3,data_r4};
endmodule

3、顶层文件的编写

通过编写一个顶层文件将三个.v文件整合在一起,新建一个top.v文件,如下:

module top (
    input       clk     ,
    input       rst_n   ,
    inout       dq      ,
    output      tx ,
    output   [5:0] sel,
    output   [7:0] dig          
);
wire  [23:0] dis_data;//温度数值
wire   sign;   //符号位
wire   sign_out;
wire  [19:0]   dout    ;
wire     dout_vld;

seg_driver seg_driver_inst(
    /*input            */ .clk   (clk)          ,
    /*input            */ .rst_n (rst_n)        ,
    /*input [23:0]     */ .din   (dis_data )    ,
    /*input            */ .sign  (sign)         ,
    /*output reg [5:0] */ .sel   (sel)          ,
    /*output reg [7:0] */ .dig   (dig)

);


data data_inst(
    /*input          */ .clk    (clk),
    /*input          */ .rst_n  (rst_n),
    /*input [19:0]   */ .din    (dout),
    /*input          */ .din_vld(dout_vld),
    /*output   [23:0]*/ .dout   (dis_data)
);


ds18b20_driver  ds18b20_driver_inst(
   /* input              */. clk      (clk     )  ,
   /* input              */. rst_n    (rst_n   )  ,
   /* input              */. dq       (dq   )  ,//输入信号
   /* output  reg  [19:0]*/. dout     (dout    )  ,//串行发送出去的数据
   /* output             */. dout_vld (dout_vld)  ,
   /* output             */. sign     (sign    )  //发送一字节完成信号
);
endmodule

4、在线调试

因为这里需过用modelsim进行仿真的话需要编写大量的测试文件代码才能进行仿真,所以我们直接采取Signal Tap进行在线调试的方式进行波形抓取。

通过在线抓取,经过调试之后,我们可以直接看到温度的值,通过下板验证可以看到数码管显示的值和抓取过程的值是一样的。在数码管中因为我们要显示一个符号位,所以值保留3位小数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2055760.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于vue框架的班级网站的设计与实现vg66m(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;班级,学生,班级活动,班级相册,班级开支,活动记录 开题报告内容 基于Vue框架的班级网站设计与实现 开题报告 一、引言 随着互联网技术的飞速发展&#xff0c;网络已经成为人们日常生活中不可或缺的一部分。在教育领域&#xff0c;班级…

大白话解析:深入浅出大模型RAG模块全解析

文章目录 什么是 RAG&#xff1f; 技术交流&资料通俗易懂讲解大模型系列 RAG模块化 什么是模块化RAG&#xff1f; 索引模块 块优化 滑动窗口从小到大元数据附加 结构化组织 层次化索引知识图谱文档组织 预检索模块 查询扩展 多查询子查询CoVe 查询转换 重写HyDE 查询路由…

TON链上游戏项目开发基本要求及模式创建与海外宣发策略

TON&#xff08;The Open Network&#xff09;是由Telegram开发的区块链平台&#xff0c;以其高速、低延迟、和高扩展性吸引了大量开发者和项目方。TON链上游戏项目作为一个新兴领域&#xff0c;结合了区块链技术和游戏产业&#xff0c;为用户提供了全新的游戏体验和经济激励。…

精益生产咨询:为企业量身定制的高效能蜕变计划!——张驰咨询

在当今这个快速变化、竞争激烈的市场环境中&#xff0c;企业如何保持持续的竞争优势&#xff0c;提高生产效率&#xff0c;降低成本&#xff0c;同时又能快速响应市场需求&#xff0c;成为了每一个企业家必须面对的重大课题。精益生产&#xff08;Lean Production&#xff09;作…

第5节:Elasticsearch核心概念

我的后端学习笔记大纲 我的ElasticSearch学习大纲 1.Lucene和Elasticsearch的关系: 1.Lucene&#xff1a;最先进、功能最强大的搜索库&#xff0c;直接基于lucene开发&#xff0c;非常复杂&#xff0c;api复杂2.Elasticsearch&#xff1a;基于lucene&#xff0c;封装了许多luc…

跳槽?面试软件测试需要掌握的知识你Get了吗

想从事软件测试相关的工作&#xff0c;立志成为一名优秀的软件测试工程师。 一名优秀的软件测试工程师&#xff0c;需要扎实的专业基础&#xff0c;包括测试相关技术、编程技能、数据库知识、计算机网络、以及操作系统等等。对于没有测试经验的应届生求职者来说&#xff0c;面…

SpringBoot项目部署时application.yml文件的加载优先级和启动脚本

文章目录 application.yml文件的加载优先级(由高到低)第一级命令行参数第二级Jar包同级目录 /config第三级Jar包同级目录第四级classpath 下的/config第五级classpath 根路径/总结&#xff1a; logback.xml 文件加载顺序当application.yml 和 bootstrap.yml 同时存在时java jar…

淘宝天猫详情接口API:实现轻松购物,探索最具性价比的商品

随着电子商务的蓬勃发展&#xff0c;网络购物已经成为现代人日常生活中的重要部分。在这个浩瀚的电商海洋中&#xff0c;淘宝和天猫无疑是最为耀眼的两大平台。然而&#xff0c;如何在众多的商品中挑选出性价比最高的产品&#xff1f;淘宝天猫详情接口API为您提供了解决方案。 …

基于vue框架的班级管理系统3pdep(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;学生,班级事务,班级,成绩信息,请假,销假,班级信息,教师 开题报告内容 基于Vue框架的班级管理系统 开题报告 一、引言 随着教育信息化进程的加快&#xff0c;学校管理工作逐渐从传统的纸质化、人工化向数字化、智能化转变。班级作为学…

Python与自动化测试:提高软件质量和稳定性

在软件开发过程中&#xff0c;自动化测试是提高软件质量和稳定性的重要手段之一。Python作为一种简洁而强大的编程语言&#xff0c;为自动化测试提供了丰富的工具和库。本文将介绍几个常见的自动化测试案例&#xff0c;并提供详细的Python代码示例&#xff0c;帮助您更好地理解…

前端面试——js作用域

说一说JS的作用域吧 作用域的分类 作用域分为&#xff1a;全局作用域&#xff0c;函数作用域&#xff0c;块级作用域 作用域的特性 全局作用域&#xff1a; 能够让变量和函数在全局位置访问&#xff0c;其挂载在浏览器的window对象下面 其中var定义的变量和function函数存…

怀旧风吹到体育圈,刘翔、郭晶晶等再翻红?明星与体育冠军代言的区别!

今年奥运&#xff0c;怀旧风吹到了体育圈&#xff0c;曾经的奥运冠军如刘翔、郭晶晶等再度成为公众焦点。这段时间&#xff0c;刘翔频频出现在伊利、霸王茶姬等品牌的广告中&#xff0c;还和法国球星姆巴佩合作拍摄了小红书广告。同样备受品牌关注的还有郭晶晶&#xff0c;巴黎…

【Python实现全屏播放视频】

效果如下&#xff1a; 虽然视频比较抽象&#xff0c;但是确实是用python(cv2)实现的 代码&#xff1a; import cv2 from playsound import playsound from threading import Threaddef func1():cap cv2.VideoCapture("mp4/out.mp4") #替换为视频路径ret, frame ca…

记一次长事务方法带来的坑

文章目录 1. 沟通需求2.分析需求3. 波折起4.初版完成5.锁等待超时6.消费者超时7.总结 1. 沟通需求 产品找到我说&#xff0c;咱要将一波数据给更新了&#xff0c;因为涉及业务&#xff0c;就不说具体的内容了&#xff0c;需要支持分页滚动&#xff0c;校对数据后进行推送&…

无人机系统的关键技术

一、飞控系统&#xff1a;是无人机完成整个飞行过程的关键&#xff0c;决定了无人机的飞行性能和稳定性。 二、导航系统&#xff1a;提供无人机所需的位置、速度和飞行姿态等信息&#xff0c;引导无人机按照指定航线飞行。 三、动力系统&#xff1a;提供飞行动力&#xff0c;…

报表工具是开源还是商用的好?如何选择适合自己的报表工具?

在当今数字化转型的浪潮中&#xff0c;制作既精确又直观的报表已成为个人高效工作与企业精准沟通的核心工具。然而&#xff0c;面对市场上纷繁复杂的报表工具选项&#xff0c;选择最适合自身或企业需求的那一款&#xff0c;宛如漫步于迷雾笼罩的森林&#xff0c;挑战重重&#…

React 学习——useMemo

useMemo使用场景&#xff1a;消耗非常大的计算&#xff0c;例如递归 import { useMemo, useState } from react; // 缓存&#xff1a;消耗非常大的计算&#xff0c;例如递归 function fib(n){console.log(fib);if(n < 3)return 1;return fib(n-2) fib(n-1); }const App (…

Python开发工具PyCharm v2024.2全新发布——新增Databricks集成

JetBrains PyCharm是一种Python IDE&#xff0c;其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外&#xff0c;该IDE提供了一些高级功能&#xff0c;以用于Django框架下的专业Web开发。 立即获取PyCharm v2024.2正式版(Q技术交流&#xff1a;786598704&…

Spark2.x 入门:DStream 转换操作

DStream转换操作包括无状态转换和有状态转换。 无状态转换&#xff1a;每个批次的处理不依赖于之前批次的数据。 有状态转换&#xff1a;当前批次的处理需要使用之前批次的数据或者中间结果。有状态转换包括基于滑动窗口的转换和追踪状态变化的转换(updateStateByKey)。 DStre…

ThreeJs学习笔记--GUI(可视化三维改变场景)

引入gui import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";//具体的看自己本地threejs目录创建gui&#xff08;实例化gui&#xff09; // 实例化一个gui对象 const gui new GUI(); //改变/设置gui操作界面style属性 gui.domElement.style.ri…