one wire(单总线)FPGA代码篇

news2024/11/24 15:08:27

一.引言

        单总线(OneWire)是一种串行通信协议,它允许多个设备通过一个单一的数据线进行通信。这个协议通常用于低速、短距离的数字通信,特别适用于嵌入式系统和传感器网络。

 

二.one wire通信优点缺点

优点:

  1. 单一数据线: 单总线仅需要一根数据线,这极大地简化了硬件连接。设备可以在同一总线上连接,并且通过地址来区分彼此。
  2. 低成本: 单总线协议不需要复杂的硬件,这降低了成本。这使其成为连接多个设备的经济实惠选择。
  3. 数据传输速率: 单总线通常以较低的数据传输速率工作,适用于一些低功耗和简单的应用。
  4. 异步通信: 数据在单总线上传输是异步的,不需要共享时钟信号。这使得它适用于各种设备和微控制器。
  5. 支持供电: 单总线通常支持从总线上获得电源,这对于一些小型设备非常有用。

缺点:

  1. 传输距离有限:由于采用单线传输数据,因此传输距离有限,通常在几米以内。
  2. 抗干扰能力较弱:由于采用单线传输数据,因此容易受到外界干扰的影响,导致数据传输错误。
  3. 扩展性较差:由于采用单线传输数据,因此无法实现多从机的通信,扩展性较差。

三.one wire工作原理

  1. 物理层连接: 单总线通信通常包括一个总线上的主设备和一个或多个从设备。这些设备通过一根物理数据线连接。总线上还可能有一个电源线用于为从设备提供电源。
  2. 数据帧: 通信基于数据帧的传输。一个数据帧通常包括起始位(Start Bit)、数据位、可选的校验位,以及停止位(Stop Bit)。
  3. 数据传输: 数据传输是异步的,没有共享时钟信号。数据通过时间间隔来表示逻辑 0 和逻辑 1。逻辑 0 和逻辑 1通常是通过时间长短来区分的,即短脉冲表示逻辑 0,长脉冲表示逻辑 1。
  4. 设备地址: 每个从设备都有一个唯一的地址,主设备通过发送从设备的地址来选择与之通信的特定设备。
  5. 总线控制: 主设备负责控制总线上的通信。它生成起始条件(Start Condition)和停止条件(Stop Condition)来开始和结束通信。
  6. 时序要求: 单总线通信非常依赖时序。每个位都必须在特定的时间内传输和采样,以确保数据的正确性。
  7. 供电: 一些单总线设备可以从总线上获得电源,这减少了对额外电源线的需求。
  8. 错误处理: 单总线通信通常包括错误检测和纠正机制,以确保数据的完整性。

四.协议简介   

        One Wire总线的通信过程分为三个阶段:

  1. 初始化阶段:主机发送一个复位信号,将总线上的所有设备复位。
  2. 数据传输阶段:主机发送一个时钟信号,从机根据主机的时钟信号逐位发送数据。主机可以接收从机发送的数据,也可以向从机发送数据。
  3. 结束阶段:主机发送一个停止信号,结束通信过程。

复位和应答

写协议

读协议 

 

 五.verilog代码

        代码以状态机的方式展示,根据上图协议我们可以把状态机分成复位脉冲和在线应答脉冲的复位序列、写 0 时隙、写 1 时隙、读时隙等等。

module wb_onewire(  
  input         wb_clk_i,           // 时钟输入  
  input         wb_rst_i,            // 复位输入  
  input  [15:0] wb_dat_i,            // 16位宽的数据输入  
  output [15:0] wb_dat_o,            // 16位宽的数据输出  
  output        wb_ack_o,           // 一拍有效的确认输出  
  input         wb_we_i,             // 一拍有效的写信号输入  
  input         wb_cyc_i,            // 一拍有效的周期信号输入  
  input         wb_stb_i,            // 一拍有效的稳定信号输入  
  
  output [7:0]  onewire_o,           // 8位宽的一线串行总线输出  
  output [7:0]  onewire_oe_o,        // 高表示总线为主机使用,低表示总线为从机使用  
  input  [7:0]  onewire_i            // 8位宽的一线串行总线输入  
);  
  
parameter read_block_enable_opt = 1'b1;   // 读块使能参数,默认为1  
parameter push_1_opt            = 1'b0;   // push 1参数,默认为0  
parameter wb_freq               = 75000000; // 时钟频率参数,默认为75MHz  
  
