基于FPGA的I2C实验Verilog源代码优选.docx
- 文档编号:26936920
- 上传时间:2023-06-24
- 格式:DOCX
- 页数:15
- 大小:17.97KB
基于FPGA的I2C实验Verilog源代码优选.docx
《基于FPGA的I2C实验Verilog源代码优选.docx》由会员分享,可在线阅读,更多相关《基于FPGA的I2C实验Verilog源代码优选.docx(15页珍藏版)》请在冰豆网上搜索。
基于FPGA的I2C实验Verilog源代码优选
`timescale1ns/1ps
modulei2c_drive(
clk,rst_n,
sw1,sw2,
scl,sda,
dis_data
);
inputclk;//50MHz
inputrst_n;//复位信号,低有效
inputsw1,sw2;//按键1、2,(1按下执行写入操作,2按下执行读操作)
outputscl;//24C02的时钟端口
inoutsda;//24C02的数据端口
output[7:
0]dis_data;//输出指定单元的数据
//--------------------------------------------
//按键检测
regsw1_r,sw2_r;//键值锁存寄存器,每20ms检测一次键值
reg[19:
0]cnt_20ms;//20ms计数寄存器
always@(posedgeclkornegedgerst_n)
if(!
rst_n)
cnt_20ms<=20'd0;
else
cnt_20ms<=cnt_20ms+1'b1;//不断计数
always@(posedgeclkornegedgerst_n)
if(!
rst_n)
begin
sw1_r<=1'b1;//键值寄存器复位,没有键盘按下时键值都为1
sw2_r<=1'b1;
end
elseif(cnt_20ms==20'hfffff)
begin
sw1_r<=sw1;//按键1值锁存
sw2_r<=sw2;//按键2值锁存
end
//---------------------------------------------
//分频部分
reg[2:
0]cnt;//cnt=0:
scl上升沿,cnt=1:
scl高电平中间,cnt=2:
scl下降沿,cnt=3:
scl低电平中间
reg[8:
0]cnt_delay;//500循环计数,产生iic所需要的时钟
regscl_r;//时钟脉冲寄存器
always@(posedgeclkornegedgerst_n)
if(!
rst_n)
cnt_delay<=9'd0;
elseif(cnt_delay==9'd499)
cnt_delay<=9'd0;//计数到10us为scl的周期,即100KHz
else
cnt_delay<=cnt_delay+1'b1;//时钟计数
always@(posedgeclkornegedgerst_n)begin
if(!
rst_n)
cnt<=3'd5;
else
begin
case(cnt_delay)
9'd124:
cnt<=3'd1;//cnt=1:
scl高电平中间,用于数据采样
9'd249:
cnt<=3'd2;//cnt=2:
scl下降沿
9'd374:
cnt<=3'd3;//cnt=3:
scl低电平中间,用于数据变化
9'd499:
cnt<=3'd0;//cnt=0:
scl上升沿
default:
cnt<=3'd5;
endcase
end
end
`defineSCL_POS(cnt==3'd0)//cnt=0:
scl上升沿
`defineSCL_HIG(cnt==3'd1)//cnt=1:
scl高电平中间,用于数据采样
`defineSCL_NEG(cnt==3'd2)//cnt=2:
scl下降沿
`defineSCL_LOW(cnt==3'd3)//cnt=3:
scl低电平中间,用于数据变化
always@(posedgeclkornegedgerst_n)
if(!
rst_n)
scl_r<=1'b0;
elseif(cnt==3'd0)
scl_r<=1'b1;//scl信号上升沿
elseif(cnt==3'd2)
scl_r<=1'b0;//scl信号下降沿
assignscl=scl_r;//产生iic所需要的时钟
//---------------------------------------------
//需要写入24C02的地址和数据
`defineDEVICE_READ8'b1010_0001//被寻址器件地址(读操作)
`defineDEVICE_WRITE8'b1010_0000//被寻址器件地址(写操作)
`defineWRITE_DATA8'b0000_0111//写入EEPROM的数据
`defineBYTE_ADDR8'b0000_0100//写入/读出EEPROM的地址寄存器
reg[7:
0]db_r;//在IIC上传送的数据寄存器
reg[7:
0]read_data;//读出EEPROM的数据寄存器
//---------------------------------------------
//读、写时序
parameterIDLE=4'd0;
parameterSTART1=4'd1;
parameterADD1=4'd2;
parameterACK1=4'd3;
parameterADD2=4'd4;
parameterACK2=4'd5;
parameterSTART2=4'd6;
parameterADD3=4'd7;
parameterACK3=4'd8;
parameterDATA=4'd9;
parameterACK4=4'd10;
parameterSTOP1=4'd11;
parameterSTOP2=4'd12;
reg[3:
0]cstate;//状态寄存器
regsda_r;//输出数据寄存器
regsda_link;//输出数据sda信号inout方向控制位
reg[3:
0]num;//
always@(posedgeclkornegedgerst_n)begin
if(!
rst_n)
begin
cstate<=IDLE;
sda_r<=1'b1;
sda_link<=1'b0;
num<=4'd0;
read_data<=8'b0000_0000;
end
else
case(cstate)
IDLE:
begin
sda_link<=1'b1;//数据线sda为input
sda_r<=1'b1;
if(!
sw1_r||!
sw2_r)
begin//SW1,SW2键有一个被按下
db_r<=`DEVICE_WRITE;//送器件地址(写操作)
cstate<=START1;
end
else
cstate<=IDLE;//没有任何键被按下
end
START1:
begin
if(`SCL_HIG)
begin//scl为高电平期间
sda_link<=1'b1;//数据线sda为output
sda_r<=1'b0;//拉低数据线sda,产生起始位信号
cstate<=ADD1;
num<=4'd0;//num计数清零
end
else
cstate<=START1;//等待scl高电平中间位置到来
end
ADD1:
begin
if(`SCL_LOW)
begin
if(num==4'd8)
begin
num<=4'd0;//num计数清零
sda_r<=1'b1;
sda_link<=1'b0;//sda置为高阻态(input)
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
//sda_r<=db_r[4'd7-num];//送器件地址,从高位开始
end
end
//elseif(`SCL_POS)db_r<={db_r[6:
0],1'b0};//器件地址左移1bit
else
cstate<=ADD1;
end
ACK1:
begin
if(/*!
sda*/`SCL_NEG)
begin//注:
24C01/02/04/08/16器件可以不考虑应答位
cstate<=ADD2;//从机响应信号
db_r<=`BYTE_ADDR;//1地址
end
else
cstate<=ACK1;//等待从机响应
end
ADD2:
begin
if(`SCL_LOW)
begin
if(num==4'd8)
begin
num<=4'd0;//num计数清零
sda_r<=1'b1;
sda_link<=1'b0;//sda置为高阻态(input)
cstate<=ACK2;
end
else
begin
sda_link<=1'b1;//sda作为output
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
//sda_r<=db_r[4'd7-num];//送EEPROM地址(高bit开始)
cstate<=ADD2;
end
end
//elseif(`SCL_POS)db_r<={db_r[6:
0],1'b0};//器件地址左移1bit
else
cstate<=ADD2;
end
ACK2:
begin
if(/*!
sda*/`SCL_NEG)begin//从机响应信号
if(!
sw1_r)begin
cstate<=DATA;//写操作
db_r<=`WRITE_DATA;//写入的数据
end
elseif(!
sw2_r)begin
db_r<=`DEVICE_READ;//送器件地址(读操作),特定地址读需要执行该步骤以下操作
cstate<=START2;//读操作
end
end
elsecstate<=ACK2;//等待从机响应
end
START2:
begin//读操作起始位
if(`SCL_LOW)begin
sda_link<=1'b1;//sda作为output
sda_r<=1'b1;//拉高数据线sda
cstate<=START2;
end
elseif(`SCL_HIG)begin//scl为高电平中间
sda_r<=1'b0;//拉低数据线sda,产生起始位信号
cstate<=ADD3;
end
elsecstate<=START2;
end
ADD3:
begin//送读操作地址
if(`SCL_LOW)begin
if(num==4'd8)begin
num<=4'd0;//num计数清零
sda_r<=1'b1;
sda_link<=1'b0;//sda置为高阻态(input)
cstate<=ACK3;
end
elsebegin
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
//sda_r<=db_r[4'd7-num];//送EEPROM地址(高bit开始)
cstate<=ADD3;
end
end
//elseif(`SCL_POS)db_r<={db_r[6:
0],1'b0};//器件地址左移1bit
elsecstate<=ADD3;
end
ACK3:
begin
if(/*!
sda*/`SCL_NEG)begin
cstate<=DATA;//从机响应信号
sda_link<=1'b0;
end
elsecstate<=ACK3;//等待从机响应
end
DATA:
begin
if(!
sw2_r)begin//读操作
if(num<=4'd7)begin
cstate<=DATA;
if(`SCL_HIG)begin
num<=num+1'b1;
case(num)
4'd0:
read_data[7]<=sda;
4'd1:
read_data[6]<=sda;
4'd2:
read_data[5]<=sda;
4'd3:
read_data[4]<=sda;
4'd4:
read_data[3]<=sda;
4'd5:
read_data[2]<=sda;
4'd6:
read_data[1]<=sda;
4'd7:
read_data[0]<=sda;
default:
;
endcase
//read_data[4'd7-num]<=sda;//读数据(高bit开始)
end
//elseif(`SCL_NEG)read_data<={read_data[6:
0],read_data[7]};//数据循环右移
end
elseif((`SCL_LOW)&&(num==4'd8))begin
num<=4'd0;//num计数清零
cstate<=ACK4;
end
elsecstate<=DATA;
end
elseif(!
sw1_r)begin//写操作
sda_link<=1'b1;
if(num<=4'd7)begin
cstate<=DATA;
if(`SCL_LOW)begin
sda_link<=1'b1;//数据线sda作为output
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
//sda_r<=db_r[4'd7-num];//写入数据(高bit开始)
end
//elseif(`SCL_POS)db_r<={db_r[6:
0],1'b0};//写入数据左移1bit
end
elseif((`SCL_LOW)&&(num==4'd8))begin
num<=4'd0;
sda_r<=1'b1;
sda_link<=1'b0;//sda置为高阻态
cstate<=ACK4;
end
elsecstate<=DATA;
end
end
ACK4:
begin
if(/*!
sda*/`SCL_NEG)begin
//sda_r<=1'b1;
cstate<=STOP1;
end
elsecstate<=ACK4;
end
STOP1:
begin
if(`SCL_LOW)begin
sda_link<=1'b1;
sda_r<=1'b0;
cstate<=STOP1;
end
elseif(`SCL_HIG)begin
sda_r<=1'b1;//scl为高时,sda产生上升沿(结束信号)
cstate<=STOP2;
end
elsecstate<=STOP1;
end
STOP2:
begin
if(`SCL_LOW)sda_r<=1'b1;
elseif(cnt_20ms==20'hffff0)cstate<=IDLE;
elsecstate<=STOP2;
end
default:
cstate<=IDLE;
endcase
end
assignsda=sda_link?
sda_r:
1'bz;
assigndis_data=read_data;
//---------------------------------------------
endmodule
最新文件----------------仅供参考--------------------已改成word文本---------------------方便更改
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 FPGA I2C 实验 Verilog 源代码 优选