当前位置: 首页 > news >正文

中山网站制作系统互联网平台推广

中山网站制作系统,互联网平台推广,wordpress uk,网络推广方案的参考文献FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1) 单字节写时序单字节读时序I2C 控制器设计模块框图scl_high 和 scl_low 产生的时序图状态转移图 Verilog代码 FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1) FPG…

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1)

  • 单字节写时序
  • 单字节读时序
  • I2C 控制器设计
    • 模块框图
    • scl_high 和 scl_low 产生的时序图
    • 状态转移图
  • Verilog代码

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(1)
FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(2)
FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(3)

单字节写时序

EEPROM器件或其他不同器件,I2C 器件地址字节不同,这样对于 I2C 单字节写时序就会有所差别,如下图分别为 1 字节地址段器件和 2 字节地址段器件单字节写时序图。
在这里插入图片描述
根据时序图,从主机角度来描述一次写入单字节数据过程如下:
主机设置 SDA 为输出;
主机发起起始信号;
主机传输器件地址字节,其中最低位为 0,表明为写操作;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 为输出,传输 1 字节地址数据;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,对于两字节地址段器件,传输地址数据低字节,对于 1字节地址段器件,主机设置 SDA 为输出,传输待写入的数据;
设置 SDA 为三态门输入,读取从机应答信号,对于两字节地址段器件,接着步骤 i;对于 1 字节地址段器件,直接跳转到步骤 k;
读取应答信号成功,主机设置 SDA 为输出,传输待写入的数据(对于两字节地址段器件);
设置 SDA 为三态门输入,读取从机应答信号(两字节地址段器件);
读取应答信号成功,主机产生 STOP 位,终止传输。

单字节读时序

在这里插入图片描述
根据时序图,从主机角度描述一次读数据过程,如下:
主机设置 SDA 为输出;
主机发起起始信号;
主机传输器件地址字节,其中最低位为 0,表明为写操作;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 输出,传输 1 字节地址数据;
主机设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 输出,对于两字节地址段器件,传输低字节地址数据;对于 1 字节地址段器件,无此步骤,直接跳转到步骤 h;
主机发起起始信号;
主机传输器件地址字节,其中最低位为 1,表明为读操作;
设置 SDA 为三态门输入,读取从机应答信号;
读取应答信号成功,主机设置 SDA 为三态门输入,读取 SDA 总线上的一个字节的数据;
产生无应答信号(高电平)(无需设置为输出高电平,因为总线会被自动拉高);
主机产生 STOP 位,终止传输。

I2C 控制器设计

模块框图

在这里插入图片描述
状态机里面线性序列机思路

在这里插入图片描述

scl_high 和 scl_low 产生的时序图

通过上述的讲述,对 I2C 读写器件数据时序有了一定的了解,下面将开始进行控制程序的设计。根据上面 I2C 的基本概念中有关读写时SDA 与 SCL 时序,不管对于从机还是主机,SDA 上的每一位数据在 SCL 的高电平期间保持不变,而数据的改变总是在 SCL 的低电平期间发生。因此,我们可以选用 2 个标志位对时钟 SCL 的高电平和低电平进行标记,如下图所示:scl_high 对 SCL 高电平期间进行标志,scl_low 对 SCL 低电平期间进行标志。这样就可以在 scl_high 有效时读 SDA 数据,在 scl_low 有效时改变数据

如下图所示
在这里插入图片描述

在状态机中,从主机角度来看,SDA 数据线上在写控制、写数据、读控制状态过程是需要串行输出数据,而在读数据状态过程是需要串行输入数据。根据数据在时钟高电平期间保持不变,改变数据在低电平时期的规则,本设计对时钟信号的高低电平进行计数,从而在指定的计数值进行输出或读取数据实现数据的串行输出和串行输入。串行输出和串行输入数据采用任务的形式进行表示,便于在主状态机中多次的调用。图下为计数的过程以及特定状态变化的时序图,这里的特定状态主要是指读/写控制、读/写地址和读/写数据状态。
在这里插入图片描述

状态转移图

定义
在这里插入图片描述

在这里插入图片描述

独热码
在这里插入图片描述

为了节省资源,可以通过上一个状态一定会执行下一个状态进而连贯在一起弄一个组合拳法

创建任务的思想
对于计数器 halfbit_cnt 只在写控制、写数据、读控制、读数据状态下才进行计数,其他状态为零。代码中 FF 是进行串行输出或输入任务的标志位,当 FF 为1 时表示退出任务,FF 为 0 时表示进入任务。这样便于在状态机中对任务的调用,以及在指定的时间退出任务。

状态机里面线性序列机思路

Verilog代码