// 函数定义:计算微秒计数器值  
function [15:0] usec_count;  
input [9:0] usec;  
begin  
  usec_count = (((wb_freq / 1000000) * usec) - 1) & 16'hffff;  
end  
endfunction  
  
reg [2:0]  lun, b;                     // 3位宽的lun和b寄存器  
reg [3:0]  read_bytes;                // 4位宽的读取字节寄存器  
reg [15:0] usec_counter;             // 16位宽的微秒计数器  
reg        rst_bit, usec_counter_run; // 重置位和微秒计数器运行标志位  
reg        wb_ack, rxdone, onewire_i_q; // wb确认、接收完成、onewire输入队列标志位  
reg        usec_counter2_run;        // 第二个微秒计数器运行标志位  
reg [8:0]  usec_counter2;            // 9位宽的第二个微秒计数器  
reg [7:0]  dat, shiftreg, onewire, onewire_oe; // 数据、移位寄存器、onewire数据、onewire使能标志位  
  
assign wb_ack_o     = wb_ack;          // wb确认输出信号  
assign wb_dat_o     = {lun, rst_bit, read_bytes, dat}; // wb数据输出信号  
assign onewire_oe_o  = onewire_oe;      // 一线串行总线使能输出信号  
assign onewire_o     = onewire;        // 一线串行总线输出信号  
  
