module i2c(clk,rst,data_in,scl,sda,wr_input,rd_input,lowbit,en,seg_data);
input clk,rst;
output scl;//I2C時鐘線
inout sda;//I2C數(shù)據(jù)線
input[3:0] data_in;//撥碼開關(guān)輸入想寫入EEPROM的數(shù)據(jù)
input wr_input;//要求寫的輸入
input rd_input;//要求讀的輸入
output lowbit; //輸出一個低電平給矩陣鍵盤的某一行
output[1:0] en;//數(shù)碼管使能
output[7:0] seg_data;//數(shù)碼管段數(shù)據(jù)
reg[7:0] seg_data;
reg scl;
reg[1:0] en;
reg[7:0] seg_data_buf;
reg[11:0] cnt_scan;
reg sda_buf;//sda輸入輸出數(shù)據(jù)緩存
reg link; //sda輸出標(biāo)志
reg phase0,phase1,phase2,phase3;//一個scl時鐘周期的四個相位階段,將一個scl周期分為4段
//phase0對應(yīng)scl的上升沿時刻,phase2對應(yīng)scl的下降沿時刻,phase1對應(yīng)從scl高電平的中間時刻,phase2對應(yīng)從scl低電平的中間時刻,
reg[7:0] clk_div;//分頻計數(shù)器
reg[1:0] main_state;
reg[2:0] i2c_state;//對i2c操作的狀態(tài)
reg[3:0] inner_state;//i2c每一操作階段內(nèi)部狀態(tài)
reg[19:0] cnt_delay;//按鍵延時計數(shù)器
reg start_delaycnt;//按鍵延時開始
reg[7:0] writeData_reg,readData_reg;//要寫的數(shù)據(jù)的寄存器和讀回數(shù)據(jù)的寄存器
reg[7:0] addr;//被操作的EEPROM字節(jié)的地址
parameter div_parameter=100;// 分頻系數(shù),AT24C02最大支持400K時鐘速率
parameter start=4'b0000, //開始
first=4'b0001, //第1位
second=4'b0010,//第2位
third=4'b0011, //第3位
fourth=4'b0100, //第4位
fifth=4'b0101, //第5位
sixth=4'b0110, //第6位
seventh=4'b0111, //第7位
eighth=4'b1000, //第8位
ack=4'b1001, //確認(rèn)位
stop=4'b1010; //結(jié)束位
parameter ini=3'b000, //初始化EEPROM狀態(tài)
sendaddr=3'b001, //發(fā)送地址狀態(tài)
write_data=3'b010, //寫數(shù)據(jù)狀態(tài)?
read_data=3'b011, //讀數(shù)據(jù)狀態(tài)
read_ini=6'b100; //發(fā)送讀信息狀態(tài)
assign lowbit=0;
assign sda=(link)? sda_buf:1'bz;
always@(posedge clk or negedge rst)
begin
if(!rst)
cnt_delay<=0;
else begin
if(start_delaycnt) begin
if(cnt_delay!=20'd800000)
cnt_delay<=cnt_delay+1;
else
cnt_delay<=0;
end
end
end
always@(posedge clk or negedge rst)
begin
if(!rst) begin
clk_div<=0;
phase0<=0;
phase1<=0;
phase2<=0;
phase3<=0;
end
else begin
if(clk_div!=div_parameter-1)
clk_div<=clk_div+1;
else
clk_div<=0;
if(phase0)
phase0<=0;
else if(clk_div==99)
phase0<=1;
if(phase1)
phase1<=0;
else if(clk_div==24)
phase1<=1;
if(phase2)
phase2<=0;
else if(clk_div==49)
phase2<=1;
if(phase3)
phase3<=0;
else if(clk_div==74)
phase3<=1;
end
end
///////////////////////////EEPROM操作部分/////////////
always@(posedge clk or negedge rst)
begin
if(!rst) begin
start_delaycnt<=0;
main_state<=2'b00;
i2c_state<=ini;
inner_state<=start;
scl<=1;
sda_buf<=1;
link<=0;
writeData_reg<=5;
readData_reg<=0;
addr<=10;
end
else begin
case(main_state)
2'b00: begin //等待讀寫要求
writeData_reg<=data_in;
scl<=1;
sda_buf<=1;
link<=0;
inner_state<=start;
i2c_state<=ini;
if((cnt_delay==0)&&(!wr_input||!rd_input))
start_delaycnt<=1;
else if(cnt_delay==20'd800000) begin
start_delaycnt<=0;
if(!wr_input)
main_state<=2'b01;
else if(!rd_input)
main_state<=2'b10;
end
end
2'b01: begin //向EEPROM寫入數(shù)據(jù)
if(phase0)
scl<=1;
else if(phase2)
scl<=0;
case(i2c_state)
ini: begin //初始化EEPROM
case(inner_state)
start: begin
if(phase1) begin
link<=1;
sda_buf<=0;
end
if(phase3&&link) begin
inner_state<=first;
sda_buf<=1;
link<=1;
end
end
first:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=second;
end
second:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=third;
end
third:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fourth;
end
fourth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fifth;
end
fifth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=sixth;
end
sixth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=seventh;
end
seventh:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=3'b000;
end
if(phase3) begin
link<=1;
sda_buf<=addr[7];
inner_state<=first;
i2c_state<=sendaddr;
end
end
endcase
end
sendaddr: begin //送相應(yīng)字節(jié)的地址
case(inner_state)
first:
if(phase3) begin
link<=1;
sda_buf<=addr[6];
inner_state<=second;
end
second:
if(phase3) begin
link<=1;
sda_buf<=addr[5];
inner_state<=third;
end
third:
if(phase3) begin
link<=1;
sda_buf<=addr[4];
inner_state<=fourth;
end
fourth:
if(phase3) begin
link<=1;
sda_buf<=addr[3];
inner_state<=fifth;
end
fifth:
if(phase3) begin
link<=1;
sda_buf<=addr[2];
inner_state<=sixth;
end
sixth:
if(phase3) begin
link<=1;
sda_buf<=addr[1];
inner_state<=seventh;
end
seventh:
if(phase3) begin
link<=1;
sda_buf<=addr[0];
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=3'b000;
end
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[7];
inner_state<=first;
i2c_state<=write_data;
end
end
endcase
end
write_data: begin //寫入數(shù)據(jù)
case(inner_state)
first:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[6];
inner_state<=second;
end
second:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[5];
inner_state<=third;
end
third:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[4];
inner_state<=fourth;
end
fourth:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[3];
inner_state<=fifth;
end
fifth:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[2];
inner_state<=sixth;
end
sixth:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[1];
inner_state<=seventh;
end
seventh:
if(phase3) begin
link<=1;
sda_buf<=writeData_reg[0];
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
else if(phase3) begin
link<=1;
sda_buf<=0;
inner_state<=stop;
end
end
stop: begin
if(phase1)
sda_buf<=1;
if(phase3)
main_state<=2'b00;
end
endcase
end
default:
main_state<=2'b00;
endcase
end
2'b10: begin //讀EEPROM
if(phase0)
scl<=1;
else if(phase2)
scl<=0;
case(i2c_state)
ini: begin //初始化EEPROM
case(inner_state)
start: begin
if(phase1) begin
link<=1;
sda_buf<=0;
end
if(phase3&&link) begin
inner_state<=first;
sda_buf<=1;
link<=1;
end
end
first:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=second;
end
second:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=third;
end
third:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fourth;
end
fourth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fifth;
end
fifth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=sixth;
end
sixth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=seventh;
end
seventh:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
if(phase3) begin
link<=1;
sda_buf<=addr[7];
inner_state<=first;
i2c_state<=sendaddr;
end
end
endcase
end
sendaddr: begin //送相應(yīng)要讀字節(jié)的地址
case(inner_state)
first:
if(phase3) begin
link<=1;
sda_buf<=addr[6];
inner_state<=second;
end
second:
if(phase3) begin
link<=1;
sda_buf<=addr[5];
inner_state<=third;
end
third:
if(phase3) begin
link<=1;
sda_buf<=addr[4];
inner_state<=fourth;
end
fourth:
if(phase3) begin
link<=1;
sda_buf<=addr[3];
inner_state<=fifth;
end
fifth:
if(phase3) begin
link<=1;
sda_buf<=addr[2];
inner_state<=sixth;
end
sixth:
if(phase3) begin
link<=1;
sda_buf<=addr[1];
inner_state<=seventh;
end
seventh:
if(phase3) begin
link<=1;
sda_buf<=addr[0];
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
if(phase3) begin
link<=1;
sda_buf<=1;
inner_state<=start;
i2c_state<=read_ini;
end
end
endcase
end
read_ini: begin //發(fā)出讀要求
case(inner_state)
start: begin
if(phase1) begin
link<=1;
sda_buf<=0;
end
if(phase3&&link) begin
inner_state<=first;
sda_buf<=1;
link<=1;
end
end
first:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=second;
end
second:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=third;
end
third:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fourth;
end
fourth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=fifth;
end
fifth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=sixth;
end
sixth:
if(phase3) begin
sda_buf<=0;
link<=1;
inner_state<=seventh;
end
seventh:
if(phase3) begin
sda_buf<=1;
link<=1;
inner_state<=eighth;
end
eighth:
if(phase3) begin
link<=0;
inner_state<=ack;
end
ack: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
if(sda_buf==1)
main_state<=2'b00;
end
if(phase3) begin
link<=0;
inner_state<=first;
i2c_state<=read_data;
end
end
endcase
end
read_data: begin //讀出數(shù)據(jù)
case(inner_state)
first: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=second;
end
second: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=third;
end
third: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=fourth;
end
fourth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=fifth;
end
fifth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=sixth;
end
sixth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=seventh;
end
seventh: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=eighth;
end
eighth: begin
if(phase0)
sda_buf<=sda;
if(phase1) begin
readData_reg[7:1]<=readData_reg[6:0];
readData_reg[0]<=sda;
end
if(phase3)
inner_state<=ack;
end
ack: begin
if(phase3) begin
link<=1;
sda_buf<=0;
inner_state<=stop;
end
end
stop: begin
if(phase1)
sda_buf<=1;
if(phase3)
main_state<=2'b00;
end
endcase
end
endcase
end
endcase
end
end
///////////////////////////數(shù)碼管顯示部分/////////////
always@(posedge clk or negedge rst)
begin
if(!rst) begin
cnt_scan<=0;
en<=2'b10;
end
else begin
cnt_scan<=cnt_scan+1;
if(cnt_scan==12'hfff)
en<=~en;
end
end
always@(writeData_reg or readData_reg or en)
begin
case(en)
2'b10:
seg_data_buf=writeData_reg;
2'b01:
seg_data_buf=readData_reg;
default:
seg_data_buf=0;
endcase
end
always@(seg_data_buf)
begin
case(seg_data_buf)
8'b0000_0000:
seg_data=8'b0000_0011;
8'b0000_0001:
seg_data=8'b1001_1111;
8'b0000_0010:
seg_data=8'b0010_0101;
8'b0000_0011:
seg_data=8'b0000_1101;
8'b0000_0100:
seg_data=8'b1001_1001;
8'b0000_0101:
seg_data=8'b0100_1001;
8'b0000_0110:
seg_data=8'b0100_0001;
8'b0000_0111:
seg_data=8'b0001_1111;
8'b0000_1000:
seg_data=8'b0000_0001;
8'b0000_1001:
seg_data=8'b0001_1001;
8'b0000_1010:
seg_data=8'b0001_0001;
8'b0000_1011:
seg_data=8'b1100_0001;
8'b0000_1100:
seg_data=8'b0110_0011;
8'b0000_1101:
seg_data=8'b1000_0101;
8'b0000_1110:
seg_data=8'b0110_0001;
8'b0000_1111:
seg_data=8'b0111_0001;
default:
seg_data=8'b1111_1111;
endcase
end
endmodule