协议——IIC
I²C即Inter-Integrated Circuit(集成电路总线),它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代设计出来的一种简单、双向、二线制总线标准。多用于主机和从机在数据量不大且传输距离短的场合下的主从通信。主机启动总线,并产生时钟用于传送数据,此时任何接收数据的器件均被认为是从机。I²C总线由数据线SDA和时钟线SCL构成通信线路,既可用于发送数据,也可接收数据。在主控与被控IC之间可进行双向数据传送,数据的传输速率在标准模式下可达100kbit/s,在快速模式下可达400kbit/s,在高速模式下可达3.4Mbit/s,各种被控器件均并联在总线上,通过器件地址(SLAVE ADDR,具体可查器件手册)识别。I²C总线物理拓扑结构图如下所示:










//**************************************************************************
// *** 名称 : iic.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2019-08-10
// *** 描述 : IIC控制器
//************************************************************************** module iic
//========================< 参数 >==========================================
#(
parameter DEVICE_ID = 'b1010000 , //器件ID
parameter CLK = 'd50_000_000 , //本模块的时钟频率
parameter SCL = 'd250_000 //输出的SCL时钟频率
)
//========================< 端口 >==========================================
(
input clk , //时钟
input rst_n , //复位,低电平有效
//IIC control ---------------------------------------
input iic_en , //IIC触发信号
input addr16_en , //16位地址使能
input addr8_en , //8位地址使能
input write_en , //IIC写使能
input read_en , //IIC读使能
input [:] iic_addr , //IIC器件内地址
input [ :] iic_data_wr , //IIC要写的数据
//IIC output ----------------------------------------
output reg [ :] iic_data_rd , //IIC读出的数据
output reg iic_done , //IIC一次操作完成
output reg iic_scl , //IIC的SCL时钟信号
inout iic_sda , //IIC的SDA数据信号
//dri_clk -------------------------------------------
output reg iic_dri_clk //驱动IIC操作的驱动时钟,1Mhz
);
//========================< 参数 >==========================================
localparam IDLE = 'b0000_0001 ; //空闲状态
localparam DEVICE = 'b0000_0010 ; //写器件地址
localparam ADDR_16 = 'b0000_0100 ; //写字地址高8位
localparam ADDR_8 = 'b0000_1000 ; //写字地址低8位
localparam DATA_WR = 'b0001_0000 ; //写数据
localparam DEVICE_RD = 'b0010_0000 ; //虚写器件地址
localparam DATA_RD = 'b0100_0000 ; //读数据
localparam STOP = 'b1000_0000 ; //结束
//========================< 信号 >==========================================
reg sda_dir ; //IIC数据(SDA)方向控制
reg sda_out ; //SDA输出信号
wire sda_in ; //SDA输入信号
reg state_done ; //状态结束
reg [ :] cnt ; //计数
reg [ :] state_c ; //状态机当前状态
reg [ :] state_n ; //状态机下一状态
reg [:] iic_addr_t ; //地址
reg [ :] iic_data_rd_t ; //读取的数据
reg [ :] iic_data_wr_t ; //IIC需写的数据的临时寄存
reg [ :] clk_cnt ; //分频时钟计数
wire [ :] clk_divide ; //模块驱动时钟的分频系数 //==========================================================================
//== sda控制
//==========================================================================
assign iic_sda = sda_dir ? sda_out : 'bz; //SDA数据输出或高阻
assign sda_in = iic_sda ; //SDA数据输入 //==========================================================================
//== 生成SCL的4倍时钟来驱动后面IIC的操作,生成1Mhz的iic_dri_clk
//==========================================================================
assign clk_divide = (CLK/SCL) >> ; // >>3即除以8 always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
iic_dri_clk <= 'b1;
clk_cnt <= 'd0;
end
else if(clk_cnt == clk_divide - 'd1) begin
clk_cnt <= 'd0;
iic_dri_clk <= ~iic_dri_clk;
end
else
clk_cnt <= clk_cnt + 'b1;
end //==========================================================================
//== 状态机
//==========================================================================
always @(posedge iic_dri_clk or negedge rst_n) begin
if(!rst_n)
state_c <= IDLE;
else
state_c <= state_n;
end always @(*) begin
case(state_c)
IDLE: begin //空闲状态
if(iic_en) begin
state_n = DEVICE;
end
else
state_n = IDLE;
end
DEVICE: begin //写器件ID
if(state_done) begin
if(addr16_en)
state_n = ADDR_16;
else if(addr8_en)
state_n = ADDR_8 ;
end
else
state_n = DEVICE;
end
ADDR_16: begin //写地址高8位
if(state_done)
state_n = ADDR_8;
else
state_n = ADDR_16;
end
ADDR_8: begin //写地址低8位
if(state_done) begin
if(write_en)
state_n = DATA_WR;
else if(read_en)
state_n = DEVICE_RD;
end
else
state_n = ADDR_8;
end
DATA_WR: begin //写数据
if(state_done)
state_n = STOP;
else
state_n = DATA_WR;
end
DEVICE_RD: begin //虚写器件ID
if(state_done)
state_n = DATA_RD;
else
state_n = DEVICE_RD;
end
DATA_RD: begin //读数据
if(state_done)
state_n = STOP;
else
state_n = DATA_RD;
end
STOP: begin //结束
if(state_done)
state_n = IDLE;
else
state_n = STOP ;
end
default:state_n= IDLE;
endcase
end //==========================================================================
//== 设计各路信号
//==========================================================================
always @(posedge iic_dri_clk or negedge rst_n) begin
if(!rst_n) begin
iic_scl <= 'b1;
sda_out <= 'b1;
sda_dir <= 'b1;
iic_done <= 'b0;
cnt <= 'b0;
state_done <= 'b0;
iic_addr_t <= 'b0;
iic_data_rd <= 'b0;
iic_data_rd_t <= 'b0;
iic_data_wr_t <= 'b0;
end
else begin
state_done <= 'b0 ;
cnt <= cnt +'b1 ;
case(state_c)
//--------------------------------------------------- 空闲状态
IDLE: begin
iic_scl <= 'b1;
sda_out <= 'b1;
sda_dir <= 'b1;
iic_done <= 'b0;
cnt <= 'b0;
if(iic_en) begin
iic_addr_t <= iic_addr;
iic_data_wr_t <= iic_data_wr;
end
end
//--------------------------------------------------- 写器件ID
DEVICE: begin
case(cnt)
'd1 : sda_out <= 1'b0;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= DEVICE_ID[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= DEVICE_ID[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= DEVICE_ID[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= DEVICE_ID[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= DEVICE_ID[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= DEVICE_ID[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= DEVICE_ID[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: sda_out <= 1'b0; //0:写
'd33: iic_scl <= 1'b1;
'd35: iic_scl <= 1'b0;
'd36: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd37: iic_scl <= 1'b1;
'd38: state_done <= 1'b1; //状态结束
'd39: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写字地址高8位
ADDR_16: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1 ;
sda_out <= iic_addr_t[];
end
'd1 : iic_scl <= 1'b1;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= iic_addr_t[14];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= iic_addr_t[13];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= iic_addr_t[12];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= iic_addr_t[11];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= iic_addr_t[10];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= iic_addr_t[9];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= iic_addr_t[8];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写字地址低8位
ADDR_8: begin
case(cnt)
'd0: begin
sda_dir <= 'b1 ;
sda_out <= iic_addr_t[];
end
'd1 : iic_scl <= 1'b1;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= iic_addr_t[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= iic_addr_t[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= iic_addr_t[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= iic_addr_t[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= iic_addr_t[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= iic_addr_t[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= iic_addr_t[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写数据
DATA_WR: begin
case(cnt)
'd0: begin
sda_out <= iic_data_wr_t[];
sda_dir <= 'b1;
end
'd1 : iic_scl <= 1'b1;
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= iic_data_wr_t[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= iic_data_wr_t[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= iic_data_wr_t[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= iic_data_wr_t[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= iic_data_wr_t[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= iic_data_wr_t[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= iic_data_wr_t[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 虚写器件ID
DEVICE_RD: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1;
sda_out <= 'b1;
end
'd1 : iic_scl <= 1'b1;
'd2 : sda_out <= 1'b0; //重新开始
'd3 : iic_scl <= 1'b0;
'd4 : sda_out <= DEVICE_ID[6];
'd5 : iic_scl <= 1'b1;
'd7 : iic_scl <= 1'b0;
'd8 : sda_out <= DEVICE_ID[5];
'd9 : iic_scl <= 1'b1;
'd11: iic_scl <= 1'b0;
'd12: sda_out <= DEVICE_ID[4];
'd13: iic_scl <= 1'b1;
'd15: iic_scl <= 1'b0;
'd16: sda_out <= DEVICE_ID[3];
'd17: iic_scl <= 1'b1;
'd19: iic_scl <= 1'b0;
'd20: sda_out <= DEVICE_ID[2];
'd21: iic_scl <= 1'b1;
'd23: iic_scl <= 1'b0;
'd24: sda_out <= DEVICE_ID[1];
'd25: iic_scl <= 1'b1;
'd27: iic_scl <= 1'b0;
'd28: sda_out <= DEVICE_ID[0];
'd29: iic_scl <= 1'b1;
'd31: iic_scl <= 1'b0;
'd32: sda_out <= 1'b1; //1:读
'd33: iic_scl <= 1'b1;
'd35: iic_scl <= 1'b0;
'd36: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd37: iic_scl <= 1'b1;
'd38: state_done <= 1'b1; //状态结束
'd39: begin
iic_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 读数据
DATA_RD: begin
case(cnt)
'd0 : sda_dir <= 1'b0;
'd1 : begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd3 : iic_scl <= 1'b0;
'd5 : begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd7 : iic_scl <= 1'b0;
'd9 : begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd11: iic_scl <= 1'b0;
'd13: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd15: iic_scl <= 1'b0;
'd17: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd19: iic_scl <= 1'b0;
'd21: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd23: iic_scl <= 1'b0;
'd25: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1;
end
'd27: iic_scl <= 1'b0;
'd29: begin
iic_data_rd_t[] <= sda_in;
iic_scl <= 'b1 ;
end
'd31: iic_scl <= 1'b0;
'd32: begin
sda_dir <= 'b1; //非应答
sda_out <= 'b1;
end
'd33: iic_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
iic_scl <= 'b0;
cnt <= 'b0;
iic_data_rd <= iic_data_rd_t;
end
default : ;
endcase
end
//--------------------------------------------------- 结束
STOP: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1;
sda_out <= 'b0;
end
'd1 : iic_scl <= 1'b1;
'd3 : sda_out <= 1'b1;
'd15: state_done <= 1'b1; //状态结束
'd16: begin
cnt <= 'b0;
iic_done <= 'b1; //IIC配置完成
end
default : ;
endcase
end
endcase
end
end endmodule
协议——IIC的更多相关文章
- 协议—IIC
I2C总线支持任何IC生产过程NMOS CMOS双极性,两线――串行数据 SDA 和串行时钟SCL线在连接到总线的器件间传递信息,每个器件都有一个唯一的地址识别,无论是微控制器.LCD 驱动器.存储器 ...
- FPGA基础设计(四):IIC协议
很多数字传感器.数字控制的芯片(DDS.串行ADC.串行DAC)都是通过IIC总线来和控制器通信的.不过IIC协议仍然是一种慢速的通信方式,标准IIC速率为100kbit/s,快速模式速率为400kb ...
- 九、IIC驱动原理分析
学习目标:学习IIC驱动原理: 一.IIC总线协议 IIC串行总线包括一条数据线(SDA)和一条时钟线(SCL),支持“一主多从”和“多主机”模式:每个从机设备都有唯一的地址来识别. 图 1 IIC ...
- 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)
版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 ...
- IIC通信控制的AD5259------在调试过程中遇到的奇葩问题
首先说一下的遇到的问题: 1.AD5259按照SCL是100KHz的情况下,可以正常接收上位机的数据,但是一段时间后,就不能正确的按照时序来走了 原因在于AD5259在接收到上位机的数据后需要一定的响 ...
- 51单片机下实现软件模拟IIC通信
1.IIC协议简易概述 IIC全称Inter-Integrated Circuit (集成电路总线),是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备.IIC属于半双 ...
- 嵌入式LINUX入门到实践(一)
MINI2440 IIC协议 IIC协议在工程中应用广泛,在我看来,此协议的优势就在于其硬件及其简单,结构清晰. 首先来解读一下S3C2440A这款芯片的IIC协议. 一.一个协议的解读从如上结构图中 ...
- OLED屏幕详细使用
IC扩展-OLED屏的点亮,模拟IIC功能实现C代码点亮OLED屏,只要是可以C编程且有两个GPIO口的单片机均可更改小部分代码使用.OLED屏为像素自发光,其尺寸多为128*64,表示横轴上有128 ...
- 基于STM32F429的ADS1115驱动程序
1.ADS1115中文资料:https://wenku.baidu.com/view/8bab101feef9aef8941ea76e58fafab069dc44e7.html?rec_flag=de ...
随机推荐
- A revolutionary architecture for building a distributed graph
转自:https://blog.apollographql.com/apollo-federation-f260cf525d21 What if you could access all of you ...
- CSS样式表书写位置
一.内嵌式写法:样式只作用于当前文件,没有真正实现结构表现分离. <head> <style type=”text/css”> 样式表写法 </style> < ...
- 搭建的一套vue打包方案,方便记录一下
package.json 配置如下: { "name": "rise-vue", "version": "1.0.0", ...
- CF #365 DIV2 D Mishka and Interesting sum 区间异或+线段树
D. Mishka and Interesting sum time limit per test 3.5 seconds memory limit per test 256 megabytes in ...
- 虚拟变量陷阱(Dummy Variable Trap)
虚拟变量陷阱(Dummy Variable Trap):指当原特征有m个类别时,如果将其转换成m个虚拟变量,就会导致变量间出现完全共线性的情况. 假设我们有一个特征“性别”,包含男性和女性两个类别,如 ...
- GoCN每日新闻(2019-10-25)
GoCN每日新闻(2019-10-25) GoCN每日新闻(2019-10-25) 1. [译]Golang应付百万级请求/分钟 https://juejin.im/post/5db1464b6fb9 ...
- Flask報錯 KeyError 'SQLALCHEMY_TRACK_MODIFICATIONS'.md
KeyError: 'SQLALCHEMY_TRACK_MODIFICATIONS' 关于flask-sqlalchemy中出现的 KeyError: 'SQLALCHEMY_TRACK_MODIFI ...
- gitbook+git+typora 的使用过程
Typora 下载地址:https://typora.io/ gitbook 第一步:安装 npm install -g gitbook-cli 第二步:使用 对要操作的文件夹执行命令 gitbook ...
- ICEM-R-b
原视频下载地址:https://pan.baidu.com/s/1i4JGk8d ;密码: 4xr2
- intellij ide调用一个对象所有的set方法
1.下载地址:https://github.com/yoke233/genSets/releases/download/1.1/genSets.jar 2.plugin 从本地磁盘安装找到jar,并重 ...