// 主逻辑块,在时钟上升沿或复位信号上升沿触发  
always @(posedge wb_clk_i or posedge wb_rst_i) begin
  if (wb_rst_i) begin
    state            <= 4'd0 ;
    wb_ack           <= 1'b0 ;
    lun              <= 3'd0 ;
    read_bytes       <= 4'd0 ;
    usec_counter     <= 16'd0;
    usec_counter_run <= 1'b0 ;
    usec_counter2    <= 9'd0 ;
    usec_counter2_run<= 1'b0 ;
    onewire          <= 8'd0 ;
    onewire_oe       <= 8'd0 ;
    rst_bit          <= 1'b0 ;
    dat              <= 8'd0 ;
    shiftreg         <= 8'd0 ;
    b                <= 3'd0 ;
    rxdone           <= 1'b0 ;
    push_done        <= 1'b0 ;
    onewire_i_q      <= 1'b0 ;
  end else begin
    wb_ack      <= 1'b0;
    onewire_i_q <= onewire_i[lun];

    if (usec_counter_run) begin
      if (usec_counter == 16'd0) 
	      usec_counter_run <= 1'b0;
          usec_counter     <= usec_counter - 1'b1;
    end

    if (usec_counter2_run) begin
      if (usec_counter2 == 9'd0) 
	      usec_counter2_run <= 1'b0;
          usec_counter2     <= usec_counter2 - 1'b1;
    end

    if (wb_cyc_i && wb_stb_i && !wb_ack && !wb_we_i) begin
      if (!read_block_enable_opt || (!rst_bit && (rxdone || read_bytes == 4'd0))) begin
        wb_ack <= 1'b1;
        rxdone <= 1'b0;
      end
    end

    case (state)   //代码核心,状态机部分
    4'd0:          //初始化,状态选择
	if (!rxdone && read_bytes != 4'd0) 
	begin
        rst_bit <= 1'b1;
        state   <= 4'd7;
      if (read_bytes >= 4'he) 
	    b <= read_bytes[0] ? 3'd6 : 3'd7;
      end else if (wb_cyc_i && wb_stb_i && !wb_ack && wb_we_i) begin
        wb_ack     <= 1'b1;
        lun        <= wb_dat_i[15:13];
        read_bytes <= wb_dat_i[11:8];
      if (wb_dat_i[12] && wb_dat_i[7]) begin // reset 
        state   <= 4'd1; 
        rst_bit <= 1'b1;
      end else if (wb_dat_i[12] && wb_dat_i[6]) begin // write 1-bit 
        state    <= 4'd5; 
        shiftreg <= wb_dat_i[7:0];
        rst_bit  <= 1'b1;
        b        <= 3'd7; 
      end else if (!wb_dat_i[12]) begin // write 8-bit 
        state    <= 4'd5; 
        shiftreg <= wb_dat_i[7:0];
        rst_bit  <= 1'b1;
      end
    end 

    // Reset states 
    4'd1: 
	begin // 480us low pulse 
      onewire[lun]     <= 1'b0;
      onewire_oe[lun]  <= 1'b1;
      usec_counter     <= usec_count(480);
      usec_counter_run <= 1'b1;
      state            <= 4'd2;
    end
	
    4'd2: 
	if (usec_counter_run == 1'b0) 
	begin // 70us pull up 
      onewire_oe[lun]  <= 1'b0;
      usec_counter     <= usec_count(70);
      usec_counter_run <= 1'b1;
      state            <= 4'd3;
      dat[1]           <= 1'b1;
      push_done        <= 1'b0;
    end
	
    4'd3: 
	if (usec_counter_run == 1'b0) 
	    begin // sample presence, 410us delay 
          if (onewire_i_q == 1'b0) 
	           dat[0] <= 1'b1; 
	      else dat[0] <= 1'b0;
               usec_counter     <= usec_count(410);
               usec_counter_run <= 1'b1;
               onewire_oe[lun]  <= 1'b0;
               onewire[lun]     <= 1'b0;
               state            <= 4'd4;
        end 
	else if (onewire_i_q && !push_1_opt) 
	  dat[1] <= 1'b0;
    else if (!push_done && onewire_i_q && push_1_opt) 
	begin
      dat[1]            <= 1'b0;
      onewire_oe[lun]   <= 1'b1;
      onewire[lun]      <= 1'b1;
      usec_counter2     <= usec_count(2);
      usec_counter2_run <= 1'b1;
      push_done         <= 1'b1;
    end 
	else if (push_done && usec_counter2_run == 1'b0) 
	begin
      onewire_oe[lun] <= 1'b0;
      onewire[lun]    <= 1'b0;
    end 
	
    4'd4: 
	if (usec_counter_run == 1'b0) 
	begin
      state   <= 4'd0;
      rst_bit <= 1'b0;
    end

    // Write state machine 
    4'd5: 
	if (usec_counter_run == 1'b0) 
	begin 
      // Write of 0/1 begins with 6us low (1) or 60us low (0) 
         onewire[lun]    <= 1'b0;
         onewire_oe[lun] <= 1'b1;
      if (shiftreg[0]) 
	     usec_counter <= usec_count(6);
      else usec_counter <= usec_count(60);
         usec_counter_run <= 1'b1;
         state <= 4'd6;
    end
	
    4'd6: 
	if (usec_counter_run == 1'b0) 
	begin 
      onewire[lun] <= 1'b1;
      if (shiftreg[0]) 
	     usec_counter <= usec_count(64);
      else 
	     usec_counter     <= usec_count(10);
         usec_counter_run <= 1'b1;
         shiftreg         <= {onewire_i_q, shiftreg[7:1]}; // right shift 
         b                <= b + 1'b1;
         if (b == 3'd7) 
	          state <= 4'd4; 
	     else state <= 4'd5;
    end

    // Read state machine 
    4'd7: 
	begin
      onewire[lun]     <= 1'b0;
      onewire_oe[lun]  <= 1'b1;
      usec_counter     <= usec_count(6);
      usec_counter_run <= 1'b1;
      state            <= 4'd8;
    end
	
    4'd8: 
	if (usec_counter_run == 1'b0) 
	begin
      onewire_oe[lun]  <= 1'b0;
      usec_counter     <= usec_count(9);
      usec_counter_run <= 1'b1;
      push_done        <= 1'b0;
      state            <= 4'd9;
    end
	
    4'd9: 
	if (usec_counter_run == 1'b0) 
	begin
      shiftreg         <= {onewire_i_q, shiftreg[7:1]};
      usec_counter     <= usec_count(55);
      usec_counter_run <= 1'b1;
      state            <= 4'd10;
      onewire_oe[lun]  <= 1'b0;
      onewire[lun]     <= 1'b0;
    end 
	else if (!push_done && onewire_i_q && push_1_opt) 
	begin
      onewire_oe[lun]   <= 1'b1;
      onewire[lun]      <= 1'b1;
      usec_counter2     <= usec_count(2);
      usec_counter2_run <= 1'b1;
      push_done         <= 1'b1;
    end 
	else if (push_done && usec_counter2_run == 1'b0) 
	begin
      onewire_oe[lun] <= 1'b0;
      onewire[lun] <= 1'b0;
    end
	
    4'd10: 
	if (usec_counter_run == 1'b0) 
	begin
      b <= b + 1'b1;
      if (b == 3'd7) 
	  begin
        dat[7:0] <= shiftreg;
	    if (read_bytes >= 4'he) 
		   read_bytes <= 4'd0;
        else 
		   read_bytes <= read_bytes - 1'b1;
           rxdone     <= 1'b1;
           state      <= 4'd0;
           rst_bit    <= 1'b0;
      end 
	  else 
	     state <= 4'd7;
    end
    endcase
  end
end
endmodule

 六.总结

        在One-Wire协议中,主机和从机通过DQ线进行通信。主机向DQ线发送时钟信号,从机根据时钟信号将数据写入DQ线。主机读取DQ线上的电压变化,从而获取从机发送的数据。由于DQ线上只有一条信号线,因此需要采用特殊的操作来区分数据位和应答位。 

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

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

相关文章

[CVPR-23] Instant Volumetric Head Avatars

[paper | code | proj] 本文提出INSTA。INSTA是一种backward mapping方法。该方法基于NeRF建立标准空间&#xff0c;形变空间&#xff08;任意表情&#xff09;通过映射回标准空间&#xff0c;实现渲染。为实现形变空间中任意点向标准空间的映射&#xff0c;对形变空间中的任意…

PySpark中DataFrame的join操作

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

Vue 保留富文本中包含指定字符串所在的行

需求描述 如下图所示&#xff0c;想保留所有包含『张三』所在的行 最终实现效果 先看一下富文本的源码 <p>任务1 张三</p> <p>任务2 张三</p> <p>任务3 李四</p> <p>任务4 李四</p> &l…

「微服务模式」七种微服务反模式

什么是微服务 流行语经常为进化的概念提供背景&#xff0c;并且需要一个良好的“标签”来促进对话。微服务是一个新的“标签”&#xff0c;它定义了我个人一直在发现和使用的领域。文章和会议描述了一些事情&#xff0c;我慢慢意识到&#xff0c;过去几年我一直在发展自己的个人…

JMeter常见配置及常见问题修改

一、设置JMeter默认打开字体 1、进入安装目录&#xff1a;apache-jmeter-x.x.x\bin\ 2、找到 jmeter.properties&#xff0c;打开。 3、搜索“ languageen ”&#xff0c;前面带有“#”号.。 4、去除“#”号&#xff0c;并修改为&#xff1a;languagezh_CN 或 直接新增一行&…

Envoy

一. Envoy ). Envoy Envoy 于 2017 年 9 月作为孵化项目加入 CNCF。从孵化到毕业&#xff0c;Envoy 都是 CNCF 增长最快的项目之一 Envoy 在吞吐量和延迟方面都表现良好。这在大型云原生部署中至关重要 Envoy 是专为大型现代 SOA&#xff08;面向服务架构&#xff09;架构设计…

Java|IDEA 中添加编译参数 --add-exports

方法1 File > Settings > Build, Execution, Deployment > Compiler > Java Compiler > Javac Options > Override compiler parameters per-module 点击&#xff1a; 点击OK 双击Compliation options&#xff0c;输入后回车&#xff1a; 方法2 找到出错…

【S32DS RTD实战】-1.4-基于S32K3创建配置FreeRTOS工程-控制GPIO点亮LED

目录(附DEMO&#xff0c;可下载&#xff0c;讲解过程超详细) 1 下载FREERTOS RTD 1.1 安装FREERTOS RTD 2 确认S32DS已安装的AUTOSAR RTD 3 基于S32K3创建&配置FREERTOS工程 3.1 选择SDKs 3.2 增加FreeRTOS模块 3.3 修改MCU芯片封装 3.4 配置GPIO 3.5 修改HSE CLK…

python如何更改代码背景图片,背景主题(黑色护眼)和各类文本颜色(python进阶必看,爱了爱了)

一、在 PyCharm 中设置图片背景的方法如下&#xff1a; 打开 PyCharm 的设置窗口&#xff0c;在设置窗口中找到 "Appearance & Behavior" -> "Appearance" 选项卡。在 "Appearance" 选项卡中&#xff0c;找到 "Background Image&qu…

HarmonyOs4.0基础

目录 一、HarmonyOs系统定义 1.1系统的技术特性(三大特征) 1.1.1、硬件互助、资源共享 1.1.2、一次开发、多端部署(面向开发者) 1.1.3、统一OS&#xff0c;弹性部署(支持多种API&#xff1a;ArkTs、JS、C/C、Java) 1.2、系统的技术架构 二、Harmony OS项目搭建 2.1、(D…

同步与互斥(二)

一、谁上锁就由谁解锁&#xff1f; 互斥量、互斥锁&#xff0c;本来的概念确实是&#xff1a;谁上锁就得由谁解锁。 但是FreeRTOS并没有实现这点&#xff0c;只是要求程序员按照这样的惯例写代码。 main函数创建了2个任务&#xff1a; 任务1&#xff1…

文件:文本文件和二进制文件 详解

目录 0 引言1 文本文件1.1 是如何存储的&#xff1f;1.2 文件拓展名 2 二进制文件2.1 是如何存储的&#xff1f;2.2 分类2.2.1 图像文件2.2.2 音频文件2.2.3 视频文件2.2.4 可执行文件 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;C专栏&#x…

GD32F4中断向量查询

中断向量表 中断向量对应函数 __Vectors DCD __initial_sp ; Top of StackDCD Reset_Handler ; Reset HandlerDCD NMI_Handler ; NMI HandlerDCD HardFault_Handler ;…

行为型设计模式(三)状态模式 备忘录模式

状态模式 State 1、什么是状态模式 状态模式允许一个对象在其内部状态改变时改变它的行为&#xff0c;对象看起来似乎修改了它的类&#xff0c;将对象的行为包装在不同的状态类中&#xff0c;对象在运行时根据内部状态的改变而改变它的行为。 2、为什么使用状态模式 封装了…

【数字图像处理】实验四 图像分割

一、实验内容&#xff1a; 1&#xff0e; 熟悉和掌握利用Matlab工具进行数字图像的读、写、显示等数字图像处理基本步骤。 2&#xff0e; 熟练掌握各种图像分割的基本原理及方法。 3&#xff0e; 能够从深刻理解图像分割&#xff0c;并能够思考拓展到一定的应用领域。 二、实验…

雷军1992年发表的计算机论文,强啊!

提起雷军&#xff0c;相信大家都非常熟悉了&#xff0c;90年代初毕业于武大计算机系&#xff0c;后来一路创业&#xff0c;现如今在相应领域的成就也有目共睹。 之前咱们这里也分享过雷军早年间写的文字博客&#xff0c;他曾在早期博客中讲述了自己的编程之路&#xff0c;以及当…

机器学习 | 概率图模型

见微知著&#xff0c;睹始知终。 见到细微的苗头就能预知事物的发展方向&#xff0c;能透过微小的现象看到事物的本质&#xff0c;推断结论或者结果。 概率模型为机器学习打开了一扇新的大门&#xff0c;将学习的任务转变为计算变量的概率分布。 实际情况中&#xff0c;各个变量…

一个简单的 HTTP 请求和响应服务——httpbin

拉取镜像 docker pull kennethreitz/httpbin:latest 查看本地是否存在存在镜像 docker images | grep kennethreitz/httpbin:latest 创建 deployment&#xff0c;指定镜像 apiVersion: apps/v1 kind: Deployment metadata:labels:app: httpbinname: mm-httpbinnamespace: mm-…

FPC柔性排线用什么胶水能固定到线路板上?

为了固定FPC柔性排线到线路板上&#xff0c;可以使用特殊用于电子组装的胶水。常用的胶水类型有&#xff1a; 1.氰基丙烯酸酯胶水&#xff08;Cyanoacrylate&#xff09; 被称为“超级胶水”或“快干胶水”。这种胶水对FPC通常有很好的附着力。 2.环氧树脂胶水 环氧树脂胶水…

C++之深拷贝和浅拷贝

目录 浅拷贝 深拷贝 赋值运算符重载的深拷贝 在学习C类和对象时我们学习了浅拷贝&#xff0c;本期我们将再次回顾浅拷贝并为大家讲述深拷贝的概念。 浅拷贝 在学习类和对象时我们学习了拷贝构造函数的概念&#xff0c;而且我们也知道&#xff0c;因为拷贝构造函数属于类的默…