升腾A7pro的EEPROM芯片为24C64芯片,器件地址为1010_011。
(1)Visio整体设计视图(IIC_SCL为250KHz,IIC_CLK为1MHz,addr_num为1,地址字节数为2字节,addr_num为0,地址字节数为1字节):
(2)IIC_ctrl模块状态转移图:
(3)按键消抖模块代码及注释解析:
module key_filter(clk,reset_n,key_in,key_p_flag,key_r_flag,key_state);
input clk;
input reset_n;
input key_in;
output reg key_p_flag;
output reg key_r_flag;
output reg key_state;
reg key_in1;
reg key_in2;
reg key_in3;
reg [3:0]STATE;
//抖动时间往往小于20ms,20ms = 20_000_000ns = 20ns * 1_000_000; (1_000_000)D = (1111_0100_0010_0100_0000)B 需要一个20位的寄存器,用于计数
reg [19:0]cnt_20ms;
reg en_cnt_20ms;
wire podge;
wire nedge;
wire arrive_time_20ms;
//状态设计
parameter IDLE = 4'b0001; //释放稳定状态
parameter P_SHAKE = 4'b0010; //按下抖动状态
parameter DOWN = 4'b0100; //按下稳定状态
parameter R_SHAKE = 4'b1000; //释放抖动状态
parameter CNT_MAX = 20'd999_999;
//异步输入key_in 信号的同步化————“打两拍”
always@(posedge clk)begin
key_in1 <= key_in;
key_in2 <= key_in1;
end
//上升沿、下降沿设计
always@(posedge clk)
key_in3 <= key_in2;
assign podge = key_in2 && (!key_in3); //上升沿
assign nedge = (!key_in2) && key_in3; //下降沿
//20ms计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt_20ms <= 20'd0;
else if(en_cnt_20ms &&(cnt_20ms == CNT_MAX))
cnt_20ms <= 20'd0;
else if(en_cnt_20ms)
cnt_20ms <= cnt_20ms + 20'd1;
else
cnt_20ms <= 20'd0;
//计满20ms信号设计
assign arrive_time_20ms = (cnt_20ms == CNT_MAX);
//状态机主程序设计
always@(posedge clk or negedge reset_n)
if(!reset_n)begin
key_r_flag <= 1'd0;
key_p_flag <= 1'd0;
key_state <= 1'd1;
STATE <= IDLE;
en_cnt_20ms <= 1'd0;
end
else begin
case(STATE)
IDLE:begin
key_r_flag <= 1'd0;
key_state <= 1'd1;
if(nedge)begin
STATE <= P_SHAKE;
en_cnt_20ms <= 1'd1;
end
else
STATE <= STATE;
end
P_SHAKE:begin
if(arrive_time_20ms)begin
STATE <= DOWN;
en_cnt_20ms <= 1'd0;
key_p_flag <= 1'd1;
key_state <= 1'd0;
end
else if(podge)begin
STATE <= IDLE;
en_cnt_20ms <= 1'd0;
end
else
STATE <= STATE;
end
DOWN:begin
key_p_flag <= 1'd0;
key_state <= 1'd0;
if(podge)begin
STATE <= R_SHAKE;
en_cnt_20ms <= 1'd1;
end
else
STATE <= STATE;
end
R_SHAKE:begin
if(arrive_time_20ms)begin
STATE <= IDLE;
en_cnt_20ms <= 1'd0;
key_r_flag <= 1'd1;
key_state <= 1'd1;
end
else if(nedge)begin
STATE <= DOWN;
en_cnt_20ms <= 1'd0;
end
else
STATE <= STATE;
end
default:begin
key_r_flag <= 1'd0;
key_p_flag <= 1'd0;
key_state <= 1'd1;
STATE <= IDLE;
end
endcase
end
endmodule
(4)IIC_ctrl模块Verilog代码:
module IIC_ctrl(
input wire clk ,
input wire reset_n ,
input wire IIC_start ,
input wire wr_en ,
input wire rd_en ,
input wire [15:0] byte_addr ,
input wire [7:0] wr_data ,
input wire addr_num ,
output reg IIC_SCL ,
inout wire IIC_SDA ,
output reg IIC_clk ,
output reg IIC_end ,
output reg [7:0] rd_data
);
reg [4:0] cnt_1M ; //计数最大值是25 一个五位宽的寄存器足以胜任计数任务
reg [15:0] state ;
reg [1:0] IIC_clk_cnt ;
reg EN_IIC_clk_cnt ;
reg [2:0] bit_cnt ;
reg ack ;
reg sda_out ;
reg [7:0] rd_data_reg ;
wire sda_in ;
wire EN_IIC_SDA ;
parameter IDLE = 16'b0000_0000_0000_0001 ; //空闲状态
parameter START = 16'b0000_0000_0000_0010 ; //发送开始信号
parameter SEND_D_A = 16'b0000_0000_0000_0100 ; //发送控制命令(器件地址+写操作) {7'b1010_011,1'b0}
parameter ACK_1 = 16'b0000_0000_0000_1000 ; //等待响应
parameter SEND_B_H = 16'b0000_0000_0001_0000 ; //发送存储地址高8位
parameter ACK_2 = 16'b0000_0000_0010_0000 ; //等待响应
parameter SEND_B_L = 16'b0000_0000_0100_0000 ; //发送存储地址低8位
parameter ACK_3 = 16'b0000_0000_1000_0000 ; //等待响应
parameter WR_DATA = 16'b0000_0001_0000_0000 ; //写入单比特数据
parameter ACK_4 = 16'b0000_0010_0000_0000 ; //等待响应
parameter START_2 = 16'b0000_0100_0000_0000 ; //发送开始信号
parameter SEND_RD_A = 16'b0000_1000_0000_0000 ; //发送控制命令(器件地址+读操作) {7'b0101_011,1'b1}
parameter ACK_5 = 16'b0001_0000_0000_0000 ; //等待响应
parameter RD_DATA = 16'b0010_0000_0000_0000 ; //读出单比特数据
parameter NO_ACK = 16'b0100_0000_0000_0000 ; //等待无响应信号
parameter END = 16'b1000_0000_0000_0000 ; //结束单比特传输
parameter DEVICE_ADD = 7'b1010_011 ; //EEPROM器件地址设定
/*-----------IIC_clk生成模块--------------------*/
//IIC_clk 频率要求1MHz,而系统时钟clk频率为50MHz,半个周期需要计数25次(5位寄存器)
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt_1M <= 5'd0;
else if(cnt_1M == 5'd24)
cnt_1M <= 5'd0;
else
cnt_1M <= cnt_1M + 5'd1;
always@(posedge clk or negedge reset_n)
if(!reset_n)
IIC_clk <= 1'd0;
else if(cnt_1M == 5'd24)
IIC_clk <= ~IIC_clk;
else
IIC_clk <= IIC_clk;
/*----------------状态机设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
if(!reset_n)
state <= IDLE;
else begin
case(state)
IDLE :
if(IIC_start)
state <= START;
else
state <= state;
START :
if(IIC_clk_cnt == 2'd3)
state <= SEND_D_A;
else
state <= state;
SEND_D_A :
if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
state <= ACK_1;
else
state <= state;
ACK_1 :
if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (addr_num == 1'd1))
state <= SEND_B_H;
else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (addr_num == 1'd0))
state <= SEND_B_L;
else
state <= state;
SEND_B_H :
if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
state <= ACK_2;
else
state <= state;
ACK_2 :
if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
state <= SEND_B_L;
else
state <= state;
SEND_B_L :
if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
state <= ACK_3;
else
state <= state;
ACK_3 :
if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (wr_en == 1'd1))
state <= WR_DATA;
else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (rd_en == 1'd1))
state <= START_2;
else
state <= state;
WR_DATA :
if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
state <= ACK_4;
else
state <= state;
ACK_4 :
if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
state <= END;
else
state <= state;
START_2 :
if(IIC_clk_cnt == 2'd3)
state <= SEND_RD_A;
else
state <= state;
SEND_RD_A :
if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
state <= ACK_5;
else
state <= state;
ACK_5 :
if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
state <= RD_DATA;
else
state <= state;
RD_DATA :
if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
state <= NO_ACK;
else
state <= state;
NO_ACK :
if(IIC_clk_cnt == 2'd3)
state <= END;
else
state <= state;
END :
if((bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
state <= IDLE;
else
state <= state;
default : state <= IDLE;
endcase
end
/*----------------IIC_clk_cnt 、 EN_IIC_clk_cnt设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
if(!reset_n)
IIC_clk_cnt <= 2'd0;
else if(!EN_IIC_clk_cnt)
IIC_clk_cnt <= 2'd0;
else
IIC_clk_cnt <= IIC_clk_cnt + 2'd1;
always@(posedge IIC_clk or negedge reset_n)
if(!reset_n)
EN_IIC_clk_cnt <= 1'd0;
else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
EN_IIC_clk_cnt <= 1'd0;
else if(IIC_start)
EN_IIC_clk_cnt <= 1'd1;
else
EN_IIC_clk_cnt <= EN_IIC_clk_cnt;
/*--------------------bit_cnt设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
if(!reset_n)
bit_cnt <= 3'd0;
else if((state == IDLE)||(state == START)||(state == ACK_1)
||(state == ACK_2)||(state == ACK_3)||(state == ACK_4)
||(state == START_2)||(state == ACK_5)||(state == NO_ACK))
bit_cnt <= 3'd0;
else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
bit_cnt <= 3'd0;
else if(IIC_clk_cnt == 2'd3)
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
/*--------------------ack 、 sda_in信号设计---------------------------*/
always@(*)
begin
case(state)
ACK_1,ACK_2,ACK_3,ACK_4,ACK_5 : if(IIC_clk_cnt == 2'd0)
ack <= sda_in ;
else
ack <= ack ;
default : ack = 1'd1;
endcase
end
assign sda_in = IIC_SDA ;
/*--------------------IIC_SCL设计-----------------------*/
always@(*)
begin
case(state)
IDLE:
IIC_SCL <= 1'd1;
START:
if(IIC_clk_cnt == 2'd3)
IIC_SCL <= 1'd0;
else
IIC_SCL <= 1'd1;
SEND_D_A,ACK_1,SEND_B_H,ACK_2,SEND_B_L,ACK_3,WR_DATA,
ACK_4,START_2,SEND_RD_A,ACK_5,RD_DATA,NO_ACK:
if((IIC_clk_cnt == 2'd1) || (IIC_clk_cnt == 2'd2))
IIC_SCL <= 1'd1;
else
IIC_SCL <= 1'd0;
END:
if((bit_cnt == 3'd0) && (IIC_clk_cnt == 2'd0))
IIC_SCL <= 1'd0;
else
IIC_SCL <= 1'd1;
default:
IIC_SCL <= 1'd1;
endcase
end
/*--------------------sda_out 、 rd_data_reg设计-----------------------*/
always@(*)
begin
case(state)
IDLE :begin
sda_out <= 1'd1;
rd_data_reg <= 8'd0;
end
START :
if(IIC_clk_cnt >= 2'd1)
sda_out <= 1'd0;
else
sda_out <= 1'd1;
SEND_D_A :
if(bit_cnt <= 3'd6)
sda_out <= DEVICE_ADD[6 - bit_cnt];
else
sda_out <= 1'd0;
ACK_1,ACK_2,ACK_3,ACK_4,ACK_5 :
sda_out <= 1'd1;
SEND_B_H :
sda_out <= byte_addr[15-bit_cnt];
SEND_B_L :
sda_out <= byte_addr[7-bit_cnt];
WR_DATA :
sda_out <= wr_data[7-bit_cnt];
START_2 :
if(IIC_clk_cnt >= 2'd2)
sda_out <= 1'd0;
else
sda_out <= 1'd1;
SEND_RD_A :
if(bit_cnt <= 3'd6)
sda_out <= DEVICE_ADD[6 - bit_cnt];
else
sda_out <= 1'd1;
RD_DATA :begin
sda_out <= 1'd1;
if(IIC_clk_cnt == 2'd2)
rd_data_reg[7 - bit_cnt] <= sda_in;
else
rd_data_reg <= rd_data_reg;
end
NO_ACK :
sda_out <= 1'd1;
END :
if((bit_cnt == 3'd0) && (IIC_clk_cnt <= 2'd2))
sda_out <= 1'd0;
else
sda_out <= 1'd1;
default :begin
sda_out <= 1'd1;
rd_data_reg <= rd_data_reg;
end
endcase
end
/*--------------------rd_data设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
if(!reset_n)
rd_data <= 8'd0;
else if((state == RD_DATA) && (bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
rd_data <= rd_data_reg;
else
rd_data <= rd_data;
/*--------------------EN_IIC_SDA设计-----------------------*/
//EN_IIC_SDA信号为1,表示IIC_SDA输出;反之,EN_IIC_SDA信号为0,表示IIC_SDA作为输入.
assign EN_IIC_SDA = ((state == IDLE) || (state == START) || (state == SEND_D_A)
|| (state == SEND_B_H) || (state == SEND_B_L) || (state == WR_DATA)
|| (state == START_2) || (state == SEND_RD_A) || (state == NO_ACK)
|| (state == END));
/*--------------------IIC_SDA设计-----------------------*/
assign IIC_SDA = EN_IIC_SDA ? sda_out : 1'dz;
/*--------------------IIC_end设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)
if(!reset_n)
IIC_end <= 1'd0;
else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
IIC_end <= 1'd1;
else
IIC_end <= 1'd0;
endmodule