您的位置:首页 > 其它

基于FPGA的DS18B20控制程序设计及其Verilog实现(二)

2014-11-20 18:39 696 查看
三,1-Wire总线上按Byte读写的Verilog实现及DS18B20的Byte操作

上面用简单状态机实现了1-Wire总线上单bit数据的读写操作。在此基础上,可以通过状态机嵌套的方法实现按Byte的读写操作。实现Byte读写控制的状态机,控制8bit数据的读写操作,而每一bit的读写操作则通过嵌套单bit数据读写的状态机来实现。

1. 按Byte读操作

从DS18B20的datasheet上我们可以看到,1-Wire总线在发送或者接收数据的时候,LSB的数据在前,MSB的数据在后。所以对于Byte数据的读操作,只要依次在总线上读取8bit数据,并按照bit0~bit7的顺序将其存储到一个8bits的寄存器里即可。

通常情况下,设计状态机的时候,都会设计一个默认的初始状态(也可以称之为IDLE状态)。在这里每个bit数据的读操作可以设定为一个状态。这样,整个状态机就需要九个状态。在我们的设计中,九个状态分别是RBD_IDLE, RBD_BIT0 ~RBD_BIT7,其中 RBD_IDLE是IDLE状态,RBD_BIT0~RBD_BIT7分别是读取bit0~bit7数据的状态。

状态机在系统复位或者操作完成以后,进入RBD_IDLE状态。当读Byte数据的使能信号(RBDBEGIN)有效时,状态机进入RBD_BIT0,并调用1-Wire总线单bit读操作的状态机实现单bit的读操作,读取bit0的数据。为了在状态机进入RBD_BIT0的时候,正确调用单bit读操作的状态机,就要在RBD_BIT0状态下,使能RDBEGIN信号(单bit读操作的使能信号,详见上文)。在读完bit0的数据后(单bit读操作状态机回到IDLE状态),状态机需要进入RBD_BIT1状态,读取bit1的数据。也就是说,状态机从RBD_BIT0进入到RBD_BIT1的条件是bit0读操作结束(即其状态机回到IDLE状态),这个条件可以用单bit读操作状态机的PHASE_RD_OVER生成。上述的操作就实现了两个状态机的嵌套,顶层状态机(Byte读操作状态机)的信号触发底层状态机(单bit读操作状态机)进入工作状态,当底层状态机完成工作进入IDLE状态时,触发顶层状态机进入下一个状态。

从RBD_BIT0到RBD_BIT7的操作是相同的,依次读取8bit的数据。不过读完bit7的数据后,状态机要转回到RBD_IDLE状态。另外就是在单bit读的过程中,要根据Byte读状态机的状态,将读到的单bit数据写入对应的寄存器中。

下面是verilog的实现:

reg [7:0] RD_BYTE_DATA; //Byte读数据结果

wire RBDBEGIN ; // Byte读使能信号

reg PHASE_RD_OVER_Q;

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

PHASE_RD_OVER_Q <= 1'b0;

else

PHASE_RD_OVER_Q <= PHASE_RD_OVER;

end

wire RD_BIT_OVER = PHASE_RD_OVER & PHASE_RD_OVER_Q; //单bit读操作结束信号

parameter RBD_IDLE = 9'b0_0000_0001,

RBD_BIT0 = 9'b0_0000_0010,

RBD_BIT1 = 9'b0_0000_0100,

RBD_BIT2 = 9'b0_0000_1000,

RBD_BIT3 = 9'b0_0001_0000,

RBD_BIT4 = 9'b0_0010_0000,

RBD_BIT5 = 9'b0_0100_0000,

RBD_BIT6 = 9'b0_1000_0000,

RBD_BIT7 = 9'b1_0000_0000;

reg [8:0] RBDSM, RBDSMNXT;

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

RBDSM <= RBD_IDLE;

else

RBDSM <= RBDSMNXT;

end

always @(RBDSM or RBDBEGIN or RD_BIT_OVER) begin

case(RBDSM)

RBD_IDLE:

if(RBDBEGIN)

RBDSMNXT = RBD_BIT0;

else

RBDSMNXT = RBD_IDLE;

RBD_BIT0:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT1;

else

RBDSMNXT = RBD_BIT0;

RBD_BIT1:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT2;

else

RBDSMNXT = RBD_BIT1;

RBD_BIT2:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT3;

else

RBDSMNXT = RBD_BIT2;

RBD_BIT3:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT4;

else

RBDSMNXT = RBD_BIT3;

RBD_BIT4:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT5;

else

RBDSMNXT = RBD_BIT4;

RBD_BIT5:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT6;

else

RBDSMNXT = RBD_BIT5;

RBD_BIT6:

if(RD_BIT_OVER)

RBDSMNXT = RBD_BIT7;

else

RBDSMNXT = RBD_BIT6;

RBD_BIT7:

if(RD_BIT_OVER)

RBDSMNXT = RBD_IDLE;

else

RBDSMNXT = RBD_BIT7;

default:

