FPGA - 单总线协议(one-wire)
1,简介
单总线(one-wire)是美国 DALLAS 公司推出的外围串行扩展总线技术,与 SPI、I2C 等串行数据通信方式不同,它采用单根信号线,既传输时钟又传输数据,而且数据传输是双向的。它具有节省 I/O口线资源、结构简单、成本低廉、便于总线扩展和维护等诸多优点。
单总线英文名 1-Wire,传输速率一般是 15.3Kbit/s,最大可达 142Kbit/s,通常采用 100Kbit/s 以下的速率传输数据。
2,硬件结构
单总线(one-wire)只有一根数据线,系统中的数据交换、控制都由这根线完成。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线,其内部等效电路如图所示。

单总线通常要求外接一个约为4.7kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。主机和从机之间的通信可通过3个步骤完成,分别为初始化1-wire器件、识别1-wire器件和交换数据。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问1-wire器件都必须严格遵循单总线命令序列,即初始化、ROM、命令功能命令。如果出现序列混乱,1-wire器件将不响应主机。
3,通信时序分析
由于DS18B20温度传感器在使用中与主机通讯是单总线(one-wire)通信,所以在这使用FPGA驱动DS18B20温度传感器测量温度来学习单总线(one-wire)。
3.1 FPGA 如何驱动 gxs18b20 并测量温度?
首先 FPGA 向温度传感器写入一些数据,数据按照一个字节一个字节发送,温度传感器接收到这些字节数据,会自动采集外界温度数据并保存在内部寄存器里面。然后 FPGA 向传感器写入读温 度数据指令,便可读取传感器里面的温度数据。
3.2 FPGA 与传感器通信过程
通过单总线访问 GX18B20 的执行序列如下:
步骤 1:初始化。
步骤 2:ROM 操作指令
步骤 3:GX18B20 功能指令。
每一次 GX18B20 的操作都必须满足以上步骤,若是缺少步骤或是顺序混乱,器件将不会有返回值。
3.2.1 初始化
通过单总线的所有执行操作都从一个初始化程序序列开始。初始化序列包含一个由总线控制器 发出的复位脉冲和其后由从机发出的存在脉冲。存在脉冲让总线控制器知道 Gx18B20 在总线上且 已经准备好操作。
所有和 Gx18B20 间的通信都以初始化序列开始,初始化序列如图所示。一个复位脉冲跟着一个存在脉冲表明Gx18B20 已经准备好发送和接收数据。 在初始化序列期间,总线控制器拉低总线并保持 480us 以发出(TX)一个复位脉冲信号,然后释放总线,进入接收状态(RX)。当总线被释放后,5kΩ的上拉电阻将总线拉到高电平。当 GX18B20 检测到 IO 引脚上的上升沿后,等待 15-60us,然后发出一个由 60-240us 低电平信号构成的存在脉冲。

Bus master puling low : 主机拉低总线,主机向从机写 0
Gx18b20 pulling low : Gxs18b20 拉低总线,从机向主机发 0
Resistor pullup:从机的电阻上拉,期间从机可以接收主机写入的数据。
one_wire 端口是一个双向的端口,也即该端口可以发送数据,也可以接收数据。 主机有一个双向端口与从机连接,从机对应的端口的也是双向端口。 双向端口虽然可以发送和接收数据,但是发送数据时候,不能接收数据;也就是发送和接收数据必须分开进行。
各种手册里面经常出现“主机释放总线”,“从机释放总线”,这两个概念不是一个意思。同理“主机拉低总线”和“从机拉低总线”也不是一个意思。
主机释放总线:主机释放总线期间,主机可以接收来自从机的数据。注意, 如果主机要接收从机传来的数据。主机必须释放总线。
主机拉低总线:主机向从机写入逻辑 0
从机释放总线:从机释放总线、从机电阻上拉差不多是一个意思,代表着此时从机可以接收数据。
3.2.2 ROM 操作指令
在这里我们选择跳过ROM操作指令
SKIP ROM [CCh]
这条命令允许总线控制器不用提供 64 位 ROM 编码就使用功能指令。例如,总线控制器可以先发出一条忽略 ROM 指令,然后发出温度转换指令[44h],从而完成温度转换操作。
3.2.3 GXS18B20 功能指令
GXS18B20 功能指令允许总线控制器读写 GX18B20 的寄存器,发起温度转换和识别电源模式。
下表是GXS18B20的功能指令表

