logo资料库

iic的详细代码.docx

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
module iic_top( clk,rst_n, sw1,sw2, scl,sda, sm_cs1_n,sm_cs2_n,sm_db ); input clk; input rst_n; input sw1,sw2; output scl; inout sda; // 50MHz //复位信号,低有效 // 24C02 的数据端口 //按键 1、2,(1 按下执行写入操作,2 按下执行读操作) // 24C02 的时钟端口 output sm_cs1_n,sm_cs2_n; output[6:0] sm_db; //7 段数码管(不包括小数点) //数码管片选信号,低有效 wire[7:0] dis_data; //在数码管上显示的 16 进制数 iic_com iic_com( .clk(clk), .rst_n(rst_n), .sw1(sw1), .sw2(sw2), .scl(scl), .sda(sda), .dis_data(dis_data) ); .clk(clk), .rst_n(rst_n), .dis_data(dis_data), .sm_cs1_n(sm_cs1_n), .sm_cs2_n(sm_cs2_n), .sm_db(sm_db) ); led_seg7 led_seg7( endmodule module led_seg7( clk,rst_n, dis_data,
sm_cs1_n,sm_cs2_n,sm_db ); input clk; input rst_n; // 50MHz // 复位信号,低有效 input[7:0] dis_data; //显示数据 output sm_cs1_n,sm_cs2_n; output[6:0] sm_db; //7 段数码管(不包括小数点) //数码管片选信号,低有效 reg[7:0] cnt; always @ (posedge clk or negedge rst_n) if(!rst_n) cnt <= 8'd0; else cnt <= cnt+1'b1; //------------------------------------------------------------------------------- /* 共阴极 :不带小数点 3, 6, 7, 1, 2, 4, 5, ;0, 3fh,06h,5bh,4fh,66h,6dh,7dh,07h ;8, 7fh,6fh,77h,7ch,39h,5eh,79h,71h,00h*/ f , 灭 9, a, b, c, d, e, db db parameterseg0 = 7'h3f, seg1 = 7'h06, seg2 = 7'h5b, seg3 = 7'h4f, seg4 = 7'h66, seg5 = 7'h6d, seg6 = 7'h7d, seg7 = 7'h07, seg8 = 7'h7f, seg9 = 7'h6f, sega = 7'h77, segb = 7'h7c, segc = 7'h39, segd = 7'h5e, sege = 7'h79, segf = 7'h71; reg[6:0] sm_dbr; //7 段数码管(不包括小数点) //显示数据 wire[3:0] num; assign num = cnt[7] ? dis_data[7:4] : dis_data[3:0]; //数码管 1 常开 assign sm_cs1_n = cnt[7]; assign sm_cs2_n = ~cnt[7]; //数码管 2 常开
always @ (posedge clk) case (num) //NUM 值显示在两个数码管上 4'h0: sm_dbr <= seg0; 4'h1: sm_dbr <= seg1; 4'h2: sm_dbr <= seg2; 4'h3: sm_dbr <= seg3; 4'h4: sm_dbr <= seg4; 4'h5: sm_dbr <= seg5; 4'h6: sm_dbr <= seg6; 4'h7: sm_dbr <= seg7; 4'h8: sm_dbr <= seg8; 4'h9: sm_dbr <= seg9; 4'ha: sm_dbr <= sega; 4'hb: sm_dbr <= segb; 4'hc: sm_dbr <= segc; 4'hd: sm_dbr <= segd; 4'he: sm_dbr <= sege; 4'hf: sm_dbr <= segf; default: ; endcase assign sm_db = sm_dbr; endmodule module iic_com( clk,rst_n, sw1,sw2, scl,sda, dis_data ); // 50MHz //复位信号,低有效 input clk; input rst_n; input sw1,sw2; output scl; inout sda; output[7:0] dis_data; //按键 1、2,(1 按下执行写入操作,2 按下执行读操作) // 24C02 的时钟端口 // 24C02 的数据端口 //数码管显示的数据 //-------------------------------------------- //按键检测 reg sw1_r,sw2_r; reg[19:0] cnt_20ms; //键值锁存寄存器,每 20ms 检测一次键值 //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 //键值寄存器复位,没有键盘按下时键值都为 1 else if(cnt_20ms == 20'hfffff) begin sw1_r <= sw1;//按键 1 值锁存 sw2_r <= sw2;//按键 2 值锁存 end //--------------------------------------------- //分频部分 // cnt=0:scl 上升沿,cnt=1:scl 高电平中间,cnt=2:scl 下降沿,cnt=3:scl 低电平 reg[2:0] cnt; 中间 reg[8:0] cnt_delay; //500 循环计数,产生 iic 所需要的时钟 reg scl_r; //时钟脉冲寄存器 always @ (posedge clk or negedge rst_n) if(!rst_n) cnt_delay <= 9'd0; else if(cnt_delay == 9'd499) cnt_delay <= 9'd0; else cnt_delay <= cnt_delay+1'b1; //时钟计数 always @ (posedge clk or negedge rst_n) begin //计数到 10us 为 scl 的周期,即 100KHz if(!rst_n) cnt <= 3'd5; else begin case (cnt_delay) cnt <= 3'd1; cnt <= 3'd2; cnt <= 3'd3; cnt <= 3'd0; 9'd124: 9'd249: 9'd374: 9'd499: default: cnt <= 3'd5; endcase end end //cnt=1:scl 高电平中间,用于数据采样 //cnt=2:scl 下降沿 //cnt=3:scl 低电平中间,用于数据变化 //cnt=0:scl 上升沿 `define SCL_POS `define SCL_HIG `define SCL_NEG `define SCL_LOW (cnt==3'd0) (cnt==3'd1) (cnt==3'd2) (cnt==3'd3) //cnt=0:scl 上升沿 //cnt=1:scl 高电平中间,用于数据采样 //cnt=2:scl 下降沿 //cnt=3:scl 低电平中间,用于数据变化
always @ (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; //scl 信号上升沿 //scl 信号下降沿 assign scl = scl_r; //--------------------------------------------- //产生 iic 所需要的时钟 //需要写入 24C02 的地址和数据 `define DEVICE_READ `define DEVICE_WRITE `define WRITE_DATA `define BYTE_ADDR reg[7:0] db_r; reg[7:0] read_data; //读出 EEPROM 的数据寄存器 //在 IIC 上传送的数据寄存器 8'b1010_0001 //被寻址器件地址(读操作) 8'b1010_0000 //被寻址器件地址(写操作) 8'b0001_0001 //写入 EEPROM 的数据 8'b0000_0011 //写入/读出 EEPROM 的地址寄存器 //--------------------------------------------- //读、写时序 parameter parameter parameter parameter parameter parameter parameter parameter parameter parameter parameter parameter parameter = 4'd0; = 4'd1; = 4'd2; = 4'd3; = 4'd4; = 4'd5; IDLE START1 ADD1 ACK1 ADD2 ACK2 START2 = 4'd7; ADD3 ACK3 = 4'd8; DATA = 4'd9; ACK4 = 4'd10; STOP1 = 4'd11; STOP2 = 4'd12; = 4'd6; reg[3:0] cstate; reg sda_r; reg sda_link; reg[3:0] num; // //状态寄存器 //输出数据寄存器 //输出数据 sda 信号 inout 方向控制位 always @ (posedge clk or negedge rst_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_r <= 1'b1; if(!sw1_r || !sw2_r) begin //数据线 sda 为 input //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_r <= 1'b0; cstate <= ADD1; num <= 4'd0; end //数据线 sda 为 output //拉低数据线 sda,产生起始位信号 //num 计数清零 else cstate <= START1; //等待 scl 高电平中间位置到来 end ADD1: begin if(`SCL_LOW) begin //num 计数清零 //sda 置为高阻态(input) 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];
开始 应答位 // end ACK1: end ADD2: 4'd7: sda_r <= db_r[0]; default: ; endcase // sda_r <= db_r[4'd7-num]; //送器件地址,从高位 end end else if(`SCL_POS) db_r <= {db_r[6:0],1'b0}; else cstate <= ADD1; //器件地址左移 1bit begin if(/*!sda*/`SCL_NEG) begin //注:24C01/02/04/08/16 器件可以不考虑 cstate <= ADD2; db_r <= `BYTE_ADDR; //从机响应信号 // 1 地址 end else cstate <= ACK1; //等待从机响应 begin if(`SCL_LOW) begin if(num==4'd8) begin num <= 4'd0; sda_r <= 1'b1; sda_link <= 1'b0; cstate <= ACK2; //num 计数清零 //sda 置为高阻态(input) end else begin sda_link <= 1'b1; num <= num+1'b1; case (num) //sda 作为 output 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 bit 开始) // sda_r <= db_r[4'd7-num]; //送 EEPROM 地址(高 cstate <= ADD2; end
// end ACK2: end else if(`SCL_POS) db_r <= {db_r[6:0],1'b0}; else cstate <= ADD2; //器件地址左移 1bit begin if(/*!sda*/`SCL_NEG) begin if(!sw1_r) begin //从机响应信号 cstate <= DATA; db_r <= `WRITE_DATA; //写操作 //写入的数据 end else if(!sw2_r) begin 特定地址读需要执行该步骤以下操作 cstate <= START2; //读操作 db_r <= `DEVICE_READ; //送器件地址(读操作), end end else cstate <= ACK2; //等待从机响应 end START2: begin //读操作起始位 if(`SCL_LOW) begin sda_link <= 1'b1; sda_r <= 1'b1; cstate <= START2; end //sda 作为 output //拉高数据线 sda else if(`SCL_HIG) begin//scl 为高电平中间 //拉低数据线 sda,产生起始位信号 sda_r <= 1'b0; cstate <= ADD3; end else cstate <= START2; end ADD3: //送读操作地址 begin if(`SCL_LOW) begin if(num==4'd8) begin num <= 4'd0; sda_r <= 1'b1; sda_link <= 1'b0; cstate <= ACK3; //num 计数清零 //sda 置为高阻态(input) end else begin num <= num+1'b1; case (num) 4'd0: sda_r <= db_r[7]; 4'd1: sda_r <= db_r[6];
分享到:
收藏