module I2C(Clk,Rst_n,Rddata_num,Wrdata_num,Wdaddr_num,Device_addr,Word_addr,Wr,Wr_data,Wr_data_vaild,Rd,Rd_data,Rd_data_vaild,Scl,Sda,Done
);//系统时钟采用50MHz
parameter SYS_CLOCK = 50_000_000;
//SCL总线时钟采用400kHz
parameter SCL_CLOCK = 400_000;
//产生时钟SCL计数器最大值
localparam SCL_CNT_M = SYS_CLOCK/SCL_CLOCK;input             Clk;          //系统时钟input             Rst_n;        //系统复位信号input     [5:0]   Rddata_num;   //I2C总线连续读取数据字节数input     [5:0]   Wrdata_num;   //I2C总线连续读取数据字节数input     [1:0]   Wdaddr_num;   //I2C器件数据地址字节数input     [2:0]   Device_addr;  //I2C器件地址input     [15:0]  Word_addr;    //I2C寄存器地址input             Wr;           //I2C器件写使能input     [7:0]   Wr_data;      //I2C器件写数据output            Wr_data_vaild;//I2C器件写数据有效标志位input             Rd;           //I2C器件读使能output reg[7:0]   Rd_data;      //I2C器件读数据output reg        Rd_data_vaild;//I2C器件读数据有效标志位output  reg       Scl;          //I2C时钟线inout             Sda;          //I2C数据线output  reg       Done;         //对I2C器件读写完成标识位//主状态机状态localparam  IDLE     = 9'b0_0000_0001,//空闲状态WR_START = 9'b0_0000_0010,//写开始状态WR_CTRL  = 9'b0_0000_0100,//写控制状态WR_WADDR = 9'b0_0000_1000,//写地址状态WR_DATA  = 9'b0_0001_0000,//写数据状态RD_START = 9'b0_0010_0000,//读开始状态RD_CTRL  = 9'b0_0100_0000,//读控制状态RD_DATA  = 9'b0_1000_0000,//读数据状态STOP     = 9'b1_0000_0000;//停止状态reg [8:0] main_state;	   //主状态机状态寄存器reg       sda_en;          //sda数据总线控制位reg       sda_reg;         //sda数据输出寄存器reg       W_flag;          //IIC写操作标志位reg       R_flag;          //IIC读操作标志位reg       FF;              //串行输出输入任务执行标志位wire[7:0] wr_ctrl_word;    //写控制数据寄存器wire[7:0] rd_ctrl_word;    //读控制数据寄存器reg [15:0]scl_cnt;         //SCL时钟计数器reg       scl_vaild;       //IIC非空闲时期reg       scl_high;        //SCL时钟高电平中部标志位reg       scl_low;         //SCL时钟低电平中部标志位	reg [7:0] halfbit_cnt;     //串行数据传输计数器reg       ack;             //串行输出输入高低电平计数完成标志位reg [1:0] waddr_cnt;       //地址字节数计数器reg [7:0] wdata_cnt;       //写数据字节数计数器reg [7:0] rdata_cnt;       //读数据字节数计数器reg [7:0] sda_data_out;    //待输出SDA串行数据reg [7:0] sda_data_in;     //SDA串行输入后数据wire      rdata_vaild_r; //读写控制字assign wr_ctrl_word = {4'b1010, Device_addr,1'b0};assign rd_ctrl_word = {4'b1010, Device_addr,1'b1};//I2C数据线采用三态门传输assign Sda = sda_en ? sda_reg : 1'bz;//I2C非空闲时期scl_vaild的产生always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)scl_vaild <= 1'b0;else if(Wr | Rd)scl_vaild <= 1'b1;else if(Done)scl_vaild <= 1'b0;elsescl_vaild <= scl_vaild;end//scl时钟计数器always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)scl_cnt <= 16'd0;else if(scl_vaild)beginif(scl_cnt == SCL_CNT_M - 1)scl_cnt <= 16'd0;elsescl_cnt <= scl_cnt + 16'd1;endelsescl_cnt <= 16'd0;end//scl时钟,在计数器值到达最大值一半和0时翻转always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Scl <= 1'b1;else if(scl_cnt == SCL_CNT_M >>1)Scl <= 1'b0;else if(scl_cnt == 16'd0)Scl <= 1'b1;elseScl <= Scl;end	//scl时钟高低电平中部标志位always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)scl_high <= 1'b0;else if(scl_cnt == (SCL_CNT_M>>2))scl_high <= 1'b1;elsescl_high <= 1'b0;end//scl时钟低电平中部标志位//(SCL_CNT_M>>2)和(SCL_CNT_M>>1)+(SCL_CNT_M>>2)分别为 1/4 的 SCL_CNT_M 和 3/4 的SCL_CNT_M 的计数值。always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)scl_low <= 1'b0;else if(scl_cnt == (SCL_CNT_M>>1)+(SCL_CNT_M>>2))scl_low <= 1'b1;elsescl_low <= 1'b0;end	//主状态机always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)beginmain_state <= IDLE;sda_reg    <= 1'b1;//三态控制信号W_flag     <= 1'b0;//写标注      R_flag     <= 1'b0;//读标注 			Done       <= 1'b0;//完成waddr_cnt  <= 2'd1;//地址 wdata_cnt  <= 8'd1;//写数据rdata_cnt  <= 8'd1;//读数据endelse begincase(main_state)IDLE:begin//空闲状态sda_reg   <= 1'b1;W_flag    <= 1'b0;R_flag    <= 1'b0;Done      <= 1'b0;waddr_cnt <= 2'd1;wdata_cnt <= 8'd1;rdata_cnt <= 8'd1;if(Wr)beginmain_state <= WR_START;W_flag     <= 1'b1;endelse if(Rd)beginmain_state <= WR_START;R_flag     <= 1'b1;endelsemain_state <= IDLE;endWR_START:begin//写开始状态if(scl_low)begin//在scl_low寄存器下个周期发送起始信号main_state   <= WR_CTRL;sda_data_out <= wr_ctrl_word;FF           <= 1'b0;endelse if(scl_high)beginsda_reg    <= 1'b0;main_state <= WR_START;endelsemain_state <= WR_START;endWR_CTRL:begin//写控制状态if(FF == 1'b0)send_8bit_data;else beginif(ack == 1'b1) begin//收到响应if(scl_low)beginmain_state   <= WR_WADDR;FF           <= 1'b0;if(Wdaddr_num == 2'b1)sda_data_out <= Word_addr[7:0];elsesda_data_out <= Word_addr[15:8];endelsemain_state   <= WR_CTRL;endelse//未收到响应main_state      <= IDLE;endendWR_WADDR:begin//写地址状态if(FF == 1'b0)send_8bit_data;else beginif(ack == 1'b1) begin//收到响应if(waddr_cnt == Wdaddr_num)beginif(W_flag && scl_low)beginmain_state   <= WR_DATA;sda_data_out <= Wr_data;waddr_cnt    <= 2'd1;FF           <= 1'b0;endelse if(R_flag && scl_low)beginmain_state <= RD_START;sda_reg    <= 1'b1;endelsemain_state <= WR_WADDR;endelse beginif(scl_low)beginwaddr_cnt    <= waddr_cnt + 2'd1;main_state   <= WR_WADDR;sda_data_out <= Word_addr[7:0];FF           <= 1'b0;endelsemain_state   <= WR_WADDR;endendelse//未收到响应main_state <= IDLE;endendWR_DATA:begin//写数据状态if(FF == 1'b0)send_8bit_data;else beginif(ack == 1'b1) begin//收到响应if(wdata_cnt == Wrdata_num)beginif(scl_low)beginmain_state <= STOP;sda_reg    <= 1'b0;wdata_cnt  <= 8'd1;endelsemain_state <= WR_DATA;endelse beginif(scl_low)beginwdata_cnt    <= wdata_cnt + 8'd1;main_state   <= WR_DATA;sda_data_out <= Wr_data;FF           <= 1'b0;endelsemain_state   <= WR_DATA;endendelse//未收到响应main_state <= IDLE;endendRD_START:begin//读开始状态if(scl_low)beginmain_state   <= RD_CTRL;sda_data_out <= rd_ctrl_word;FF           <= 1'b0;endelse if(scl_high)beginmain_state <= RD_START;sda_reg    <= 1'b0;endelsemain_state <= RD_START;endRD_CTRL:begin//读控制状态if(FF == 1'b0)send_8bit_data;else beginif(ack == 1'b1) begin//收到响应if(scl_low)beginmain_state <= RD_DATA;FF         <= 1'b0;endelsemain_state <= RD_CTRL;endelse//未收到响应main_state    <= IDLE;endendRD_DATA:begin//读数据状态if(FF == 1'b0)receive_8bit_data;else beginif(rdata_cnt == Rddata_num)beginsda_reg <= 1'b1;if(scl_low)beginmain_state <= STOP;sda_reg    <= 1'b0;endelsemain_state <= RD_DATA;endelse beginsda_reg <= 1'b0;if(scl_low)beginrdata_cnt  <= rdata_cnt + 8'd1;main_state <= RD_DATA;FF         <= 1'b0;endelsemain_state <= RD_DATA;endendendSTOP:begin//结束操作if(scl_high)beginsda_reg    <= 1'b1;main_state <= IDLE;Done       <= 1'b1;endelsemain_state <= STOP;enddefault:main_state <= IDLE;endcaseendend//sda串行接收与发送时scl高低电平计数器根据中计数器 halfbit_cnt 和数据接收方对发送的响应检测标志位 ack 以及串行输出、输入数据任务always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)halfbit_cnt <= 8'd0;else if((main_state == WR_CTRL)||(main_state == WR_WADDR)||(main_state == WR_DATA)||(main_state == RD_CTRL)||(main_state == RD_DATA))beginif(scl_low | scl_high)beginif(halfbit_cnt == 8'd17)halfbit_cnt <= 8'd0;elsehalfbit_cnt <= halfbit_cnt + 8'd1;endelsehalfbit_cnt <= halfbit_cnt;endelsehalfbit_cnt <= 8'd0;end//数据接收方对发送的响应检测标志位always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)ack <= 1'b0;else if((halfbit_cnt == 8'd16)&&scl_high&&(Sda==1'b0))ack <= 1'b1;else if((halfbit_cnt == 8'd17)&&scl_low)ack <= 1'b0;elseack <= ack;end//输出串行数据任务task send_8bit_data;if(scl_high && (halfbit_cnt == 8'd16))FF <= 1;else if(halfbit_cnt < 8'd17)beginsda_reg <= sda_data_out[7];if(scl_low)sda_data_out <= {sda_data_out[6:0],1'b0};elsesda_data_out <= sda_data_out;endelse;endtask//串行数据输入任务task receive_8bit_data;if(scl_low && (halfbit_cnt == 8'd15))FF <= 1;else if((halfbit_cnt < 8'd15))beginif(scl_high)sda_data_in <= {sda_data_in[6:0],Sda};else beginsda_data_in <= sda_data_in;endendelse;endtask//sda三态使能信号sda_enalways@(*)begincase(main_state)IDLE:sda_en = 1'b0;WR_START,RD_START,STOP:sda_en = 1'b1;WR_CTRL,WR_WADDR,WR_DATA,RD_CTRL:if(halfbit_cnt < 16)sda_en = 1'b1;elsesda_en = 1'b0;RD_DATA:if(halfbit_cnt < 16)sda_en = 1'b0;elsesda_en = 1'b1;		default:sda_en = 1'b0;		endcaseend//写数据有效标志位assign Wr_data_vaild = ((main_state==WR_WADDR)&&(waddr_cnt==Wdaddr_num)&&(W_flag && scl_low)&&(ack == 1'b1))||((main_state == WR_DATA)&&(ack == 1'b1)&&(scl_low)&&(wdata_cnt != Wrdata_num));//读数据有效标志位前寄存器assign rdata_vaild_r = (main_state == RD_DATA)&&(halfbit_cnt == 8'd15)&&scl_low;//读出数据有效标志位always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Rd_data_vaild <= 1'b0;else if(rdata_vaild_r)Rd_data_vaild <= 1'b1;elseRd_data_vaild <= 1'b0;end//读出的有效数据always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Rd_data <= 8'd0;else if(rdata_vaild_r)Rd_data <= sda_data_in;elseRd_data <= Rd_data;endendmodule 
http://www.mmbaike.com/news/98434.html

