当前位置:   article > 正文

one wire(单总线)FPGA代码篇_one wire协议

one wire协议

一.引言

        单总线(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 时隙、读时隙等等。

  1. module wb_onewire(
  2. input wb_clk_i, // 时钟输入
  3. input wb_rst_i, // 复位输入
  4. input [15:0] wb_dat_i, // 16位宽的数据输入
  5. output [15:0] wb_dat_o, // 16位宽的数据输出
  6. output wb_ack_o, // 一拍有效的确认输出
  7. input wb_we_i, // 一拍有效的写信号输入
  8. input wb_cyc_i, // 一拍有效的周期信号输入
  9. input wb_stb_i, // 一拍有效的稳定信号输入
  10. output [7:0] onewire_o, // 8位宽的一线串行总线输出
  11. output [7:0] onewire_oe_o, // 高表示总线为主机使用,低表示总线为从机使用
  12. input [7:0] onewire_i // 8位宽的一线串行总线输入
  13. );
  14. parameter read_block_enable_opt = 1'b1; // 读块使能参数,默认为1
  15. parameter push_1_opt = 1'b0; // push 1参数,默认为0
  16. parameter wb_freq = 75000000; // 时钟频率参数,默认为75MHz
  17. // 函数定义:计算微秒计数器值
  18. function [15:0] usec_count;
  19. input [9:0] usec;
  20. begin
  21. usec_count = (((wb_freq / 1000000) * usec) - 1) & 16'hffff;
  22. end
  23. endfunction
  24. reg [2:0] lun, b; // 3位宽的lun和b寄存器
  25. reg [3:0] read_bytes; // 4位宽的读取字节寄存器
  26. reg [15:0] usec_counter; // 16位宽的微秒计数器
  27. reg rst_bit, usec_counter_run; // 重置位和微秒计数器运行标志位
  28. reg wb_ack, rxdone, onewire_i_q; // wb确认、接收完成、onewire输入队列标志位
  29. reg usec_counter2_run; // 第二个微秒计数器运行标志位
  30. reg [8:0] usec_counter2; // 9位宽的第二个微秒计数器
  31. reg [7:0] dat, shiftreg, onewire, onewire_oe; // 数据、移位寄存器、onewire数据、onewire使能标志位
  32. assign wb_ack_o = wb_ack; // wb确认输出信号
  33. assign wb_dat_o = {lun, rst_bit, read_bytes, dat}; // wb数据输出信号
  34. assign onewire_oe_o = onewire_oe; // 一线串行总线使能输出信号
  35. assign onewire_o = onewire; // 一线串行总线输出信号
  36. // 主逻辑块,在时钟上升沿或复位信号上升沿触发
  37. always @(posedge wb_clk_i or posedge wb_rst_i) begin
  38. if (wb_rst_i) begin
  39. state <= 4'd0 ;
  40. wb_ack <= 1'b0 ;
  41. lun <= 3'd0 ;
  42. read_bytes <= 4'd0 ;
  43. usec_counter <= 16'd0;
  44. usec_counter_run <= 1'b0 ;
  45. usec_counter2 <= 9'd0 ;
  46. usec_counter2_run<= 1'b0 ;
  47. onewire <= 8'd0 ;
  48. onewire_oe <= 8'd0 ;
  49. rst_bit <= 1'b0 ;
  50. dat <= 8'd0 ;
  51. shiftreg <= 8'd0 ;
  52. b <= 3'd0 ;
  53. rxdone <= 1'b0 ;
  54. push_done <= 1'b0 ;
  55. onewire_i_q <= 1'b0 ;
  56. end else begin
  57. wb_ack <= 1'b0;
  58. onewire_i_q <= onewire_i[lun];
  59. if (usec_counter_run) begin
  60. if (usec_counter == 16'd0)
  61. usec_counter_run <= 1'b0;
  62. usec_counter <= usec_counter - 1'b1;
  63. end
  64. if (usec_counter2_run) begin
  65. if (usec_counter2 == 9'd0)
  66. usec_counter2_run <= 1'b0;
  67. usec_counter2 <= usec_counter2 - 1'b1;
  68. end
  69. if (wb_cyc_i && wb_stb_i && !wb_ack && !wb_we_i) begin
  70. if (!read_block_enable_opt || (!rst_bit && (rxdone || read_bytes == 4'd0))) begin
  71. wb_ack <= 1'b1;
  72. rxdone <= 1'b0;
  73. end
  74. end
  75. case (state) //代码核心,状态机部分
  76. 4'd0: //初始化,状态选择
  77. if (!rxdone && read_bytes != 4'd0)
  78. begin
  79. rst_bit <= 1'b1;
  80. state <= 4'd7;
  81. if (read_bytes >= 4'he)
  82. b <= read_bytes[0] ? 3'd6 : 3'd7;
  83. end else if (wb_cyc_i && wb_stb_i && !wb_ack && wb_we_i) begin
  84. wb_ack <= 1'b1;
  85. lun <= wb_dat_i[15:13];
  86. read_bytes <= wb_dat_i[11:8];
  87. if (wb_dat_i[12] && wb_dat_i[7]) begin // reset
  88. state <= 4'd1;
  89. rst_bit <= 1'b1;
  90. end else if (wb_dat_i[12] && wb_dat_i[6]) begin // write 1-bit
  91. state <= 4'd5;
  92. shiftreg <= wb_dat_i[7:0];
  93. rst_bit <= 1'b1;
  94. b <= 3'd7;
  95. end else if (!wb_dat_i[12]) begin // write 8-bit
  96. state <= 4'd5;
  97. shiftreg <= wb_dat_i[7:0];
  98. rst_bit <= 1'b1;
  99. end
  100. end
  101. // Reset states
  102. 4'd1:
  103. begin // 480us low pulse
  104. onewire[lun] <= 1'b0;
  105. onewire_oe[lun] <= 1'b1;
  106. usec_counter <= usec_count(480);
  107. usec_counter_run <= 1'b1;
  108. state <= 4'd2;
  109. end
  110. 4'd2:
  111. if (usec_counter_run == 1'b0)
  112. begin // 70us pull up
  113. onewire_oe[lun] <= 1'b0;
  114. usec_counter <= usec_count(70);
  115. usec_counter_run <= 1'b1;
  116. state <= 4'd3;
  117. dat[1] <= 1'b1;
  118. push_done <= 1'b0;
  119. end
  120. 4'd3:
  121. if (usec_counter_run == 1'b0)
  122. begin // sample presence, 410us delay
  123. if (onewire_i_q == 1'b0)
  124. dat[0] <= 1'b1;
  125. else dat[0] <= 1'b0;
  126. usec_counter <= usec_count(410);
  127. usec_counter_run <= 1'b1;
  128. onewire_oe[lun] <= 1'b0;
  129. onewire[lun] <= 1'b0;
  130. state <= 4'd4;
  131. end
  132. else if (onewire_i_q && !push_1_opt)
  133. dat[1] <= 1'b0;
  134. else if (!push_done && onewire_i_q && push_1_opt)
  135. begin
  136. dat[1] <= 1'b0;
  137. onewire_oe[lun] <= 1'b1;
  138. onewire[lun] <= 1'b1;
  139. usec_counter2 <= usec_count(2);
  140. usec_counter2_run <= 1'b1;
  141. push_done <= 1'b1;
  142. end
  143. else if (push_done && usec_counter2_run == 1'b0)
  144. begin
  145. onewire_oe[lun] <= 1'b0;
  146. onewire[lun] <= 1'b0;
  147. end
  148. 4'd4:
  149. if (usec_counter_run == 1'b0)
  150. begin
  151. state <= 4'd0;
  152. rst_bit <= 1'b0;
  153. end
  154. // Write state machine
  155. 4'd5:
  156. if (usec_counter_run == 1'b0)
  157. begin
  158. // Write of 0/1 begins with 6us low (1) or 60us low (0)
  159. onewire[lun] <= 1'b0;
  160. onewire_oe[lun] <= 1'b1;
  161. if (shiftreg[0])
  162. usec_counter <= usec_count(6);
  163. else usec_counter <= usec_count(60);
  164. usec_counter_run <= 1'b1;
  165. state <= 4'd6;
  166. end
  167. 4'd6:
  168. if (usec_counter_run == 1'b0)
  169. begin
  170. onewire[lun] <= 1'b1;
  171. if (shiftreg[0])
  172. usec_counter <= usec_count(64);
  173. else
  174. usec_counter <= usec_count(10);
  175. usec_counter_run <= 1'b1;
  176. shiftreg <= {onewire_i_q, shiftreg[7:1]}; // right shift
  177. b <= b + 1'b1;
  178. if (b == 3'd7)
  179. state <= 4'd4;
  180. else state <= 4'd5;
  181. end
  182. // Read state machine
  183. 4'd7:
  184. begin
  185. onewire[lun] <= 1'b0;
  186. onewire_oe[lun] <= 1'b1;
  187. usec_counter <= usec_count(6);
  188. usec_counter_run <= 1'b1;
  189. state <= 4'd8;
  190. end
  191. 4'd8:
  192. if (usec_counter_run == 1'b0)
  193. begin
  194. onewire_oe[lun] <= 1'b0;
  195. usec_counter <= usec_count(9);
  196. usec_counter_run <= 1'b1;
  197. push_done <= 1'b0;
  198. state <= 4'd9;
  199. end
  200. 4'd9:
  201. if (usec_counter_run == 1'b0)
  202. begin
  203. shiftreg <= {onewire_i_q, shiftreg[7:1]};
  204. usec_counter <= usec_count(55);
  205. usec_counter_run <= 1'b1;
  206. state <= 4'd10;
  207. onewire_oe[lun] <= 1'b0;
  208. onewire[lun] <= 1'b0;
  209. end
  210. else if (!push_done && onewire_i_q && push_1_opt)
  211. begin
  212. onewire_oe[lun] <= 1'b1;
  213. onewire[lun] <= 1'b1;
  214. usec_counter2 <= usec_count(2);
  215. usec_counter2_run <= 1'b1;
  216. push_done <= 1'b1;
  217. end
  218. else if (push_done && usec_counter2_run == 1'b0)
  219. begin
  220. onewire_oe[lun] <= 1'b0;
  221. onewire[lun] <= 1'b0;
  222. end
  223. 4'd10:
  224. if (usec_counter_run == 1'b0)
  225. begin
  226. b <= b + 1'b1;
  227. if (b == 3'd7)
  228. begin
  229. dat[7:0] <= shiftreg;
  230. if (read_bytes >= 4'he)
  231. read_bytes <= 4'd0;
  232. else
  233. read_bytes <= read_bytes - 1'b1;
  234. rxdone <= 1'b1;
  235. state <= 4'd0;
  236. rst_bit <= 1'b0;
  237. end
  238. else
  239. state <= 4'd7;
  240. end
  241. endcase
  242. end
  243. end
  244. endmodule

 六.总结

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

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/110561
推荐阅读
相关标签
  

闽ICP备14008679号