ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Verilog 代码编写 IIC通信-主到从向芯片写入数据

2022-01-20 13:58:31  阅读:324  来源: 互联网

标签:SCL 主到 应答 从机 地址 Verilog IIC 寄存器


题目:

        根据课堂讲授的基本原理,自己尝试编写一个 IIC 控制逻辑,FPGA 的输 入时钟为 10MHz,IIC 的通信频率为 400KHz,要求 FPGA 向 AD 芯片写入控 制指令,AD 芯片的地址为 0000123(改为十进制 123,即 01111011),AD 芯片 中有三个地址连续的寄存器, 地址为 0x48,配置数据为 0x55,地址为 0x49, 配置数据为 0xAA,地址为 0x50,配置数据为 0xCC,试画出电路连接框图、状 态转移图、完成代码编写并仿真。 分析:               根据要求,此 IIC 通信模块应该在 FPGA 与 AD 芯片间建立连接,其中最主要的就是 SCL 时钟线输出给 AD 芯片,建立通信时钟,还有 SDA 线实现双向数 据传输。        电路模块框图如下所示:         其中两个上拉电阻 R1 和 R2 保证了在空闲状态时,SCL 线与 SDA 线上均保 持高电平。         根据 IIC 的通信方法,我们按照 Moore 型状态机 进行时序编写,这是因为整个通信过程中状态的转移不受输入条件的影响,仅依赖过程中时序的变化,从而改变状态。设计思路如下: 1.按照题目意思,需要 17 个状态来表示整个通信过程,即: 不定态+起始态+发出芯片地址+从机应答+发出寄存器 1 地址+从机应答+发 出寄存器 1 数据+从机应答+发出寄存器 2 地址+从机应答+发出寄存器 2 数据+ 从机应答+发出寄存器 3 地址+从机应答+发出寄存器 3 数据+从机应答+终止态         由此在编写 Verilog 语言时应定义以上 17 个状态。当满足触发条件时将发生状态转移。 2.采用三端式状态机进行编写。除了正常的三部分之外,还应该 有一个数 据寄存器转移的部分,该部分提供了状态转移的动力和条件。 3.设计计数器产生所需频率的时钟 SCL 以及相应的变换节点,即在本设计中视为 SCL 高电平中点为稳定状态,判断起始与终止条件;将 SCL 低电平中点 看作数据变换点,即仅在此时发生数据变化。 4.SDA 的双向传输特性使用 三态门 来实现。         设计状态转移图如下:

 

        具体代码如下:

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
        最后设计仿真文件,得到如下波形图,进行结果的分析: 1.起始态与芯片地址发送         图中当使能 en 为 1 且复位 rst 打开时,可以开始传输,由图中黄线标注处可以看到,当 SCL 为高时,SDA 由高变低,传输开始。 接下来传输芯片地址,SDA 输出,由图中红框处可以看到,11110110 ,正是我们的发出地址(芯片地址七位+0)。然后是 SDA 的输入状态,此时为高阻,手动输入 0,视为应答信号。 2.寄存器 1 地址和寄存器 1 数据:         接上图,芯片地址传输完成后,传输寄存器 1 地址,图中红框 1 处,为01001000,即0x48,然后高阻应答 ,继续传输寄存器 1 数据,图中红框 2 处,为 01010101,即 0x55,然后高阻应答 。可见,与之前设计的数据一样,仿真设计成功。 3.寄存器 2 地址和寄存器 2 数据:        接上图,同理传输寄存器 2 的地址和数据:地址 01001001, 即 0x49 ,数据 10101010,即 0xAA 。与设计一致。 4.寄存器 3 地址和寄存器 3 数据及终止态:         接上图,同理传输寄存器 3 的地址和数据:地址 01010000, 即 0x50 ,数据 11001100,即 0xCC 。与设计一致。然后在下一个 SCL 为高时, SDA 恢复高电 平,终止传输。         仿真结束,结果与预期一致,仿真成功,以下为 testbench:
`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

 

 

 

 

标签:SCL,主到,应答,从机,地址,Verilog,IIC,寄存器
来源: https://blog.csdn.net/qq_46132759/article/details/122599882

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有