1、基于FPGA的I2C实验Verilog源代码优选timescale 1ns / 1psmodule i2c_drive( clk,rst_n, sw1,sw2, scl,sda, dis_data );input clk; / 50MHzinput rst_n; /复位信号,低有效input sw1,sw2; /按键1、2,(1按下执行写入操作,2按下执行读操作)output scl; / 24C02的时钟端口inout sda; / 24C02的数据端口output 7:0 dis_data; /输出指定单元的数据/-/按键检测reg sw1_r,sw2_r; /键值锁存寄存器,每20ms检
2、测一次键值 reg19:0 cnt_20ms; /20ms计数寄存器always (posedge clk or negedge rst_n) if(!rst_n) cnt_20ms = 20d0; else cnt_20ms = cnt_20ms+1b1; /不断计数always (posedge clk or negedge rst_n) if(!rst_n) begin sw1_r = 1b1; /键值寄存器复位,没有键盘按下时键值都为1 sw2_r = 1b1; end else if(cnt_20ms = 20hfffff) begin sw1_r = sw1; /按键1值锁存 sw
3、2_r = sw2; /按键2值锁存 end/-/分频部分reg2:0 cnt; / cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl低电平中间reg8:0 cnt_delay; /500循环计数,产生iic所需要的时钟reg scl_r; /时钟脉冲寄存器always (posedge clk or negedge rst_n) if(!rst_n) cnt_delay = 9d0; else if(cnt_delay = 9d499) cnt_delay = 9d0; /计数到10us为scl的周期,即100KHz else cnt_de
4、lay = cnt_delay+1b1; /时钟计数always (posedge clk or negedge rst_n) begin if(!rst_n) cnt = 3d5; else begin case (cnt_delay) 9d124: cnt = 3d1; /cnt=1:scl高电平中间,用于数据采样 9d249: cnt = 3d2; /cnt=2:scl下降沿 9d374: cnt = 3d3; /cnt=3:scl低电平中间,用于数据变化 9d499: cnt = 3d0; /cnt=0:scl上升沿 default: cnt = 3d5; endcase endend
5、define SCL_POS (cnt=3d0) /cnt=0:scl上升沿define SCL_HIG (cnt=3d1) /cnt=1:scl高电平中间,用于数据采样define SCL_NEG (cnt=3d2) /cnt=2:scl下降沿define SCL_LOW (cnt=3d3) /cnt=3:scl低电平中间,用于数据变化always (posedge clk or negedge rst_n) if(!rst_n) scl_r = 1b0; else if(cnt=3d0) scl_r = 1b1; /scl信号上升沿 else if(cnt=3d2) scl_r = 1b0
6、; /scl信号下降沿assign scl = scl_r; /产生iic所需要的时钟/-/需要写入24C02的地址和数据 define DEVICE_READ 8b1010_0001 /被寻址器件地址(读操作)define DEVICE_WRITE 8b1010_0000 /被寻址器件地址(写操作)define WRITE_DATA 8b0000_0111 /写入EEPROM的数据define BYTE_ADDR 8b0000_0100 /写入/读出EEPROM的地址寄存器 reg7:0 db_r; /在IIC上传送的数据寄存器reg7:0 read_data; /读出EEPROM的数据寄存
7、器/- /读、写时序parameter IDLE = 4d0;parameter START1 = 4d1;parameter ADD1 = 4d2;parameter ACK1 = 4d3;parameter ADD2 = 4d4;parameter ACK2 = 4d5;parameter START2 = 4d6;parameter ADD3 = 4d7;parameter ACK3 = 4d8;parameter DATA = 4d9;parameter ACK4 = 4d10;parameter STOP1 = 4d11;parameter STOP2 = 4d12; reg3:0
8、cstate; /状态寄存器reg sda_r; /输出数据寄存器reg sda_link; /输出数据sda信号inout方向控制位 reg3:0 num; /always (posedge clk or negedge rst_n) begin if(!rst_n) begin cstate = IDLE; sda_r = 1b1; sda_link = 1b0; num = 4d0; read_data = 8b0000_0000; end else case (cstate) IDLE: begin sda_link = 1b1; /数据线sda为input sda_r = 1b1;
9、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 = 1b1; /数据线sda为output sda_r = 1b0; /拉低数据线sda,产生起始位信号 cstate = ADD1; num = 4d0; /num计数清零 end else cstate = START1; /等待s
10、cl高电平中间位置到来 end ADD1: begin if(SCL_LOW) begin if(num = 4d8) begin num = 4d0; /num计数清零 sda_r = 1b1; sda_link = 1b0; /sda置为高阻态(input) cstate = ACK1; end else begin cstate = ADD1; num = num+1b1; case (num) 4d0: sda_r = db_r7; 4d1: sda_r = db_r6; 4d2: sda_r = db_r5; 4d3: sda_r = db_r4; 4d4: sda_r = db_r
11、3; 4d5: sda_r = db_r2; 4d6: sda_r = db_r1; 4d7: sda_r = db_r0; default: ; endcase / sda_r = db_r4d7-num; /送器件地址,从高位开始 end end / else if(SCL_POS) db_r = db_r6:0,1b0; /器件地址左移1bit else cstate = ADD1; end ACK1: begin if(/*!sda*/SCL_NEG) begin /注:24C01/02/04/08/16器件可以不考虑应答位 cstate = ADD2; /从机响应信号 db_r =
12、BYTE_ADDR; / 1地址 end else cstate = ACK1; /等待从机响应 end ADD2: begin if(SCL_LOW) begin if(num=4d8) begin num = 4d0; /num计数清零 sda_r = 1b1; sda_link = 1b0; /sda置为高阻态(input) cstate = ACK2; end else begin sda_link = 1b1; /sda作为output num = num+1b1; case (num) 4d0: sda_r = db_r7; 4d1: sda_r = db_r6; 4d2: sda
13、_r = db_r5; 4d3: sda_r = db_r4; 4d4: sda_r = db_r3; 4d5: sda_r = db_r2; 4d6: sda_r = db_r1; 4d7: sda_r = db_r0; default: ; endcase / sda_r = db_r4d7-num; /送EEPROM地址(高bit开始) cstate = ADD2; end end / else if(SCL_POS) db_r = db_r6:0,1b0; /器件地址左移1bit else cstate = ADD2; end ACK2: begin if(/*!sda*/SCL_NE
14、G) begin /从机响应信号 if(!sw1_r) begin cstate = DATA; /写操作 db_r = WRITE_DATA; /写入的数据 end else if(!sw2_r) begin db_r = DEVICE_READ; /送器件地址(读操作),特定地址读需要执行该步骤以下操作 cstate = START2; /读操作 end end else cstate = ACK2; /等待从机响应 end START2: begin /读操作起始位 if(SCL_LOW) begin sda_link = 1b1; /sda作为output sda_r = 1b1; /
15、拉高数据线sda cstate = START2; end else if(SCL_HIG) begin /scl为高电平中间 sda_r = 1b0; /拉低数据线sda,产生起始位信号 cstate = ADD3; end else cstate = START2; end ADD3: begin /送读操作地址 if(SCL_LOW) begin if(num=4d8) begin num = 4d0; /num计数清零 sda_r = 1b1; sda_link = 1b0; /sda置为高阻态(input) cstate = ACK3; end else begin num = nu
16、m+1b1; case (num) 4d0: sda_r = db_r7; 4d1: sda_r = db_r6; 4d2: sda_r = db_r5; 4d3: sda_r = db_r4; 4d4: sda_r = db_r3; 4d5: sda_r = db_r2; 4d6: sda_r = db_r1; 4d7: sda_r = db_r0; default: ; endcase / sda_r = db_r4d7-num; /送EEPROM地址(高bit开始) cstate = ADD3; end end / else if(SCL_POS) db_r = db_r6:0,1b0;
17、 /器件地址左移1bit else cstate = ADD3; end ACK3: begin if(/*!sda*/SCL_NEG) begin cstate = DATA; /从机响应信号 sda_link = 1b0; end else cstate = ACK3; /等待从机响应 end DATA: begin if(!sw2_r) begin /读操作 if(num=4d7) begin cstate = DATA; if(SCL_HIG) begin num = num+1b1; case (num) 4d0: read_data7 = sda; 4d1: read_data6
18、= sda; 4d2: read_data5 = sda; 4d3: read_data4 = sda; 4d4: read_data3 = sda; 4d5: read_data2 = sda; 4d6: read_data1 = sda; 4d7: read_data0 = sda; default: ; endcase / read_data4d7-num = sda; /读数据(高bit开始) end / else if(SCL_NEG) read_data = read_data6:0,read_data7; /数据循环右移 end else if(SCL_LOW) & (num=4
19、d8) begin num = 4d0; /num计数清零 cstate = ACK4; end else cstate = DATA; end else if(!sw1_r) begin /写操作 sda_link = 1b1; if(num=4d7) begin cstate = DATA; if(SCL_LOW) begin sda_link = 1b1; /数据线sda作为output num = num+1b1; case (num) 4d0: sda_r = db_r7; 4d1: sda_r = db_r6; 4d2: sda_r = db_r5; 4d3: sda_r = db
20、_r4; 4d4: sda_r = db_r3; 4d5: sda_r = db_r2; 4d6: sda_r = db_r1; 4d7: sda_r = db_r0; default: ; endcase / sda_r = db_r4d7-num; /写入数据(高bit开始) end / else if(SCL_POS) db_r = db_r6:0,1b0; /写入数据左移1bit end else if(SCL_LOW) & (num=4d8) begin num = 4d0; sda_r = 1b1; sda_link = 1b0; /sda置为高阻态 cstate = ACK4;
21、end else cstate = DATA; end end ACK4: begin if(/*!sda*/SCL_NEG) begin/ sda_r = 1b1; cstate = STOP1; end else cstate = ACK4; end STOP1: begin if(SCL_LOW) begin sda_link = 1b1; sda_r = 1b0; cstate = STOP1; end else if(SCL_HIG) begin sda_r = 1b1; /scl为高时,sda产生上升沿(结束信号) cstate = STOP2; end else cstate = STOP1; end STOP2: begin if(SCL_LOW) sda_r = 1b1; else if(cnt_20ms=20hffff0) cstate = IDLE; else cstate = STOP2; end default: cstate = IDLE; endcaseendassign sda = sda_link ? sda_r:1bz;assign dis_data = read_data;/-endmodule最新文件- 仅供参考-已改成word文本 - 方便更改
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2