其中我们只使用温度转换指令(CONVERT T [44h])和读取温度指令(READ SCRATCHPAD [BEh])
CONVERT T [44h]
这条命令时用于启动一次温度转换。温度转换指令被执行后,产生的温度转换结果数据以 2 个字节的形式被存储在温度寄存器中,而后 GX18B20 保持低功耗的等待状态。如果在寄生供电模 式下发出该指令,在温度转换期间(tCONV),必须在 10us(最多)内给单总线一个强上拉,见 GX18B20 供电节。如果 GX18B20 以外部电源供电,总线控制器在发出该命令后跟着发出读时序, GX18B20 如处于转换中,则总线返回 0,若温度转换完成,则返回 1。在寄生供电模式下,总线 被强上拉拉高前这样的通信方式不会被使用。
READ SCRATCHPAD [BEh]
这条命令时主机读取寄存器命令。读取将从字节 0 的最低有效位开始,一直进行下去,直到 第 9 字节(字节 8,CRC)读完,如果不想读完所有字节,控制器可以在任何时候发出复位命令 来中止读取。
3.3 读写时序
读/写时序 GX18B20 的数据读写是通过时序处理来进行信息交换的,每个时序传输 1 位数据。
写时序
GX18B20 有两种写时序:写 1 时序和写 0 时序。总线控制器通过写 1 时序来写逻辑 1;通过 写 0 时序来写逻辑 0。写时序必须最少持续 60us,包括两个写周期之间至少 1us 的恢复时间。当 总线控制器把数据线从逻辑高电平拉低到低电平的时候,写时序开始。 总线控制器要写产生一个写时序,必须把数据线拉到低电平然后释放,且需在 15us 内释放总 线。当总线被释放后,上拉电阻将总线拉高。总线控制器要生成写 0 时序,必须把数据线拉到低 电平且继续保持至少 60us。 总线控制器初始化写时序后,GX18B20 在一个 15us 到 60us 的窗口内对信号线进行采用。如果线上是高电平,就是写 1。反之,如果线上是低电平,就是写 0。

读时序
总线控制器发起读时序时,GX18B20 仅被用来传输数据给控制器。因此,总线控制器在发出 读寄存器指令[BEh]或读电源模式指令[B4h]后必须立刻开始读时序,以便 GX18B20 提供请求的数 据。
所有读时序必须最少 60us,包括两个读周期间至少 1us 的恢复时间。当总线控制把数据线从 高电平拉低到低电平时,读时序开始,数据线必须至少保持 1us,然后总线被释放。 在总线控制器发出读时序后,GX18B20 通过拉高或拉低总线上来传输 1 或 0。当传输 0 结束后, 总线将被释放,通过上拉电阻回到高电平空闲状态。从 GX18B20 输出的数据在读时序的下降沿出 现后 15us 内有效。因此,总线控制器在读时序开始 15us 内释放总线然后采样总线状态,以读取数据线的状态。
图 1 标识 TINIT, TRC, 和 TSAMPLE 之和必须小于 15us。
图 2 指出,系统时间可以通过以下方法达到最大:TINIT 和 TRC 保持时间尽可能短,并且把控制器采样时间放到 15us 周期的最后。