RBDSMNXT = RBD_IDLE;

endcase

end

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

RD_BYTE_DATA <= 8'b0;

else if(PHASE_RD_MSAP & (RD_CNT == 6'd13) )

begin

case(RBDSM)

9'b0_0000_0010:

RD_BYTE_DATA[0] <= DQ;

9'b0_0000_0100:

RD_BYTE_DATA[1] <= DQ;

9'b0_0000_1000:

RD_BYTE_DATA[2] <= DQ;

9'b0_0001_0000:

RD_BYTE_DATA[3] <= DQ;

9'b0_0010_0000:

RD_BYTE_DATA[4] <= DQ;

9'b0_0100_0000:

RD_BYTE_DATA[5] <= DQ;

9'b0_1000_0000:

RD_BYTE_DATA[6] <= DQ;

9'b1_0000_0000:

RD_BYTE_DATA[7] <= DQ;

default:

RD_BYTE_DATA <= RD_BYTE_DATA;

endcase

end

else

RD_BYTE_DATA <= RD_BYTE_DATA;

end

2. 按Byte写操作

按Byte写操作的状态机与按Byte读操作的状态机的控制原理基本上是相同的。只不过在这里要嵌套的是单bit写操作的状态机。另外就是在单bit写操作的时候,要把对应bit的数据放到DQ总线上。

限于篇幅,状态机的实现不再给出,可自行参照Byte读操作的状态机做修改。

3. DS18B20的Byte操作

DS18B20的控制主要包括初始化,ROM命令和功能命令等。初始化的控制方式前面已经讨论过了。这里主要讨论一下ROM命令和功能命令。实际上不管是ROM命令还是功能命令,都可以归结为一个字节的命令(Byte写操作)加上0或者多个的Byte读/写操作。所以我们完全可以用上面所述的Byte读写状态机来实现ROM和功能命令。

对于只有一个单Byte写操作的命令,我们直接引用单Byte写操作的状态机就可以实现了。

下图即为执行SKIP ROM(8’hcc)命令时,从DQ总线上抓到的波形。





下图为执行COVERT(8’h44)命令时,从DQ总线上抓到的波形。





而对于如读ROM数据的操作,则是一个Byte的写命令操作加上连续多个Byte的读数据的操作。在实现的时候,我们完全可以依照Byte读写操作状态机嵌套单bit读写操作状态机的方法,设计一个多BYTE读写操作的状态机,嵌套单Byte读写状态机。

下面是从DS18B20读出9Byte数据的状态机的verilog实现:

reg [7:0] TMP_LSB;

reg [7:0] TMP_MSB;

reg [7:0] USERBYTE1;

reg [7:0] USERBYTE2;

reg [7:0] CFGREG;

reg [7:0] RESERVED5;

reg [7:0] RESERVED6;

reg [7:0] RESERVED7;

reg [7:0] REGCRC;

wire RDSPAD_EN; //读DS18B20 rom数据使能信号

wire BYTE_READ_OVER = RD_BIT_OVER & PHASE_RBD_BIT7; //Byte读操作结束信号。

wire BYTE_WRITE_OVER = WD_BIT_OVER & PHASE_WBD_BIT7; //Byte 写操作结束信号。

parameter RDSPAD_IDLE = 11'b000_0000_0001,

RDSPAD_CMD = 11'b000_0000_0010, //读ROM命令

RDSPAD_BYTE1 = 11'b000_0000_0100, // 读ROM Byte 1

RDSPAD_BYTE2 = 11'b000_0000_1000,

RDSPAD_BYTE3 = 11'b000_0001_0000,

RDSPAD_BYTE4 = 11'b000_0010_0000,

RDSPAD_BYTE5 = 11'b000_0100_0000,

RDSPAD_BYTE6 = 11'b000_1000_0000,

RDSPAD_BYTE7 = 11'b001_0000_0000,

RDSPAD_BYTE8 = 11'b010_0000_0000,

RDSPAD_BYTE9 = 11'b100_0000_0000;

reg [10:0] RDSPADSM, RDSPADSMNXT;

wire PHASE_RDSPAD_IDLE = RDSPADSM[0];

wire PHASE_RDSPAD_CMD = RDSPADSM[1];

wire PHASE_RDSPAD_BYTE1 = RDSPADSM[2];

wire PHASE_RDSPAD_BYTE2 = RDSPADSM[3];

wire PHASE_RDSPAD_BYTE3 = RDSPADSM[4];

wire PHASE_RDSPAD_BYTE4 = RDSPADSM[5];

wire PHASE_RDSPAD_BYTE5 = RDSPADSM[6];

wire PHASE_RDSPAD_BYTE6 = RDSPADSM[7];

wire PHASE_RDSPAD_BYTE7 = RDSPADSM[8];

wire PHASE_RDSPAD_BYTE8 = RDSPADSM[9];

wire PHASE_RDSPAD_BYTE9 = RDSPADSM[10];

wire PHASENXT_RDSPAD_IDLE = RDSPADSMNXT[0];

wire PHASENXT_RDSPAD_CMD = RDSPADSMNXT[1];

wire PHASENXT_RDSPAD_BYTE1 = RDSPADSMNXT[2];

wire PHASENXT_RDSPAD_BYTE2 = RDSPADSMNXT[3];

wire PHASENXT_RDSPAD_BYTE3 = RDSPADSMNXT[4];

wire PHASENXT_RDSPAD_BYTE4 = RDSPADSMNXT[5];

wire PHASENXT_RDSPAD_BYTE5 = RDSPADSMNXT[6];

wire PHASENXT_RDSPAD_BYTE6 = RDSPADSMNXT[7];

wire PHASENXT_RDSPAD_BYTE7 = RDSPADSMNXT[8];

wire PHASENXT_RDSPAD_BYTE8 = RDSPADSMNXT[9];

wire PHASENXT_RDSPAD_BYTE9 = RDSPADSMNXT[10];

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

RDSPADSM <= RDSPAD_IDLE;

else

RDSPADSM <= RDSPADSMNXT;

end

always @( RDSPADSM or RDSPAD_EN or BYTE_READ_OVER or BYTE_WRITE_OVER) begin

case(RDSPADSM)

RDSPAD_IDLE:

if(RDSPAD_EN)

RDSPADSMNXT = RDSPAD_CMD;

else

RDSPADSMNXT = RDSPAD_IDLE;

RDSPAD_CMD:

if(BYTE_WRITE_OVER)

RDSPADSMNXT = RDSPAD_BYTE1;

else

RDSPADSMNXT = RDSPAD_CMD;

RDSPAD_BYTE1:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE2;

else

RDSPADSMNXT = RDSPAD_BYTE1;

RDSPAD_BYTE2:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE3;

else

RDSPADSMNXT = RDSPAD_BYTE2;

RDSPAD_BYTE3:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE4;

else

RDSPADSMNXT = RDSPAD_BYTE3;

RDSPAD_BYTE4:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE5;

else

RDSPADSMNXT = RDSPAD_BYTE4;

RDSPAD_BYTE5:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE6;

else

RDSPADSMNXT = RDSPAD_BYTE5;

RDSPAD_BYTE6:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE7;

else

RDSPADSMNXT = RDSPAD_BYTE6;

RDSPAD_BYTE7:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE8;

else

RDSPADSMNXT = RDSPAD_BYTE7;

RDSPAD_BYTE8:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_BYTE9;

else

RDSPADSMNXT = RDSPAD_BYTE8;

RDSPAD_BYTE9:

if(BYTE_READ_OVER)

RDSPADSMNXT = RDSPAD_IDLE;

else

RDSPADSMNXT = RDSPAD_BYTE9;

default:

RDSPADSMNXT = RDSPAD_IDLE;

endcase

end

//采集并保存TMP_LSB

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

TMP_LSB <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE2 & BYTE_READ_OVER)

TMP_LSB <= RD_BYTE_DATA;

else

TMP_LSB <= TMP_LSB;

end

//采集并保存 TMP_MSB

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

TMP_MSB <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE3 & BYTE_READ_OVER)

