赞
踩
单总线(OneWire)是一种串行通信协议,它允许多个设备通过一个单一的数据线进行通信。这个协议通常用于低速、短距离的数字通信,特别适用于嵌入式系统和传感器网络。
One Wire总线的通信过程分为三个阶段:
代码以状态机的方式展示,根据上图协议我们可以把状态机分成复位脉冲和在线应答脉冲的复位序列、写 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线上只有一条信号线,因此需要采用特殊的操作来区分数据位和应答位。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。