|
`timescale 1ns / 1ps
module iic_top(clk,rst_n,sw1,sw2,scl,sda,led_d2,led_d3,led_d4,led_d5);
input clk; // 4m
input rst_n; //复位信号,低有效
input sw1,sw2;
output scl; // 24C02的时钟端口
inout sda; // 24C02的数据端口
output led_d2,led_d3,led_d4,led_d5; //四个LED灯
//--------------------------------------------
//按键检测
reg sw1_r,sw2_r; //每20ms检测一次键值
reg[19:0] cnt_20ms;
always @ (posedge clk or negedge rst_n)
if(!rst_n) cnt_20ms <= 20'd0;
else cnt_20ms <= cnt_20ms+1'b1;
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
sw1_r <= 1'b1;
sw2_r <= 1'b1;
end
else if(cnt_20ms == 20'h0000f) begin
sw1_r <= sw1;
sw2_r <= sw2;
end
//---------------------------------------------
//分频部分
reg[2:0] cnt; //cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl低电平中间
reg[12:0] cnt_delay; //
reg scl_r; //时钟脉冲寄存器
always @ (posedge clk)
if(!rst_n) cnt_delay <= 13'd0;
else if(cnt_delay==13'd400) cnt_delay <= 13'd0; //产生iic所需要的时钟
else cnt_delay <= cnt_delay+1'b1;
always @ (posedge clk ) begin
if(!rst_n) cnt <= 2'd0;
else begin
case (cnt_delay)
13'd99: cnt <= 3'd1;
13'd199: cnt <= 3'd2;
13'd299: cnt <= 3'd3;
13'd399: cnt <= 3'd0;
default: cnt <= 3'd5;
endcase
end
end
always @ (posedge clk) begin //posedge clk or negedge rst_n
if(!rst_n) scl_r <= 1'b0;
else if(cnt==3'd0) scl_r <= 1'b1;
else if(cnt==3'd2) scl_r <= 1'b0;
else scl_r <= scl_r;
end
//assign scl = scl_r ? 1'b1:1'b0; //产生iic所需要的时钟
assign scl=scl_r;
//---------------------------------------------
//需要写入24C02的地址和数据
reg[7:0] device_add; //最低bit:1--读,0--写
parameter device_read = 8'b1010_0001;
parameter device_write = 8'b1010_0000;
reg[7:0] byte_add; // 写入地址
reg[7:0] byte_data1; //写入的数据
reg[7:0] byte_data2; //读出的数据
//---------------------------------------------
//读、写时序
parameter IDLE = 12'b000000000001;
parameter START1 = 12'b000000000010;
parameter ADD1 = 12'b000000000100;
parameter ACK1 = 12'b000000001000;
parameter ADD2 = 12'b000000010000;
parameter ACK2 = 12'b000000100000;
parameter START2 = 12'b000001000000;
parameter ADD3 = 12'b000010000000;
parameter ACK3 = 12'b000100000000;
parameter DATA = 12'b001000000000;
parameter ACK4 = 12'b010000000000;
parameter STOP = 12'b100000000000;
reg[11:0] current_state,next_state;
reg sda_r,sda_link; //输出数据寄存器
reg[3:0] num;
reg ack_bit; //响应位寄存器
always @ (next_state or rst_n) //posedge clk or negedge rst_n
if(!rst_n) current_state <= IDLE;
else current_state <= next_state;
always @ (posedge clk or negedge rst_n) begin ////rst_n or current_state or sw1_r or sw2_r or cnt
if(!rst_n) begin
next_state <= IDLE;
sda_r <= 1'b1;
sda_link <= 1'b0;
num <= 4'd0;
byte_data2 <= 8'b0000_0000;
ack_bit <= 1'b1;
byte_add <= 8'b0000_0001; // 0地址
byte_data1 <= 8'b0001_1101; //写入的数据,低四位1001
device_add <= 8'b0000_0000;
end
else
case (current_state)
IDLE: begin
sda_link <= 1'b0;
if((!sw1_r || !sw2_r) && cnt==3'd1) begin
device_add <= device_write;
next_state <= START1;
sda_link <= 1'b1;
sda_r <= 1'b1;
end
else next_state <= IDLE;
end
START1: begin
if(cnt==3'd1) begin
sda_r <= 1'b0;
next_state <= ADD1;
num <= 4'd0;
end
else next_state <= START1;
end
ADD1: begin
if(num<=4'd7) begin
next_state <= ADD1;
if(cnt==3'd3) begin
num <= num+1'b1;
sda_r <= device_add[7];
end
else if(cnt==3'd0) begin
device_add <= {device_add[6:0],device_add[7]};
end
end
else if((num==4'd8) && (cnt==3'd3)) begin
device_add <= {device_add[6:0],device_add[7]};//
num <= 4'd0;
sda_link <= 1'b0; //sda置为高阻态
next_state <= ACK1;
end
else next_state <= ADD1;
end
ACK1: begin
if(cnt==3'd2) begin
next_state <= ADD2;
end
else next_state <= ACK1;
end
ADD2: begin
if(num<=4'd7) begin
next_state <= ADD2;
if(cnt==3'd3) begin
sda_link <= 1'b1;
num <= num+1'b1;
sda_r <= byte_add[7];
end
else if(cnt==3'd0) begin
byte_add <= {byte_add[6:0],byte_add[7]};
end
end
else if((num==4'd8) && (cnt==3'd3)) begin
byte_add <= {byte_add[6:0],byte_add[7]};//
num <= 4'd0;
sda_link <= 1'b0; //sda置为高阻态
next_state <= ACK2;
if(!sw1_r) device_add <= device_write;
else if(!sw2_r) device_add <= device_read;
end
else next_state <= ADD2;
end
ACK2: begin
if(cnt==3'd2) begin
case (device_add[0])
1'b1: next_state <= START2; //读操作
1'b0: next_state <= DATA; //写操作
default: ;
endcase
end
else next_state <= ACK2;
end
START2: begin
if(cnt==3'd3) begin
sda_link <= 1'b1;
sda_r <= 1'b1;
end
else if(cnt==3'd1) begin
sda_r <= 1'b0;
next_state <= ADD3;
end
end
ADD3: begin
if(num<=4'd7) begin
next_state <= ADD3;
if(cnt==3'd3) begin
num <= num+1'b1;
sda_r <= device_add[7];
end
else if(cnt==3'd0) begin
device_add <= {device_add[6:0],device_add[7]};
end
end
else if((num==4'd8) && (cnt==3'd3)) begin
device_add <= {device_add[6:0],device_add[7]};
num <= 4'd0;
sda_link <= 1'b0; //sda_r置为高阻态
next_state <= ACK3;
end
else next_state <= ADD3;
end
ACK3: begin
if(cnt==3'd3) begin
next_state <= DATA;
end
else next_state <= ACK3;
end
DATA: begin
if(!sw2_r) begin //读
if(num<=4'd7) begin
next_state <= DATA;
if(cnt==3'd1) begin
num <= num+1'b1;
byte_data2[7] <= sda;
end
else if(cnt==3'd2) begin
byte_data2 <= {byte_data2[6:0],byte_data2[7]};
end
end
else if((cnt==3'd3) && (num==4'd8)) begin
byte_data2 <= {byte_data2[6:0],byte_data2[7]};
num <= 4'd0;
next_state <= ACK4;
end
else next_state <= DATA;
end
else begin //写
if(num<=4'd7) begin
next_state <= DATA;
if(cnt==3'd3) begin
sda_link <= 1'b1;
num <= num+1'b1;
sda_r <= byte_data1[7];
end
else if(cnt==3'd0) begin
byte_data1 <= {byte_data1[6:0],byte_data1[7]};
end
end
else if((cnt==3'd3) && (num==4'd8)) begin
byte_data1 <= {byte_data1[6:0],byte_data1[7]};
num <= 4'd0;
sda_link <= 1'b0; //sda置为高阻态
next_state <= ACK4;
end
else next_state <= DATA;
end
end
ACK4: begin
if(cnt==3'd3) begin
sda_r <= 1'b0;
sda_link <= 1'b1;
next_state <= STOP;
end
else next_state <= ACK4;
end
STOP: begin
if(cnt==3'd1) begin
sda_r <= 1'b1;
end
else if((cnt==3'd3) && sda_link) sda_link <= 1'b0;
if(cnt_20ms==20'hffff0) next_state <= IDLE;
else next_state <= STOP;
end
default: ;
endcase
end
assign sda = sda_link ? sda_r:1'bz;
assign {led_d2,led_d3,led_d4,led_d5} = byte_data2[3:0];
//---------------------------------------------
//任务
task write_add1 //写地址1任务
case (num)
4'd0: sda_r <= device_write[7];
4'd1: sda_r <= device_write[6];
4'd2: sda_r <= device_write[5];
4'd3: sda_r <= device_write[4];
4'd4: sda_r <= device_write[3];
4'd5: sda_r <= device_write[2];
4'd6: sda_r <= device_write[1];
4'd7: sda_r <= device_write[0];
default: ;
endcase
endtask
task write_add2 begin //写地址2任务
case (num)
4'd0: sda_r <= byte_add[7];
4'd1: sda_r <= byte_add[6];
4'd2: sda_r <= byte_add[5];
4'd3: sda_r <= byte_add[4];
4'd4: sda_r <= byte_add[3];
4'd5: sda_r <= byte_add[2];
4'd6: sda_r <= byte_add[1];
4'd7: sda_r <= byte_add[0];
default: ;
endcase
end
endtask
task write_add3 begin //写地址3任务
case (num)
4'd0: sda_r <= device_read[7];
4'd1: sda_r <= device_read[6];
4'd2: sda_r <= device_read[5];
4'd3: sda_r <= device_read[4];
4'd4: sda_r <= device_read[3];
4'd5: sda_r <= device_read[2];
4'd6: sda_r <= device_read[1];
4'd7: sda_r <= device_read[0];
default: ;
endcase
end
endtask
task write_data begin //写数据任务
case (num)
4'd0: sda_r <= byte_data1[7];
4'd1: sda_r <= byte_data1[6];
4'd2: sda_r <= byte_data1[5];
4'd3: sda_r <= byte_data1[4];
4'd4: sda_r <= byte_data1[3];
4'd5: sda_r <= byte_data1[2];
4'd6: sda_r <= byte_data1[1];
4'd7: sda_r <= byte_data1[0];
default: ;
endcase
end
endtask
task read_data begin //写数据任务
case (num)
4'd0: byte_data2[7] <= sda;
4'd1: byte_data2[6] <= sda;
4'd2: byte_data2[5] <= sda;
4'd3: byte_data2[4] <= sda;
4'd4: byte_data2[3] <= sda;
4'd5: byte_data2[2] <= sda;
4'd6: byte_data2[1] <= sda;
4'd7: byte_data2[0] <= sda;
default: ;
endcase
end
endtask
endmodule |
阿莫论坛20周年了!感谢大家的支持与爱护!!
该献的血还是要献的。你不献他不献。难道让我去献? --- 出自坛友:lovejp1981
|