TMP_MSB <= RD_BYTE_DATA;

else

TMP_MSB <= TMP_MSB;

end

//采集并保存 USERBYTE1

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

USERBYTE1 <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE4 & BYTE_READ_OVER)

USERBYTE1 <= RD_BYTE_DATA;

else

USERBYTE1 <= USERBYTE1;

End

//采集并保存USERBYTE2

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

USERBYTE2 <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE5 & BYTE_READ_OVER)

USERBYTE2 <= RD_BYTE_DATA;

else

USERBYTE2 <= USERBYTE2;

end

//采集并保存 CFGREG

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

CFGREG <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE6 & BYTE_READ_OVER)

CFGREG <= RD_BYTE_DATA;

else

CFGREG <= CFGREG;

end

//采集并保存 RESERVED5

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

RESERVED5 <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE7 & BYTE_READ_OVER)

RESERVED5 <= RD_BYTE_DATA;

else

RESERVED5 <= RESERVED5;

end

//采集并保存 RESERVED6

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

RESERVED6 <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE8 & BYTE_READ_OVER)

RESERVED6 <= RD_BYTE_DATA;

else

RESERVED6 <= RESERVED6;

end

//采集并保存 RESERVED7

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

RESERVED7 <= 8'b0;

else if(PHASENXT_RDSPAD_BYTE9 & BYTE_READ_OVER)

RESERVED7 <= RD_BYTE_DATA;

else

RESERVED7 <= RESERVED7;

end

//采集并保存 REGCRC

always @(posedge CLK1MHZ or negedge RESET)

begin

if(~RESET)

REGCRC <= 8'b0;

else if(PHASENXT_RDSPAD_IDLE & BYTE_READ_OVER)

REGCRC <= RD_BYTE_DATA;

else

REGCRC <= REGCRC;

end

下图是从示波器上抓出的单Byte读操作的DQ上的波形。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: