利用狀態機實現比較複雜的接口設計:測試
這是一個將並行數據轉換爲串行輸出的變換器,利用雙向總線輸出。這是由EEPROM讀寫器的縮減獲得的,首先對I2C總線特徵介紹:ui
I2C總線(inter integrated circuit)雙向二線制串行總線協議爲:只有總線處於「非忙」狀態時,數據傳輸纔開始。在數據傳輸期間,只要時鐘線爲高電平,數據線都必須保持穩定,不然數據線上的任何變化都被看成「啓動」或「中止」信號。編碼
下面介紹A、B、C、D的工做狀態:spa
(1)總線處於非忙狀態(A段):該段內的數據線(sda)和時鐘線(scl)都保持高電平;設計
(2)啓動數據傳輸(B段):當時鍾線(scl)爲高電平時,數據線(sda)由高電平變爲低電平的降低沿被認爲是「啓動」信號;3d
(3)中止數據傳輸(C段):當時鍾線(scl)爲高電平時,數據線(sda)由低電平變爲高電平的上升沿被認爲是「中止」信號;code
(4)數據有效(D段):在出現「啓動」信號以後,在時鐘線(scl)爲高電平時,數據線是穩定的,這是數據線上的數據就是要傳送的數據,數據線上的數據改變必須在時鐘線(scl)爲低電平期間完成,每一個數據佔用一個時鐘;blog
(5)應答信號:每一個正在接受數據的EEPROM在接收到一個字節的數據後,一般須要發出一個應答信號;而每一個正在發送數據的EEPROM在發出一個字節的數據後,一般須要接受一個應答信號;EEPROM讀寫控制器必須提供一個與這個應答信號相聯繫的二外的始終脈衝。接口
其控制字節一共有8位:1010xxxW/R 其中1010是I2C總線器件特徵編碼,xxx表示地址,W/R表示讀寫狀態。ci
在實現並行輸入串行輸出時,須要兩個狀態機:
主狀態機主要控制內部存儲器和輸入端的鏈接,以及給出應答信號;從狀態機主要負責總線鏈接時,內部寄存器的最高位輸出個移位;
狀態機的源碼以下:
1 module parallel_to_serial(rst,clk,addr,data,sda,ack); 2 input rst,clk; 3 input [7:0]data,addr; 4 5 inout sda; //data bus 6 output ack; //ask for next address/data writting wo eeprm; 7 reg link_write; //whether connect to output 8 reg [2:0]state; //main status, 9 reg [4:0]sh8out_state; //serial output status 10 reg [7:0]sh8out_buf; //output data buffer 11 reg finish_F; //whether finished an operation of main status 12 reg ack; 13 14 parameter idle=0, addr_write=3'd1, data_write=3'd2, stop_ack=3'd4; //main status code 15 parameter bit0=1, bit1=2, bit2=3, bit3=4, bit4=5, bit5=6, bit6=7, bit7=8; //serial output status code 16 17 assign sda=link_write?sh8out_buf[7]:1'bz; //??????????? 18 19 always @(posedge clk) 20 begin 21 if(!rst) //reset 22 begin 23 ack<=0; 24 link_write<=0; //??????? 25 finish_F<=0; 26 state<=idle; 27 sh8out_state<=idle; 28 sh8out_buf<=0; 29 end 30 else 31 case(state) 32 idle:begin 33 link_write<=0; //?????? 34 ack<=0; 35 finish_F<=0; 36 sh8out_buf<=addr; //??????? 37 sh8out_state<=idle; 38 state<=addr_write; //??????? 39 end 40 addr_write:begin 41 if (finish_F==0) begin shift8_out;end //??????? 42 else 43 begin 44 link_write<=0; 45 ack<=0; 46 finish_F<=0; 47 sh8out_buf<=data; //??????? 48 state<=data_write; 49 sh8out_state<=idle; 50 end 51 end 52 data_write:begin 53 if (finish_F==0) begin shift8_out;end //??????? 54 else 55 begin 56 link_write<=0; 57 finish_F<=0; 58 state<=stop_ack; 59 ack<=1; //???????? 60 end 61 end 62 stop_ack:begin //???? 63 ack<=0; 64 state<=idle; 65 end 66 endcase 67 end 68 69 task shift8_out; //??????? 70 begin 71 case(sh8out_state) 72 idle:begin 73 link_write<=1; //?????????????????17?assign sda=link_write?sh8out_buf[7]:1'bz; sda??????????sh8out_buf????? 74 sh8out_state<=bit7; 75 end 76 bit7:begin 77 link_write<=1; 78 sh8out_buf=sh8out_buf<<1; //?????data?????bit6 79 sh8out_state<=bit6; 80 end 81 bit6:begin 82 link_write<=1; 83 sh8out_buf=sh8out_buf<<1; 84 sh8out_state<=bit5; 85 end 86 bit5:begin 87 link_write<=1; 88 sh8out_buf=sh8out_buf<<1; 89 sh8out_state<=bit4; 90 end 91 bit4:begin 92 link_write<=1; 93 sh8out_buf=sh8out_buf<<1; 94 sh8out_state<=bit3; 95 end 96 bit3:begin 97 link_write<=1; 98 sh8out_buf=sh8out_buf<<1; 99 sh8out_state<=bit2; 100 end 101 bit2:begin 102 link_write<=1; 103 sh8out_buf=sh8out_buf<<1; 104 sh8out_state<=bit1; 105 end 106 bit1:begin 107 link_write<=1; 108 sh8out_buf=sh8out_buf<<1; 109 sh8out_state<=bit0; 110 end 111 bit0:begin 112 link_write<=0; 113 finish_F<=1; 114 end 115 endcase 116 end 117 endtask 118 endmodule
測試程序:
1 `timescale 1ns/1ns 2 `define clk_period 50 3 module parallel_to_serial_test; 4 reg rst,clk; 5 reg [7:0]data,addr; 6 wire ack,sda; 7 wire [2:0]state; //main status, 8 wire [4:0]sh8out_state; 9 10 initial 11 begin 12 clk=0; 13 rst=1; 14 data=0; 15 addr=0; 16 #(2*`clk_period) rst=0; 17 #(2*`clk_period) rst=1; 18 #(100*`clk_period) $stop; 19 end 20 21 always #50 clk=~clk; 22 23 24 25 always @(posedge clk) 26 begin data=data+1; addr=addr+1; end 27 28 parallel_to_serial m( 29 .rst(rst), 30 .clk(clk), 31 .addr(addr), 32 .data(data), 33 .sda(sda), 34 .ack(ack) 35 ); 36 37 assign state=m.state; 38 assign sh8out_state=m.sh8out_state; 39 endmodule
波形信號: