
接口定义
状态机:
状态机涉及的变量有:
reg [3:0] cstate;
reg sda_r;
reg sda_link;
reg [3:0] num;
reg [7:0] db_r;
reg [7:0] read_data;
没有仿真、没有下载测试。解决方法:可以从杨老师那里自己焊一个板子来试验。
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 09:36:37 11/15/2010
// Design Name:
// Module Name: i2c
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module i2c(clk,rst_n,bu1,bu2,scl,sda,out_data);
input clk,rst_n,bu1,bu2; //bu1:按下执行写入.bu2:按下执行读取.
output scl;
output [7:0] out_data;
inout sda;
//按键部分
reg [19:0] cnt_20ms; //20ms的定时器
reg bu1_r,bu2_r;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt_20ms <= 1'b0;
else
cnt_20ms <= cnt_20ms + 1'd1;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
bu1_r <= 1'b0;
bu1_r <= 1'b0;
end
else if(cnt_20ms == 20'hf_ffff)
begin
bu1_r <= bu1;
bu2_r <= bu2;
end
//分频中的计数
reg [8:0] cnt_delay;
reg [2:0] cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt_delay <= 1'd0;
else if(cnt_delay == 9'd499)
cnt_delay <= 1'd0;
else
cnt_delay <= cnt_delay+1;
//获取捕捉的点
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 3'd5;
else
begin
case(cnt_delay)
9'd125: cnt <= 3'd1; //高电片的中间时刻
9'd249: cnt <= 3'd2; //下降沿
9'd375: cnt <= 3'd3; //低电平的中间时刻
9'd499: cnt <= 3'd0; //上升沿
default: cnt <= 3'd5;
endcase
end
`define scl_pos (cnt == 3'd0)
`define scl_high (cnt == 3'd1)
`define scl_neg (cnt == 3'd2)
`define scl_low (cnt == 3'd3)
//EEPRom时钟的产生
reg scl_r;
always @(posedge clk or negedge rst_n)
if(!rst_n)
scl_r <= 3'd0;
else if(`scl_pos)
scl_r <= 3'd1;
else if(`scl_neg)
scl_r <= 3'd0;
assign scl = scl_r;
//写入iic的地址和数据
`define DEVICE_READ 8'b1010_0001
`define DEVICE_WRITE 8'b1010_0000
`define WRITE_DATA 8'b1101_0001
`define BYTE_ADDR 8'b0000_0011
reg [7:0] db_r; //数据寄存器,存放要发送的地址或数据
reg [7:0] read_data;
//写入、?慈?iic的状态机
parameter IDLE = 4'd0;
parameter START1 = 4'd1;
parameter ADD1 = 4'd2;
parameter ACK1 = 4'd3;
parameter ADD2 = 4'd4;
parameter ACK2 = 4'd5;
parameter START2 = 4'd6;
parameter ADD3 = 4'd7;
parameter ACK3 = 4'd8;
parameter DATA = 4'd9;
parameter ACK4 = 4'd10;
parameter STOP1 = 4'd11;
parameter STOP2 = 4'd12;
reg [3:0] cstate;
reg sda_r;
reg sda_link;
reg [3:0] num; //用来计量地址或数据的位数
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
cstate <= IDLE;
sda_r <= 1'b1;
sda_link <= 1'b0;
num <= 4'd0;
read_data <= 8'd0;
end
else
begin
case(cstate)
IDLE:
begin
sda_link <= 1'b1;
sda_r <= 1'b1;
if(bu1 || bu2)
begin
db_r <= `DEVICE_WRITE;
cstate <= START1;
end
else
cstate <= IDLE;
end
START1:
begin
if(`scl_high)
begin
sda_link <= 1'b1;
sda_r <= 0; //产生下降沿,产生起始信号
cstate <= ADD1;
num <= 1'b0;
end
else
cstate <= START1;
end
ADD1:
begin
if(`scl_low)
if(num == 4'd8)
begin
num <= 4'd0;
sda_r <= 1'b1;
sda_link <= 1'b0;
cstate <= ACK1;
end
else
begin
cstate <= ADD1;
num <= num + 1'b1;
case(num)
4'd0: sda_r <= db_r[7];
4'd1: sda_r <= db_r[6];
4'd2: sda_r <= db_r[5];
4'd3: sda_r <= db_r[4];
4'd4: sda_r <= db_r[3];
4'd5: sda_r <= db_r[2];
4'd6: sda_r <= db_r[1];
4'd7: sda_r <= db_r[0];
default: ;
endcase
end
else
cstate <= ADD1;
end
ACK1:
begin
if(`scl_neg)
begin
cstate <= ADD2;
db_r <= `BYTE_ADDR;
end
else
cstate <= ACK1;
end
ADD2:
begin
if(`scl_low)
if(num == 4'd8)
begin
num <= 4'd0;
sda_r <= 1'b1;
sda_link <= 1'b0;
cstate <= ACK2;
end
else
begin
cstate <= ADD2;
num <= num + 1'b1;
case(num)
4'd0: sda_r <= db_r[7];
4'd1: sda_r <= db_r[6];
4'd2: sda_r <= db_r[5];
4'd3: sda_r <= db_r[4];
4'd4: sda_r <= db_r[3];
4'd5: sda_r <= db_r[2];
4'd6: sda_r <= db_r[1];
4'd7: sda_r <= db_r[0];
default: ;
endcase
end
else
cstate <= ADD2;
end
ACK2:
begin
if(`scl_neg)
begin
if(bu1_r)
begin
cstate <= DATA;
db_r <= `WRITE_DATA;
end
else if(bu2_r)
begin
cstate <= START2;
db_r <= `DEVICE_READ;
end
end
else
cstate <= ACK2;
end
START2:
begin
if(`scl_high)
begin
sda_r <= 1'b0;
cstate <= ADD3;
end
else
begin
sda_link <= 1'b1;
sda_r <= 1'b1;
cstate <= START2;
end
end
ADD3:
begin
if(`scl_low)
if(num == 4'd8)
begin
num <= 4'd0;
sda_r <= 1'b1;
sda_link <= 1'b0;
cstate <= ACK3;
end
else
begin
cstate <= ADD2;
num <= num + 1'b1;
case(num)
4'd0: sda_r <= db_r[7];
4'd1: sda_r <= db_r[6];
4'd2: sda_r <= db_r[5];
4'd3: sda_r <= db_r[4];
4'd4: sda_r <= db_r[3];
4'd5: sda_r <= db_r[2];
4'd6: sda_r <= db_r[1];
4'd7: sda_r <= db_r[0];
default: ;
endcase
end
else
cstate <= ADD2;
end
ACK3:
begin
if(`scl_neg)
begin
cstate <= DATA;
sda_link <= 1'b0;
end
else
cstate <= ACK2;
end
DATA:
begin
if(bu2_r)
begin
if(num <=7)
begin
cstate <= DATA;
if(`scl_high)
begin
num <= num + 1'b1;
case(num)
4'd0: sda_r <= db_r[7];
4'd1: sda_r <= db_r[6];
4'd2: sda_r <= db_r[5];
4'd3: sda_r <= db_r[4];
4'd4: sda_r <= db_r[3];
4'd5: sda_r <= db_r[2];
4'd6: sda_r <= db_r[1];
4'd7: sda_r <= db_r[0];
default: ;
endcase
end
end
else if(`scl_low && num == 4'd8)
begin
num <= 4'd0;
cstate <= ACK4;
end
else
cstate <= DATA;
end
else if(bu1_r)
begin
sda_link <= 1'b1;
if(num <=7)
begin
cstate <= DATA;
if(`scl_high)
begin
sda_link <= 1'b1;
num <= num + 1'b1;
case(num)
4'd0: sda_r <= db_r[7];
4'd1: sda_r <= db_r[6];
4'd2: sda_r <= db_r[5];
4'd3: sda_r <= db_r[4];
4'd4: sda_r <= db_r[3];
4'd5: sda_r <= db_r[2];
4'd6: sda_r <= db_r[1];
4'd7: sda_r <= db_r[0];
default: ;
endcase
end
end
else if(`scl_low && num == 4'd8)
begin
num <= 4'd0;
cstate <= ACK4;
end
else
cstate <= DATA;
end
end
//end
ACK4:
begin
if(`scl_neg)
cstate <= STOP1;
else
cstate <= ACK4;
end
STOP1:
begin
if(`scl_low)
begin
sda_link <= 1'b1;
sda_r <= 1'b0;
cstate <= STOP1;
end
else if(`scl_high)
begin
sda_r <= 1'b1;
cstate <= STOP2;
end
end
STOP2:
if(`scl_low)
sda_r <= 1'b1;
else if(cnt_20ms == 20'hfffff)
cstate <= IDLE;
else
cstate <= STOP2;
default: cstate <= IDLE;
endcase
end
assign sda = sda_link? sda_r:1'bz;
assign out_data = read_data;
endmodule
