异步FIFO设计
1 FIFO简介
FIFO的本质是RAM
,具有先进先出的特性。
FIFO的基本使用原则:空时不能读,满时不能写
FIFO的两个重要参数:宽度和深度
FIFO的两种类型:
- 同步FIFO:读写时钟相同,通常用来做数据缓存
- 异步FIFO:读写时钟不同,通常用来做跨时钟域处理
2 异步FIFO设计要点
2.1 空满信号产生的原理
读空信号:
- 复位的时候(读指针和写指针相等),读空信号有效
- 读指针赶上写指针的时候,读空信号有效
写满信号:
- 写指针赶上读指针的时候
2.2 空满指针跨时钟域处理,为什么要使用Gray信号进行同步
空满信号是通过读写指针的比较来产生,但是读指针属于读时钟域,写指针属于写时钟域,读写指针的比较有一个跨时钟域的问题,因此需要对读写指针进行信号的同步:
- 将写指针同步到读时钟域,然后读指针再和同步后的写指针比较,产生读空信号
- 将读指针同步到写时钟域,然后写指针再和同步后的读指针比较,产生写满信号
使用格雷码Gray
表示的读写指针用两级寄存器同步:
同步过程的亚稳态问题是无法解决的,需要保证即使出现亚稳态也不影响设计的功能
- 如果使用二进制编码表示的读写指针进行同步,当出现亚稳态的时候,将会影响设计的功能。
例如现在将写指针同步到读时钟域,去判断读空信号。写指针0111–>1000,同时有4bit数据发生跳变,在亚稳态的影响下,同步后的写指针的数值可能是0000-1111之间的任何一个数值。本来应该判空的,但是现在没有判空,将会读取错误的数据,使得设计出现问题。 - 如果使用格雷码表示的读写指针进行同步,即使出现亚稳态,也不会影响设计的功能。
格雷码的特点是,相邻的编码之间每次只有1bit数据发生变化。那么这1bit数据如果发生亚稳态会影响设计的功能吗?答案是不会。例如现在还是将写指针同步到读时钟域,去判断读空信号。假设格雷码写指针从0000->0001,写指针同步出错,出错的结果只能是0000->0000,即写指针不变。这种结果最多就是让空信号标志在FIFO不是真正空的时候产生,而不会产生空读的情形。只会影响FIFO的效率,而不会影响到FIFO的功能。
所以Gray码保证的是同步后的读写指针即使在出错的情形下依然能够保证FIFO功能的正确性
2.3 设计的时候,读写指针的同步至少需要消耗两个时钟周期,肯定会使得空满信号的判断有延迟,会不会导致设计出错??
假设现在将写指针同步到读时钟域再和读指针比较进行FIFO空状态判断,因为在同步写指针时需要时间,而在这个同步的时间内有可能还会写入新的数据,因此同步后的写指针一定是小于或者等于当前实际的写指针,所以此时判断FIFO为空不一定是真空,这样更加保守,一共不会出现空读的情况,虽然会影响FIFO的性能,但是并不会出错。
同理将读指针同步到写时钟域再和写指针比较进行FIFO满状态判断,同步后的读指针一定是小于或者等于当前的读指针,所以此时判断FIFO为满不一定是真满,这样更保守,肯定不会出错。
总结来说异步逻辑转到同步逻辑不可避免需要额外的时钟开销,这会导致满空趋于保守,会稍微有性能损失,但是不会出错
2.4 读写时钟不同频,在同步的过程中,可能会有指针遗漏,是否会影响功能?
异步FIFO两端的时钟不是同频的,或者读快写慢,或者读慢写快,慢的时钟域同步到快的时钟域不会出现漏掉指针的情况,但是将指针从快的时钟域同步到慢的时钟域时可能会有指针遗漏。
举例:假设读慢写快
进行满标志判断的时候,需要将读指针同步到写时钟域,因为写时钟快,不会发生读指针同步遗漏的情况,但是由于同步需要消耗至少两个时钟周期,导致读指针同步延迟,读时钟域rd_ptr=3,但是写时钟域的sync_rd_ptr=2,这样可能会导致满标志信号提前产生,满并非真满,但是不影响FIFO功能。
进行空标志判断的时候,需要将写指针同步到读时钟域,因为读时钟慢,会发生写指针同步遗漏的情况,不用关心漏掉哪几个,而是担心漏掉的指针是否会对设计产生影响,比如写指针从0写到10,期间读时钟域只同步捕捉到了3、5、8这三个写指针而漏掉了其他指针。当同步到8这个写指针时,真实的写指针可能已经写到10 ,相当于在读时钟域还没来得及觉察的情况下,写时钟域可能偷偷写了数据到FIFO去,这样在判断它是不是空的时候会出现不是真正空的情况,漏掉的指针不会对FIFO的逻辑操作产生影响(即不会影响,FIFO在满的时候写数据,空的时候读数据,造成的功能错误),只会影响FIFO的工作效率。
总而言之,实际的读/写指针大于同步之后的读/写指针的数值,这种情况不会影响FIFO的功能,只会影响FIFO的效率。(2.3和2.4)均是这种情况
2.5 二进制转Gray码
原理
:
代码
代码编写思路
大概就是格雷码最高位与二进制码一致,其余各位为二进制码对应位与其相邻的高位异或,如格雷码的第二位为二进制的第二位与二进制码的第三位异或。因此实现代码则为二进制码本身与逻辑右移一位后的二进制码异或即可得。
2.6 Gray码转二进制
原理
代码
代码编写思路
二进制码的最高位与格雷码最高位保持一致,其余通过自生移位与异或得到,如b[2]为格雷码逻辑右移两位(逻辑右移,最高位补0)再自身四位异或,0与任何数异或均为其本身。
2.7 读空的条件是写指针等于读指针,写满的条件也是写指针等于读指针,到底如何区分呢?
二进制码判断空满
:指针的位宽多定义一位
假设要设计深度为 8 的异步FIFO,此时定义读写指针只需要 3 位(2^3=8)就够用了,
但是我们在设计时将指针的位宽设计成 4 位,最高位的作用就是区分是读空还是写满。
具体判断规则如下:
- 当最高位相同,其余位相同认为是读空
- 当最高位不同,其余位相同认为是写满
格雷码判断空满
:指针的位宽多定义一位
在设计中判断是读指针是否等于写指针的时候,用的是读写指针的格雷码形式
具体判断规则如下:
-
当最高位和次高位相同,其余位相同认为是读空
-
当最高位和次高位不同,其余位相同认为是写满
因为格雷码是一种镜像码, 例如读指针指向 8,写指针指向 7 ,我们可以知道此时此刻并不是读空状态也不是写满状态;
(7对应的格雷码0100;8对应得格雷码1100) 但是如果按照二进制码得判断规则,最高位不同,其余位相同,就会误判出现写满信号;因此格雷码判断空满的条件和二进制判断空满的规则不相同。
3 RTL
一个典型的FIFO模块结构
如下所示:
下面是参考上图进行的实现(略有不同):
module async_fifo#(parameter DEPTH = 16,parameter WIDTH = 8
)(input wr_clk ,input wr_rstn ,input wr_en ,input [WIDTH-1:0] wr_data ,input rd_clk ,input rd_rstn ,input rd_en ,output reg [WIDTH-1:0] rd_data ,output rempty ,output wfull
);//------------------------------------------------------------------------------------
// internal vars
//------------------------------------------------------------------------------------reg [WIDTH-1:0] fifo_ram [DEPTH-1:0];reg [$clog2(DEPTH):0] wr_ptr;
reg [$clog2(DEPTH):0] rd_ptr;wire [$clog2(DEPTH):0] wr_ptr_g;
wire [$clog2(DEPTH):0] rd_ptr_g;
reg [$clog2(DEPTH):0] wr_ptr_g_d1;
reg [$clog2(DEPTH):0] rd_ptr_g_d1;
reg [$clog2(DEPTH):0] wr_ptr_g_d2;
reg [$clog2(DEPTH):0] rd_ptr_g_d2;wire [$clog2(DEPTH)-1:0] wr_addr;
wire [$clog2(DEPTH)-1:0] rd_addr;//------------------------------------------------------------------------------------
// wr_ptr && rd_ptr
//------------------------------------------------------------------------------------always@(posedge wr_clk or negedge wr_rstn)beginif(!wr_rstn)wr_ptr <= 0;else if(wr_en && !wfull)wr_ptr <= wr_ptr + 1'b1;
endalways@(posedge rd_clk or negedge rd_rstn)beginif(!rd_rstn)rd_ptr <= 0;else if(rd_en && !rempty)rd_ptr <= rd_ptr + 1'b1;
end//------------------------------------------------------------------------------------
// wfull && rempty
//------------------------------------------------------------------------------------
assign wr_ptr_g = (wr_ptr >> 1) ^ wr_ptr;
assign rd_ptr_g = (rd_ptr >> 1) ^ rd_ptr;always@(posedge rd_clk or negedge rd_rstn )begin//write_ptr_g sync to read domainif(!rd_rstn){wr_ptr_g_d2,wr_ptr_g_d1} <= 0;else {wr_ptr_g_d2,wr_ptr_g_d1} <= {wr_ptr_g_d1,wr_ptr_g};
endalways@(posedge wr_clk or negedge wr_rstn)begin//read_ptr_g sync to write domainif(!wr_rstn){rd_ptr_g_d2,rd_ptr_g_d1} <= 0;else {rd_ptr_g_d2,rd_ptr_g_d1} <= {rd_ptr_g_d1,rd_ptr_g};
endassign rempty = (rd_ptr_g == wr_ptr_g_d2);
assign wfull = wr_ptr_g == {~rd_ptr_g_d2[$clog2(DEPTH):$clog2(DEPTH)-1],rd_ptr_g_d2[$clog2(DEPTH)-2:0]};//------------------------------------------------------------------------------------
// write && read
//------------------------------------------------------------------------------------assign wr_addr = wr_ptr[$clog2(DEPTH)-1:0];
assign rd_addr = rd_ptr[$clog2(DEPTH)-1:0];always@(posedge wr_clk)if(wr_en && !wfull)fifo_ram[wr_addr] <= wr_data;always@(posedge rd_clk)if(rd_en && !rempty)rd_data <= fifo_ram[rd_addr];endmodule
4 Testbench
pattern只写不读、pattern只读不写、pattern写比读快
`timescale 1ns / 1psmodule tb_async_fifo();//---------------------------------------------------parameter WIDTH = 3;
parameter DEPTH = 32;reg wr_clk ;
reg wr_rstn ;
reg wr_en ;
reg [WIDTH-1:0] wr_data ;
reg rd_clk ;
reg rd_rstn ;
reg rd_en ;
wire [WIDTH-1:0] rd_data ;
wire empty ;
wire full ;//---------------------------------------------------initial beginwr_clk = 0;forever #10 wr_clk = ~wr_clk;//50MHz
end
initial beginrd_clk = 0;forever #12.5 rd_clk = ~rd_clk;//40MHz
endinitial beginrd_rstn = 0;wr_rstn = 0;#103 ;rd_rstn = 1;wr_rstn = 1;
end//pattern1
initial beginwr_en = 0;wr_data = 0;#203;wr_en = 1;repeat(32) @(posedge wr_clk)begin#1;wr_data = wr_data + 1;end#1;wr_en = 0;
end//pattern2
initial beginrd_en = 0;#3000;rd_en = 1;repeat(32) @(posedge rd_clk)beginend#1;rd_en = 0;
end//pattern3
initial beginrd_en = 0;wr_en = 0;#6000;wr_en = 1;rd_en = 1;repeat(300) @(posedge wr_clk)begin#1;wr_data = wr_data + 1;end#1;wr_en = 0;repeat(32) @(posedge rd_clk)beginend#1;rd_en = 0;
end
//---------------------------------------------------async_fifo#(.DEPTH(DEPTH),.WIDTH(WIDTH)
) u_async_fifo(.wr_clk (wr_clk ),.wr_rstn (wr_rstn ),.wr_en (wr_en ),.wr_data (wr_data ),.rd_clk (rd_clk ),.rd_rstn (rd_rstn ),.rd_en (rd_en ),.rd_data (rd_data ),.empty (empty ),.full (full )
);endmodule
pattern读比写快
`timescale 1ns / 1psmodule tb_async_fifo_w_slow();//---------------------------------------------------parameter WIDTH = 3;
parameter DEPTH = 32;reg wr_clk ;
reg wr_rstn ;
reg wr_en ;
reg [WIDTH-1:0] wr_data ;
reg rd_clk ;
reg rd_rstn ;
reg rd_en ;
wire [WIDTH-1:0] rd_data ;
wire empty ;
wire full ;//---------------------------------------------------initial beginwr_clk = 0;forever #10 wr_clk = ~wr_clk;//50MHz
endinitial beginrd_clk = 0;forever #8 rd_clk = ~rd_clk;//62.5MHz
endinitial beginrd_rstn = 0;wr_rstn = 0;#103 ;rd_rstn = 1;wr_rstn = 1;
end//pattern1
initial beginwr_en = 0;wr_data = 0;#203;wr_en = 1;repeat(32) @(posedge wr_clk)begin#1;wr_data = wr_data + 1;end#1;wr_en = 0;
end//pattern2
initial beginrd_en = 0;#3000;rd_en = 1;repeat(32) @(posedge rd_clk)beginend#1;rd_en = 0;
end//pattern3
initial beginrd_en = 0;wr_en = 0;#6000;wr_en = 1;rd_en = 1;repeat(300) @(posedge wr_clk)begin#1;wr_data = wr_data + 1;end#1;wr_en = 0;repeat(32) @(posedge rd_clk)beginend#1;rd_en = 0;
end
//---------------------------------------------------async_fifo#(.DEPTH(DEPTH),.WIDTH(WIDTH)
) u_async_fifo(.wr_clk (wr_clk ),.wr_rstn (wr_rstn ),.wr_en (wr_en ),.wr_data (wr_data ),.rd_clk (rd_clk ),.rd_rstn (rd_rstn ),.rd_en (rd_en ),.rd_data (rd_data ),.empty (empty ),.full (full )
);endmodule
pattern读写一样快
`timescale 1ns / 1psmodule tb_async_fifo_w_equal();//---------------------------------------------------parameter WIDTH = 3;
parameter DEPTH = 32;reg wr_clk ;
reg wr_rstn ;
reg wr_en ;
reg [WIDTH-1:0] wr_data ;
reg rd_clk ;
reg rd_rstn ;
reg rd_en ;
wire [WIDTH-1:0] rd_data ;
wire empty ;
wire full ;//---------------------------------------------------initial beginwr_clk = 0;forever #10 wr_clk = ~wr_clk;//50MHz
endinitial beginrd_clk = 0;#8;forever #10 rd_clk = ~rd_clk;//50MHz
endinitial beginrd_rstn = 0;wr_rstn = 0;#103 ;rd_rstn = 1;wr_rstn = 1;
end//pattern1
initial beginwr_en = 0;wr_data = 0;#203;wr_en = 1;repeat(32) @(posedge wr_clk)begin#1;wr_data = wr_data + 1;end#1;wr_en = 0;
end//pattern2
initial beginrd_en = 0;#3000;rd_en = 1;repeat(32) @(posedge rd_clk)beginend#1;rd_en = 0;
end//pattern3
initial beginrd_en = 0;wr_en = 0;#6000;wr_en = 1;rd_en = 1;repeat(300) @(posedge wr_clk)begin#1;wr_data = wr_data + 1;end#1;wr_en = 0;repeat(32) @(posedge rd_clk)beginend#1;rd_en = 0;
end
//---------------------------------------------------async_fifo#(.DEPTH(DEPTH),.WIDTH(WIDTH)
) u_async_fifo(.wr_clk (wr_clk ),.wr_rstn (wr_rstn ),.wr_en (wr_en ),.wr_data (wr_data ),.rd_clk (rd_clk ),.rd_rstn (rd_rstn ),.rd_en (rd_en ),.rd_data (rd_data ),.empty (empty ),.full (full )
);endmodule
参考博客:
https://zhuanlan.zhihu.com/p/551351794
https://blog.csdn.net/ZZ2588/article/details/122347438
https://blog.csdn.net/spx1164376416/article/details/121086907
https://zhuanlan.zhihu.com/p/344170711
https://wuzhikai.blog.csdn.net/article/details/121152844
https://blog.csdn.net/JustinLee2015/article/details/106527301/
https://blog.csdn.net/wuzhikaidetb/article/details/123570799
https://blog.csdn.net/weixin_44348260/article/details/119612998
相关文章:

异步FIFO设计
1 FIFO简介 FIFO的本质是RAM,具有先进先出的特性。 FIFO的基本使用原则:空时不能读,满时不能写 FIFO的两个重要参数:宽度和深度 FIFO的两种类型: 同步FIFO:读写时钟相同,通常用来做数据缓存…...
学习python和anaconda的经验
PYTHON 1 常用命令 1.1 1.1 注释 Python注释多行的方法有以下三种:使用ctrl+/实现多行注释、在每一行的开头使用shift+#键、输入’‘’ ‘’或者"“” “”",将要注释的代码插在中间 1.2 def init( ):函数 区分两个函数: 1.def init(self): 这种形式在__init_…...

【Linux】多线程【上】
文章目录 前言1、Linux线程概念1-1、什么是线程?1-1-1、如何看待页表1-1-2、回顾进程地址空间1-1-3、页表怎么进行虚拟地址到物理地址的映射的?1-1-4、Linux中线程的概念(重点)1-1-5、原生线程库1-1-6、代码测试1-1-7、知识点&…...

生成式人工智能在高等教育 IT 中的作用
作者:Jared Pane 通过将你大学的数据与公共 LLMs 和 Elasticsearch 安全集成来找到你需要的答案。 根据 2023 年 4 月 EDUCAUSE 的一项调查,83% 的受访者表示,生成式人工智能将在未来三到五年内深刻改变高等教育。 学术界很快就询问和想象生…...

黑龙江省DCMM认证、CSMM认证、CMMM认证、知识产权等政策奖励
2023年8月28日 为深入落实党的二十大精神,认真落实省第十三次党代会关于创新龙江建设的部署要求,全面贯彻新发展理念,融入和服务构建新发展格局,实施创新驱动发展战略,着力建设创新龙江,不断塑造振兴发展新…...

腾讯云2023年云服务器优惠活动价格表
腾讯云经常推出各种云产品优惠活动,为了帮助大家更好地了解腾讯云服务器的价格和优惠政策,下面给大家分享腾讯云最新云服务器优惠活动价格表,助力大家轻松上云! 一、轻量应用服务器优惠活动价格表 1、轻量应用服务器:…...

Sleuth--链路追踪
1 链路追踪介绍 在大型系统的微服务化构建中,一个系统被拆分成了许多模块。这些模块负责不同的功能,组合成系统,最终可以提供丰富的功能。在这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上&…...

MyBatis初级
文章目录 一、mybatis1、概念2、JDBC缺点2.1、之前jdbc操作2.2 、原始jdbc操作的分析 3、mybatis的使用3.1、导入maven依赖3.2、新建表3.3、实体类3.4、编写mybatis的配置文件3.5、编写接口 和 映射文件3.6、编写测试类3.7、注意事项 4、代理方式开发5、mybatis和spring整合5.1…...
Spring 学习(二)AOP
一、什么是AOP Aspect Oriented Programming,即面向切面编程。对一个大型项目的代码而言,整个系统要求关注安全检查、日志、事务等功能,这些功能实际上“横跨”多个业务方法。在一般的OOP编程里,需要在每一个业务方法内添加相关非…...

笔记1.1 计算机网络基本概念
计算机网络是通信技术与计算机技术紧密结合的产物 通信系统模型: 计算机网络是一种通信网络 计算机网络是互连的、自洽的计算机集合。 互连:互联互通 自洽:无主从关系 通过交换网络互连主机 Internet:数以百万计的互连的计算设…...

液压切管机配套用液压泵站比例阀放大器
液压切管机配套用液压泵站是液压系统的动力源,可按机械设备工况需要提供一定压力、流量和清洁度的工作介质。它由泵组、油箱组件、控温组件、滤油器组件及蓄能器组件等组合而成,液压泵站主要服务于大型管道工程。...
C++ Primer Plus 第七章笔记
目录 函数基本知识 没有返回值的函数:void函数 有返回值的函数: 函数原型 1.为什么需要函数原型? 2.函数原型的语法 3.函数原型的功能 按值传递函数参数 形参和实参 局部变量 参数问题 使用const指针参数 调用自身的函数…...

常用数据库的 API - 开篇
API API 这个词在大多数人看来可能和 CNS 差不多,前者天天听说就是用不上,后者天天读就是发不了。 不过,通过今天的一个简短介绍,今后 API 这个东西你就用上了,因为在文章最后我将会展示一个最最基础且高频的 API 使…...

C++之生成详细汇编代码(二百一十六)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...

AIGC|当一个程序员学会用AI来辅助编程实践
一、辅助编程 作为主要以 JAVA 语言为核心的后端开发者,其实,早些时间我也用过比如 Codota、Tabnine、Github 的 Copilot、阿里的 AI Coding Assistant 等 IDEA 插件,但是我并没有觉得很惊奇,感觉就是生成一些代码片段罢了&#x…...

9.14号作业
仿照vector手动实现自己的myVector,最主要实现二倍扩容功能 有些功能,不会 #include <iostream>using namespace std; //创建vector类 class Vector { private:int *data;int size;int capacity; public://无参构造Vector(){}//拷贝构造Vector(c…...
【面试题】C/C++ 中指针和引用的区别
指针是一个独立的对象,它可以指向不同的变量或对象,可以重新赋值给其他变量。而引用是已存在的变量的别名,它必须在定义时初始化,并且不能重新绑定到另一个变量。指针可以是空指针(nullptr),它不…...

spring boot 整合多数据源
多数据源产生的场景 一般情况下,不会有多数据源这样的场景出现,但老项目或者特殊需求的项目,可能会有这样的场景 同一个应用需要访问两个数据库不用数据库中间件的读写分离 注入数据源选择的时机 声明两个数据源实例,在getConnect…...

数据集成:数据挖掘的准备工作之一
⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据…...

xml配置文件密码特殊字符处理
错误姿势: 正确姿势:采取转义符的方式 常用转义符:...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...