赞
踩
题目:
具体代码如下:
- module IIC_control(clk,rst,SCL,SDA,en);
- input clk,rst,en;
- output reg SCL;
- inout SDA;
- reg sdareg; //SDA 数据寄存器
- reg sdalink; //双向端口控制
- assign SDA=sdalink?sdareg:1'bz;//三态门控制双向口
- parameter IIC_idle=5'D0, //起始态
- IIC_start=5'D1, //开始
- IIC_icaddr=5'D2, //发出芯片地址
- IIC_icaddrask=5'D3, //从机应答
- IIC_regaddr1=5'D4, //发出寄存器 1 地址
- IIC_regaddrask1=5'D5, //从机应答
- IIC_regdata1=5'D6, //寄存器 1 数据
- IIC_regdataask1=5'D7, //从机应答
- IIC_regaddr2=5'D8, //发出寄存器 2 地址
- IIC_regaddrask2=5'D9, //从机应答
- IIC_regdata2=5'D10, //寄存器 2 数据
- IIC_regdataask2=5'D11, //从机应答
- IIC_regaddr3=5'D12, //发出寄存器 3 地址
- IIC_regaddrask3=5'D13, //从机应答
- IIC_regdata3=5'D14, //寄存器 3 数据
- IIC_regdataask3=5'D15, //从机应答
- IIC_stop=5'D16, //终止状态
- icaddr=8'b0111_1011, //芯片地址
- icaddrout={icaddr[6:0],1'b0}, //发出地址
- regaddr1=8'h48, //寄存器 1 地址
- regdata1=8'h55, //寄存器 1 数据
- regaddr2=8'h49, //寄存器 2 地址
- regdata2=8'hAA, //寄存器 2 数据
- regaddr3=8'h50, //寄存器 3 地址
- regdata3=8'hCC, //寄存器 3 数据
- freqcnt=(10000000/400000); //SCL 与 clk 的周期关系
-
- reg [7:0] cnt; //计数器产生 SCL
- reg [3:0] bytecnt; //数据或地址传输的位计数
- reg [4:0] state,nstate;
- assign SCL_h=(cnt==(freqcnt>>2));//SCL 时钟四分之一周期处,高电平中点
- assign SCL_l=(cnt==(freqcnt>>2)*3);//SCL 时钟周期四分之三处,低电平
- 中点
- //cnt 计数,从 0 到(freqcnt-1)
- always @(posedge clk or negedge rst)
- begin
- if(!rst)
- cnt<=1'b0;
- else if(cnt==freqcnt-1'b1)//计数到最大
- cnt<=1'b0;
- else
- cnt<=cnt+1'b1;
- end
- //产生 SCL 的时钟信号
- always @(posedge clk or negedge rst)//SCL 时钟跳变
- begin
- if(!rst)
- SCL<=1'b0;
- else begin
- if(cnt>=1'b0&&cnt<=(freqcnt>>1)-1'b1)
- SCL<=1'b1;//SCL 前半周期为高
- else
- SCL<=1'b0;//SCL 后半周期为低
- end
- end
- //IIC 三段式状态机:
- //第一部分:
- always @(posedge clk or negedge rst)
- begin
- if(!rst)
- state<=IIC_idle;
- else
- state<=nstate;
- end
- //第二部分 状态转移:
- always @(*)
- begin
- nstate<=state;
- case(state)
- IIC_idle: if(en)
- nstate<=IIC_start;
- IIC_start: if(SCL_h)//SCL 为高时,SDA 跳变,进入起始
- nstate<=IIC_icaddr;
- IIC_icaddr: if(SCL_l==1'b1&&bytecnt==3'b0)//地址发送完成
- nstate<=IIC_icaddrask;
- IIC_icaddrask: if(SCL_l)//SCL 为低时数据变化
- nstate<=IIC_regaddr1;
- IIC_regaddr1:if(SCL_l==1'b1&&bytecnt==3'b0)
- nstate<=IIC_regaddrask1;
- IIC_regaddrask1:if(SCL_l)
- nstate<=IIC_regdata1;
- IIC_regdata1:if(SCL_l==1'b1&&bytecnt==3'b0)
- nstate<=IIC_regdataask1;
- IIC_regdataask1:if(SCL_l)
- nstate<=IIC_regaddr2;
- IIC_regaddr2:if(SCL_l==1'b1&&bytecnt==3'b0)
- nstate<=IIC_regaddrask2;
- IIC_regaddrask2:if(SCL_l)
- nstate<=IIC_regdata2;
- IIC_regdata2: if(SCL_l==1'b1&&bytecnt==3'b0)
- nstate<=IIC_regdataask2;
- IIC_regdataask2: if(SCL_l)
- nstate<=IIC_regaddr3;
- IIC_regaddr3:if(SCL_l==1'b1&&bytecnt==3'b0)
- nstate<=IIC_regaddrask3;
- IIC_regaddrask3:if(SCL_l)
- nstate<=IIC_regdata3;
- IIC_regdata3:if(SCL_l==1'b1&&bytecnt==3'b0)
- nstate<=IIC_regdataask3;
- IIC_regdataask3:if(SCL_l)
- nstate<=IIC_stop;
- IIC_stop: if(SCL_h)
- nstate<=IIC_stop;
- default: nstate<=state;
- endcase
- end
- //第三部分 数据输出控制:
- always @(posedge clk or negedge rst)
- begin
- if(!rst) begin
- sdareg<=1;
- sdalink<=1;
- end
- else begin
- case(state)
- IIC_idle: begin
- sdareg<=1;
- sdalink<=1;
- end
- IIC_start:begin
- if(SCL_h) begin
- sdareg<=0;
- sdalink<=1;
- end
- end
- IIC_icaddr:begin //输出芯片地址
- if(SCL_l) begin
- sdareg<=icaddr[bytecnt];
- sdalink<=1;
- end
- end
- IIC_icaddrask,IIC_regaddrask1,IIC_regaddrask2,
- IIC_regaddrask3,IIC_regdataask1,IIC_regdataask2,
- IIC_regdataask3:begin //输入应答信号
- if(SCL_l)begin
- sdareg<=0;
- sdalink<=0;
- end
- end
- IIC_regaddr1:begin
- if(SCL_l) begin
- sdareg<=regaddr1[bytecnt];
- sdalink<=1;
- end
- end
- IIC_regaddr2:begin
- if(SCL_l) begin
- sdareg<=regaddr2[bytecnt];
- sdalink<=1;
- end
- end
- IIC_regaddr3:begin
- if(SCL_l) begin
- sdareg<=regaddr3[bytecnt];
- sdalink<=1;
- end
- end
- IIC_regdata1:begin
- if(SCL_l) begin
- sdareg<=regdata1[bytecnt];
- sdalink<=1;
- end
- end
- IIC_regdata2:begin
- if(SCL_l) begin
- sdareg<=regdata2[bytecnt];
- sdalink<=1;
- end
- end
- IIC_regdata3:begin
- if(SCL_l) begin
- sdareg<=regdata3[bytecnt];
- sdalink<=1;
- end
- end
- IIC_stop:begin
- if(SCL_h) begin
- sdareg<=1;
- sdalink<=1;
- end
- end
- endcase
- end
- end
- //数据寄存器控制:
- always @(posedge clk or negedge rst)
- begin
- if(!rst)
- bytecnt<=3'b0;
- else
- case(state)
- IIC_icaddr,IIC_regaddr1,IIC_regaddr2,
- IIC_regaddr3,IIC_regdata1,IIC_regdata2,
- IIC_regdata3://传输 8 位数据或地址
- if(SCL_l)
- bytecnt<=bytecnt-1;
- default: bytecnt<=3'd7;
- endcase
- end

- `timescale 1ns / 1ps
- module IIC_control_tb( );
- reg clk,rst,en;
- wire SCL,SDA;
- always #50 clk=~clk; //产生 10MHz 时钟
- initial begin
- rst<=0;
- clk<=0;
- en<=0;
- #2000 rst<=1;
- #1000 en<=1;
-
- end
- IIC_control iic(
- .clk(clk),
- .rst(rst),
- .SCL(SCL),
- .SDA(SDA),
- .en(en)
- );
- endmodule

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。