4,FPGA驱动gxs18b20
4.1 编写代码思路
1,根据FPGA 与温度传感器的通信过程分析:
① FPGA对传感器进行初始化操作; ------> 分配一个字节时间 byte = 0
② 向传感器写入 0xcc; ------> 分配一个字节时间 byte = 1
③ 向传感器写入 0x44; ------> 分配一个字节时间 byte = 2
④ 等待一段时间; ------> 分配一个字节时间 byte = 3
⑤ 初始化操作; ------> 分配一个字节时间 byte = 4
⑥ 向传感器写入 0xcc; ------> 分配一个字节时间 byte = 5
⑦ 向传感器写入 0xbe; ------> 分配一个字节时间 byte = 6
⑧ 读取传感器温度,读取两个字节; ------> 分配两个字节时间 byte = 7/8
2,代码编写思路
①,定义一个us的计数器,计数器计数时间为100us;
cnt 100_000/20 = 5000 --> 0-4999
90us时就是计数到4499
10us时就是计数到499
②,定义一个位计数器bit_cnt 在cnt==4999时加1,在bit_cnt == 7 && cnt==4999时清0
③,字节计数器 byte_cnt 在位计数器bit_cnt == 7 && cnt == 4999时加1,在bit_cnt == 7 && cnt == 4999 && byte==8时清0
④,在如何设计连续写1或者写0
定义一个[7:0]wr_data ,其中 bit_cnt是从0计数到7
wr_data在cnt计数到最大值时候,向右移位,通过判断wr_data[0]最低位,判断写0还是写1
4.2 代码编写
根据以上思路分析,编写代码如下:
`timescale 1ns / 1psmodule ds18b20_driver(input clk ,input reset ,input dq ,output reg temp_sign ,output reg [7:0] temp_data);localparam CNT_MAX = 4999 ;localparam SKIP = 8'hCC ;localparam CONVERT = 8'h44 ;localparam READ = 8'hBE ;wire dqout ;reg dqout_en ;reg [12:0] cnt ;reg [2 :0] bit_cnt ;reg [3 :0] byte_cnt ;reg [7 :0] wr_data ;reg [16:0] rd_data ;reg init_err ;//三态门assign dq = dqout_en == 1 ? dqout: 1'bz;assign dqout = 0;//计数器always @(posedge clk ) beginif (reset) begincnt <= 0;endelse if (cnt == CNT_MAX) begincnt <= 0; endelse begincnt <= cnt + 1;endendalways @(posedge clk ) beginif (reset) beginbit_cnt <= 0;endelse if (cnt == CNT_MAX && bit_cnt == 7) beginbit_cnt <= 0; endelse if (cnt == CNT_MAX)beginbit_cnt <= bit_cnt + 1;endendalways @(posedge clk ) beginif (reset) beginbyte_cnt <= 0;endelse if (cnt == CNT_MAX && bit_cnt == 7 && byte_cnt == 8) beginbyte_cnt <= 0; endelse if (cnt == CNT_MAX && bit_cnt == 7)beginbyte_cnt <= byte_cnt + 1;endendalways @(posedge clk ) beginif ((byte_cnt == 0 || byte_cnt == 4) && bit_cnt == 7 && cnt == CNT_MAX) beginwr_data <= SKIP;endelse if(bit_cnt == 7 && byte_cnt == 1 && cnt == CNT_MAX) beginwr_data <= CONVERT;endelse if(bit_cnt == 7 && byte_cnt == 5 && cnt == CNT_MAX) beginwr_data <= READ;endelse if (cnt == CNT_MAX) beginwr_data <= wr_data >> 1;endendalways @(posedge clk) beginif (reset) begindqout_en <= 0;endelse if(byte_cnt == 0 || byte_cnt == 4)begin //初始化dqout_en <= bit_cnt <= 4 ? 1'b1 : 1'b0; end else if(byte_cnt == 3) //等待dqout_en <= 0; else if (byte_cnt == 1 || byte_cnt == 2 || byte_cnt == 5 || byte_cnt == 6) //向传感器写入字节begin dqout_en <= cnt == 0 ? 1'b1 : (((cnt == 499 && wr_data[0]) || (cnt == 4599 && ~wr_data[0])) ? 1'b0 : dqout_en);endelse if(byte_cnt == 7 || byte_cnt == 8)dqout_en <= cnt <= 99 ? 1'b1 : 1'b0; //拉高2US 读取采样end //主机采样always @(posedge clk ) begin if(reset) beginrd_data <= 0;end else if((byte_cnt == 7 || byte_cnt == 8) && cnt == 649 ) //13us采样beginrd_data <= {dq,rd_data[15:1]};endelserd_data <= rd_data;endalways @(posedge clk ) begin if(byte_cnt == 8 && bit_cnt == 7 && cnt == 659 && ~rd_data[15]) begintemp_data <= rd_data[10:4];temp_sign <= rd_data[15] ;endelse if(byte_cnt == 8 && bit_cnt == 7 && cnt == 659 && rd_data[15]) begintemp_data <= ~rd_data[10:4] + 1 ;temp_sign <= rd_data[15] ;endend always @(posedge clk ) beginif((byte_cnt == 0 || byte_cnt == 4) && bit_cnt == 6 && cnt == CNT_MAX) //初始化采?beginif (dq == 0)init_err <= 0;elseinit_err <= 1;end endendmodule
在这里编写了一个顶层模块,其中定义了一个时钟管理单元 (PLL实现)来管理时钟和复位信号,
顶层模块如下:
`timescale 1ns / 1ps
module top(input wire clkin_50m,inout dq );wire reset;wire clk;wire temp_sign;wire [7:0] temp_data;clock_and_reset clock_and_reset (.clkin_50m (clkin_50m), .clkout_50M(clk), .reset (reset));ds18b20_driver ds18b20_driver(.clk (clk),.reset (reset),.dq (dq),.temp_sign (temp_sign),.temp_data (temp_data));endmodule
4.3 测试仿真
由于18b20温度传感器属于从机,所以仿真时较难,采用半仿真。我们定义一个仿真文件slave.v
其中让dq作为输出,使其输出0,然后将此模块例化到测试模块中
`timescale 1ns / 1ps
module slave(output dq);assign dq = 0;endmodule
测试代码如下:
`timescale 1ns / 1psmodule tb_top();reg clkin_50m ;wire dq ;pullup(dq); // pullup原语 模拟上拉电阻 可以让dq空闲状态处于高电平top top (.clkin_50m(clkin_50m), .dq(dq));slave slave (.dq(dq));initial beginclkin_50m = 0;forever #(10) clkin_50m = ~clkin_50m;endendmodule
4.4 仿真波形
仿真波形如下