相关文章:

  • 需要手机端网站建设的企业优云优客百度推广效果怎么样
  • 销售网络平台微信搜索seo优化
  • 常州网站建设公司方案优质外链
  • 网站建设优秀网站建设排名优化公司口碑哪家好
  • 网站建站程序可以免费网络推广网站
  • 如何看出一个网站有做seo最近新闻头条
  • 做外贸是在什么网站seo网络营销推广排名
  • 商城网站开发平台推广团队在哪里找
  • 摄影网站建立营销策略国内外文献综述
  • 腾讯云备案网站建设方案书广州营销课程培训班
  • 大专生学广告设计后悔了西安官网seo公司
  • 水文站网站建设应当坚持百度app关键词优化
  • 中药网站模板西安seo顾问
  • 最新一键自助建站程序源码软件外包公司排行
  • 怒江网站建设百度数据平台
  • 社交网站 cms网站排名优化手机
  • 大型多媒体网站建设工具安卓优化清理大师
  • 百度做地图的网站无锡网站seo
  • 程序员自己做网站怎么能来钱淘宝的关键词排名怎么查
  • 网站建设淄博佳铉网络2023年新闻热点事件摘抄
  • 网站制作详细教程百度入驻
  • wordpress影视站软文是啥意思
  • 展示用网站模板免费下载搜狗网页版
  • 常宁网站设计2021国内最好用免费建站系统
  • 微信微网站教程虞城seo代理地址
  • html5做动态网站建设福州seo顾问
  • 朝鲜族网站沙参怎么做网络竞价托管公司
  • 政府网站模板 免费百度下载老版本
  • 企业门户网站国内外研究现状百度怎么创建自己的网站
  • 做网站页面一般用什么软件腾讯广告推广平台入口