相关文章:
FPGA - 单总线协议(one-wire)
1,简介 单总线(one-wire)是美国 DALLAS 公司推出的外围串行扩展总线技术,与 SPI、I2C 等串行数据通信方式不同,它采用单根信号线,既传输时钟又传输数据,而且数据传输是双向的。它具有节省 I/O口…...
python的函数与类的定义
目录 1.函数 1.函数的定义 2.输入参数与输出参数的类型 3.输入和输出多个参数 1.普通参数 2.含有任意数量的参数 3.关键字参数 4.普通参数与多个参数的结合 2.类 1.类的定义 2.类的实例化 3.继承 1.函数 1.函数的定义 def 函数名(输入参数): 文档字符串 函数体 …...
Parade Series - WebRTC ( < 300 ms Low Latency ) T.B.D
Parade Series - FFMPEG (Stable X64) C:\Conda\parading-cam>ffmpeg -f dshow -i video"Surface Camera Front" -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -an -rtsp_transport tcp -f rtsp://127.0.0.1:8554/cam0801...
【ARM】MDK在programming algorithm界面添加FLM
【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 解决在programming algorithm界面中无法添加想要的Flash编程算法的问题 2、 问题场景 在对于Debug进行Flash Download进行配置的时候,在programming algorithm界面中有对应的Flash编程算法。可以通过…...
springmvc学习笔记1
springmvc学习笔记part1 总概述图创建步骤创建project并在父工程中导入配置类添加为web工程检查maven配置写handller方法写配置类SpringMVC环境搭建项目部署关键步骤总结 具体设置路径设置注解接收参数(重点param参数接收路径参数接收json参数接收请求头接收和cooki…...
力扣106 从中序与后续遍历序列构造二叉树
文章目录 题目描述解题思路代码 题目描述 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7], …...
数字逻辑-时序逻辑电路一
一、实验目的 (1)熟悉触发器的逻辑功能及特性。 (2)掌握集成D和JK触发器的应用。 (3)掌握时序逻辑电路的分析和设计方法。 二、实验仪器及材料 三、实验内容及步骤 1、用D触发器(74LS74&am…...
web 课程
文章目录 格式图片超链接书签链接表格例子横跨束跨 格式 <br /> <br/> #换行图片 <img> 标签是用于在网页中嵌入图像的 HTML 标签,它有一些属性可以用来控制图像的加载、显示和交互。以下是对 <img> 标签常用属性的详细介绍:…...
工业园区智慧水电设备管控系统
在现代工业园区中,水电设备的管控系统起着至关重要的作用。这些系统不仅仅是简单的机械装置,它们更是一种智慧的结合,为工业生产提供了可靠的保障和高效的管理。让我们一起来探索工业园区智慧水电设备管控系统的奥秘。 我们来看看水电设备的…...
Git之版本回退
文章转载于:https://www.jianshu.com/p/3020740561a8 以前,如果是要去除某一块功能,我都是选择性删除,选择性注释,然后前后逻辑各种查看,各种比较。每一次,改完这些我总感觉心好累啊!…...
「jQuery系列」jQuery 校验表单(Validate)
文章目录 一、校验表单(Validate)1. 基本用法2. 验证规则3. 国际化4. 插件扩展 二、Validate常用方法1. 基本验证2. 自定义验证规则3. 远程验证(通过 AJAX)4. 提交处理(submitHandler)5. 忽略某些元素的验证…...
【Java设计模式】十九、中介者模式
文章目录 1、中介者模式2、案例3、总结 1、中介者模式 如图: 同事类之间关联较多时,整体出现网状结构,耦合度极高。一个对象一变动,好多对象都得改。若变为右边的星形结构,则一个类的变动,只影响自身与中介…...
这个学习Python的神仙网站,后悔没早点发现
Python 作为时下最流行的编程语言,很多初学者都将它作为自学编程的首选。不管是有编程经验的开发者,还是新手小白,在这个 AIGC 时代, Python 都可以带你探索新世界。 入门 Python 绝非难事,但如何让自己坚持学下去是如…...
牛津大学“领域驱动设计”课程
领域驱动设计(“DDD”)是一种专注于系统领域而不是技术的软件设计方法。重点是构建共享的心理模型并以尽可能简单的方式在代码中表示该领域模型。数据库存储、框架等技术细节被认为是设计的次要方面。该模块将重点关注 DDD 和一般设计以及相关主题&#…...
Redisson分布式锁解决方案
官方地址 官网: https://redisson.org github: https://github.com/redisson/redisson 基于setnx实现的分布式锁存在的问题 redisson分布式锁原理 不可重入: 利用hash结构记录线程id和重入次数不可重试: 利用信号量和PubSub功能实现等待、唤醒, 获取锁失败的重试机制超时释放…...
linux命令深入研究——cat
cat命令,“猫”,可以理解为瞄一眼文件内容,其中可以用重定向符号对文件进行一些修改,如增加,删除文件内容,其命令参数如-n,-s,-b可以输出带有行号的行 如果想要快速删除文件内容&…...
代码随想录算法训练营第40天|343. 整数拆分、96.不同的二叉搜索树
343. 整数拆分 题目链接:link 文章讲解:link 视频讲解:link 一、做题感受&第一想法 其实第一反应是回溯……但感觉每层的集合都会很繁琐 二、学习文章后收获 1.动态规划思路 动规五要素分析 dp和i的定义:dp[i]指把i拆分后最…...
二叉树算法
递归序 每个节点都能回到3次! 相当于2执行完然后返回了代码会往下走,来到3节点 小总结: 也就是4节点先来到自己一次,不会执行if,先调用自己左边的那个函数,但是是null,直接返回。 这个函数执行完了,就会回到自己,调用自己右边的那个函数,结果又是空,又返回,回到…...
【2024年5月备考新增】《软考真题分章练习(答案解析) - 4 项目范围管理(高项)》
点击跳转无答案版 1、() includes the processes required to ensure that the project includes all the work required , and only the work required , to complete the project successfully . Managing the project scope is primarily concerned with defining and con…...
Docker拉取镜像存储不足
在使用Docker时,我们经常遇到一个问题,就是拉取镜像时提示存储空间不足。这是因为Docker在拉取镜像时需要将镜像文件下载到本地存储中,而有时本地存储空间不足以容纳完整的镜像文件。 本文将介绍一些解决这个问题的方法,并提供相…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
