色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

IIC傳輸協議及其代碼的實現

HJ18656750788 ? 來源:Cascatrix ? 2023-01-08 09:16 ? 次閱讀

01

IIC基礎知識

集成電路總線(Inter-Intergrated Circuit),通常稱作IICBUS,簡稱為IIC,是一種采用多主從結構的串行通信總線。IIC由PHILIPS公司于1980年推出,利用該總線可實現多主機系統所需的裁決和高低速設備同步等功能。

IIC串行總線一般有兩根信號線,分別是時鐘線SCL和數據線SDA,所有IIC總線各設備的串行數據SDA接到總線SDA上,時鐘線SLC接到總線SCL上。

雙向串行數據SDA:輸出電路用于向總線發送數據,輸入電路用于接收總線上的數據;

雙向時鐘數據SCL:輸出電路用于向總線發送時鐘信號,輸入電路用于檢測總線時鐘電平以決定下次時鐘脈沖電平時間。

各設備與總線相連的輸出端采用高阻態以避免總線信號的混亂,通常采用漏極開路輸出或集電極開路輸出。總線空閑時,各設備都是開漏輸出,通常可采用上拉電阻使總線保持高電平,而任一設備輸出低電平都將拉低相應的總線信號。

57191204-8e9c-11ed-bfe3-dac502259ad0.png

IIC總線上的設備可分為主設備和從設備兩種:主設備有權利主動發起/結束一次通信;從設備只能被動響應。

所有連接在IIC總線上的設備都有各自唯一的地址(原地址位寬為7bits,改進后采用10bits位寬),每個設備都可以作為主設備或從設備,但是同一時刻只能有一個主設備控制。

如果總線上有多個設備同時啟用總線,IIC通過檢測和仲裁機制解決傳輸沖突。IIC允許連接的設備傳輸速率不同,多臺設備之間時鐘信號的同步過程稱為同步化。

02

IIC傳輸協議

2.1 IIC協議模式

IIC協議為半雙工模式,同一條數據線上完成讀/寫操作,不同操作時的數據幀格式可分為寫操作、讀操作、讀寫操作。

2.1.1 寫操作數據幀格式

主機向從機寫數據的數據幀格式如下:

573bf314-8e9c-11ed-bfe3-dac502259ad0.png

白色為主機發送數據,灰色為從機發送數據。

1. 主機發送開始信號S;

2. 主機發送地址數據ADDR;

3. 主機發送寫信號0;

4. 從機響應主機寫信號ACK;

5. 主機發送數據信息DATA;

6. 從機響應主機發送數據ACK;

7. 循環5 6步驟可完成主機向從機連續寫數據過程;

8. 主機發送結束信號P.

2.1.2 讀操作數據幀格式

主機從從機讀數據的數據幀格式如下:

5757227e-8e9c-11ed-bfe3-dac502259ad0.png

白色為主機發送數據,灰色為從機發送數據。

1. 主機發送開始信號S;

2. 主機發送地址數據ADDR;

3. 主機發送讀信號1;

4. 從機響應主機讀信號ACK;

5. 從機發送數據信息DATA;

6. 主機響應從機發送數據ACK;

7. 循環5 6步驟可完成主機向從機連續讀數據過程;

8. 主機發送結束信號P.

2.1.3 讀寫同時操作數據幀格式

主機先向從機寫數據后從從機讀數據的數據幀格式如下:

577905c4-8e9c-11ed-bfe3-dac502259ad0.png

白色為主機發送數據,灰色為從機發送數據。

主機可以在完成寫操作后不發送結束信號P,直接進行讀操作。該過程主機不可變,而從機可以通過發送不同地址選擇不同的從機。

2.2 IIC寫時序

IIC協議寫時序可分為單字節寫時序和連續寫時序:

2.2.1 單字節寫時序

單字節地址寫時序過程:

579d0316-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送單字節寄存器地址信息WORD ADDRESS;

5. 從機響應主機發送寄存器地址ACK;

6. 主機發送單字節數據信息DATA;

7. 從機響應主機發送數據信息ACK;

8. 主機發送結束信號P.

雙字節地址寫時序過程:

57d0eb86-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送寄存器地址信息高字節ADDRESS HIGH BYTE;

5. 從機響應主機發送寄存器地址高字節ACK;

6. 主機發送寄存器地址信息低字節ADDRESS LOW BYTE;

7. 從機響應主機發送寄存器地址低字節ACK;

8. 主機發送單字節數據信息DATA;

9. 從機響應主機發送數據信息ACK;

10. 主機發送結束信號P.

2.2.2 連續寫時序

單字節地址寫時序過程:

57f8c480-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送單字節寄存器地址信息WORD ADDRESS;

5. 從機響應主機發送寄存器地址ACK;

6. 主機發送單字節數據信息DATA;

7. 從機響應主機發送數據信息ACK;

8. 循環6 7步驟可以連續向從機寫數據DATA(D+n);

9. 主機發送結束信號P.

雙字節地址寫時序過程:

581c8b5e-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送寄存器地址信息高字節ADDRESS HIGH BYTE;

5. 從機響應主機發送寄存器地址高字節ACK;

6. 主機發送寄存器地址信息低字節ADDRESS LOW BYTE;

7. 從機響應主機發送寄存器地址低字節ACK;

8. 主機發送單字節數據信息DATA;

9. 從機響應主機發送數據信息ACK;

10. 循環8 9步驟可以連續向從機寫數據DATA(D+n);

11. 主機發送結束信號P.

2.3 IIC讀時序

IIC協議讀時序可分為單字節讀時序和連續讀時序:

2.3.1 單字節讀時序

單字節地址讀時序過程:

5838e736-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送單字節寄存器地址信息WORD ADDRESS;

5. 從機響應主機發送寄存器地址ACK;

6. 主機發送開始信號S;

7. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為1表示主機從從機讀數據;

8. 從機響應主機控制字節ACK;

9. 從機發送單字節數據信息DATA;

10. 主機響應從機發送數據信息NACK(非應答位: 接收器是主機時,在接收到最后一個字節后發送NACK已通知被控發送從機結束數據發送,并釋放SDA數據線以便主機發送停止信號P);

11. 主機發送結束信號P.

雙字節地址讀時序過程:

586baa7c-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送寄存器地址信息高字節ADDRESS HIGH BYTE;

5. 從機響應主機發送寄存器地址高字節ACK;

6. 主機發送寄存器地址信息低字節ADDRESS LOW BYTE;

7. 從機響應主機發送寄存器地址低字節ACK;

8. 主機發送開始信號S;

9. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為1表示主機從從機讀數據;

10. 從機響應主機控制字節ACK;

11. 從機發送單字節數據信息DATA;

12. 主機響應從機發送數據信息NACK(非應答位: 接收器是主機時,在接收到最后一個字節后發送NACK已通知被控發送從機結束數據發送,并釋放SDA數據線以便主機發送停止信號P);

13. 主機發送結束信號P.

2.3.2 連續讀時序

單字節地址讀時序過程:

588c590c-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送單字節寄存器地址信息WORD ADDRESS;

5. 從機響應主機發送寄存器地址ACK;

6. 主機發送開始信號S;

7. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為1表示主機從從機讀數據;

8. 從機響應主機控制字節ACK;

9. 從機發送單字節數據信息DATA;

10. 主機響應從機發送數據信息ACK;

11. 循環9 10步驟可完成主機向從機連續讀數據過程,讀取最后一個字節數據時主機應響應NACK(非應答位: 接收器是主機時,在接收到最后一個字節后發送NACK已通知被控發送從機結束數據發送,并釋放SDA數據線以便主機發送停止信號P);

12. 主機發送結束信號P.

雙字節地址讀時序過程:

58aee86e-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機發送開始信號S;

2. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為0表示主機向從機寫數據;

3. 從機響應主機控制字節ACK;

4. 主機發送寄存器地址信息高字節ADDRESS HIGH BYTE;

5. 從機響應主機發送寄存器地址高字節ACK;

6. 主機發送寄存器地址信息低字節ADDRESS LOW BYTE;

7. 從機響應主機發送寄存器地址低字節ACK;

8. 主機發送開始信號S;

9. 主機發送控制字節CONTROL BYTE(7bits設備地址dev addr和1bit讀寫信號),最低位為1表示主機從從機讀數據;

10. 從機響應主機控制字節ACK;

11. 從機發送單字節數據信息DATA;

12.主機響應從機發送數據信息ACK;

13. 循環11 12步驟可完成主機向從機連續讀數據過程,讀取最后一個字節數據時主機應響應NACK(非應答位: 接收器是主機時,在接收到最后一個字節后發送NACK已通知被控發送從機結束數據發送,并釋放SDA數據線以便主機發送停止信號P);

14. 主機發送結束信號P.

03

IIC代碼實現

3.1 IIC目標實現功能

設計一個IIC模塊,具體要求如下:

設計一個IIC協議提供給主設備,通過查找表實現對從設備寄存器進行配置。按查找表順序lut_index依次對設備地址為lut_dev_addr的從設備寄存器進行配置,為lut_reg_addr配置寄存器數據lut_reg_data,同時將傳輸異常和傳輸結束信號引出以對傳輸過程進行監控。模塊的定義如下:

module i2c(

input rst,//復位信號

input clk, //時鐘信號

input[15:0] clk_div_cnt, //時鐘計數器

input i2c_addr_2byte, //雙字節地址

output reg[9:0] lut_index, //查找表順序號

input[7:0] lut_dev_addr, //從設備地址

input[15:0] lut_reg_addr, //寄存器地址

input[7:0] lut_reg_data, //寄存器數據

output reg error, //傳輸異常信號

output done, //傳輸結束信號

inout i2c_scl, //IIC時鐘信號

inout i2c_sda //IIC數據信號

);

3.2 Verilog代碼

1. 頂層模塊 (i2c):

module i2c(

input rst,

input clk,

input[15:0] clk_div_cnt,

input i2c_addr_2byte,

output reg[9:0] lut_index,

input[7:0] lut_dev_addr,

input[15:0] lut_reg_addr,

input[7:0] lut_reg_data,

output reg error,

output done,

inout i2c_scl,

inout i2c_sda

);

wire scl_pad_i;

wire scl_pad_o;

wire scl_padoen_o;

wire sda_pad_i;

wire sda_pad_o;

wire sda_padoen_o;

assign sda_pad_i = i2c_sda;

assign i2c_sda = ~sda_padoen_o ? sda_pad_o : 1'bz;

assign scl_pad_i = i2c_scl;

assign i2c_scl = ~scl_padoen_o ? scl_pad_o : 1'bz;

reg i2c_read_req;

wire i2c_read_req_ack;

reg i2c_write_req;

wire i2c_write_req_ack;

wire[7:0] i2c_slave_dev_addr;

wire[15:0] i2c_slave_reg_addr;

wire[7:0] i2c_write_data;

wire[7:0] i2c_read_data;

wire err;

reg[2:0] state;

localparam S_IDLE = 0;

localparam S_WR_I2C_CHECK = 1;

localparam S_WR_I2C = 2;

localparam S_WR_I2C_DONE = 3;

assign done = (state == S_WR_I2C_DONE);

assign i2c_slave_dev_addr = lut_dev_addr;

assign i2c_slave_reg_addr = lut_reg_addr;

assign i2c_write_data = lut_reg_data;

//cascatrix carson

always@(posedge clk or posedge rst)

begin

if(rst)

begin

state <= S_IDLE;

error <= 1'b0;

lut_index <= 8'd0;

end

else

case(state)

S_IDLE:

begin

state <= S_WR_I2C_CHECK;

error <= 1'b0;

lut_index <= 8'd0;

end

S_WR_I2C_CHECK:

begin

if(i2c_slave_dev_addr != 8'hff)

begin

i2c_write_req <= 1'b1;

state <= S_WR_I2C;

end

else

begin

state <= S_WR_I2C_DONE;

end

end

S_WR_I2C:

begin

if(i2c_write_req_ack)

begin

error <= err ? 1'b1 : error;?

lut_index <= lut_index + 8'd1;

i2c_write_req <= 1'b0;

state <= S_WR_I2C_CHECK;

end

end

S_WR_I2C_DONE:

begin

state <= S_WR_I2C_DONE;

end

default:

state <= S_IDLE;

endcase

end

i2c_ctrl i2c_ctrl

(

.rst(rst),

.clk(clk),

.clk_div_cnt(clk_div_cnt),

// I2C signals

// i2c clock line

.scl_pad_i(scl_pad_i), // SCL-line input

.scl_pad_o(scl_pad_o), // SCL-line output (always 1'b0)

.scl_padoen_o(scl_padoen_o), // SCL-line output enable (active low)

// i2c data line

.sda_pad_i(sda_pad_i), // SDA-line input

.sda_pad_o(sda_pad_o), // SDA-line output (always 1'b0)

.sda_padoen_o(sda_padoen_o), // SDA-line output enable (active low)

.i2c_read_req(i2c_read_req),

.i2c_addr_2byte(i2c_addr_2byte),

.i2c_read_req_ack(i2c_read_req_ack),

.i2c_write_req(i2c_write_req),

.i2c_write_req_ack(i2c_write_req_ack),

.i2c_slave_dev_addr(i2c_slave_dev_addr),

.i2c_slave_reg_addr(i2c_slave_reg_addr),

.i2c_write_data(i2c_write_data),

.i2c_read_data(i2c_read_data),

.error(err)

);

endmodule

2. 組幀模塊 (i2c_ctrl):

module i2c_ctrl

(

input rst,

input clk,

input[15:0] clk_div_cnt,

// I2C signals

// i2c clock line

input scl_pad_i, //SCL-line input

output scl_pad_o, //SCL-line output (always 1'b0)

output scl_padoen_o, //SCL-line output enable (active low)

// i2c data line

input sda_pad_i, //SDA-line input

output sda_pad_o, //SDA-line output (always 1'b0)

output sda_padoen_o, //SDA-line output enable (active low)

input i2c_addr_2byte, //register address 16bit or 8bit

input i2c_read_req, //Read register request

output i2c_read_req_ack, //Read register request response

input i2c_write_req, //Write register request

output i2c_write_req_ack, //Write register request response

input[7:0] i2c_slave_dev_addr, //I2c device address

input[15:0] i2c_slave_reg_addr, //I2c register address

input[7:0] i2c_write_data, //I2c write register data

output reg[7:0] i2c_read_data,//I2c read register data

output reg error //The error indication, generally there is no response

);

//State machine definition cascatrix carson

localparam S_IDLE= 0;

localparam S_WR_DEV_ADDR=1;

localparam S_WR_REG_ADDR=2;

localparam S_WR_DATA=3;

localparam S_WR_ACK=4;

localparam S_WR_ERR_NACK=5;

localparam S_RD_DEV_ADDR0=6;

localparam S_RD_REG_ADDR=7;

localparam S_RD_DEV_ADDR1=8;

localparam S_RD_DATA=9;

localparam S_RD_STOP=10;

localparam S_WR_STOP=11;

localparam S_WAIT=12;

localparam S_WR_REG_ADDR1=13;

localparam S_RD_REG_ADDR1=14;

localparam S_RD_ACK=15;

reg start;

reg stop;

reg read;

reg write;

reg ack_in;

reg[7:0] txr;

wire[7:0] rxr;

wire i2c_busy;

wire i2c_al;

wire done;

wire irxack;

reg[3:0] state, next_state;

assign i2c_read_req_ack = (state == S_RD_ACK);

assign i2c_write_req_ack = (state == S_WR_ACK);

always@(posedge clk or posedge rst)

begin

if(rst)

state <= S_IDLE;

else

state <= next_state;? ??

end

always@(*)

begin

case(state)

S_IDLE:

//Waiting for read and write requests

if(i2c_write_req)

next_state <= S_WR_DEV_ADDR;

else if(i2c_read_req)

next_state <= S_RD_DEV_ADDR0;

else

next_state <= S_IDLE;

//Write I2C device address

S_WR_DEV_ADDR:

if(done && irxack)

next_state <= S_WR_ERR_NACK;

else if(done)

next_state <= S_WR_REG_ADDR;

else

next_state <= S_WR_DEV_ADDR;

//Write the address of the I2C register

S_WR_REG_ADDR:

if(done)

//If it is the 8bit register address, it enters the write data state

next_state<=i2c_addr_2byte? S_WR_REG_AD DR1? : S_WR_DATA;

else

next_state <= S_WR_REG_ADDR;

S_WR_REG_ADDR1:

if(done)

next_state <= S_WR_DATA;

else

next_state <= S_WR_REG_ADDR1;?

//Write data

S_WR_DATA:

if(done)

next_state <= S_WR_STOP;

else

next_state <= S_WR_DATA;

S_WR_ERR_NACK:

next_state <= S_WR_STOP;

S_RD_ACK,S_WR_ACK:

next_state <= S_WAIT;

S_WAIT:

next_state <= S_IDLE;

S_RD_DEV_ADDR0:

if(done && irxack)

next_state <= S_WR_ERR_NACK;

else if(done)

next_state <= S_RD_REG_ADDR;

else

next_state <= S_RD_DEV_ADDR0;

S_RD_REG_ADDR:

if(done)

next_state<=i2c_addr_2byte?S_RD_REG_ADDR1 : S_RD_DEV_ADDR1;

else

next_state <= S_RD_REG_ADDR;

S_RD_REG_ADDR1:

if(done)

next_state <= S_RD_DEV_ADDR1;

else

next_state <= S_RD_REG_ADDR1;? ? ? ? ? ? ? ?

S_RD_DEV_ADDR1:

if(done)

next_state <= S_RD_DATA;

else

next_state <= S_RD_DEV_ADDR1;? ?

S_RD_DATA:

if(done)

next_state <= S_RD_STOP;

else

next_state <= S_RD_DATA;

S_RD_STOP:

if(done)

next_state <= S_RD_ACK;

else

next_state <= S_RD_STOP;

S_WR_STOP:

if(done)

next_state <= S_WR_ACK;

else

next_state <= S_WR_STOP;? ? ? ? ? ? ? ??

default:

next_state <= S_IDLE;

endcase

end

always@(posedge clk or posedge rst)

begin

if(rst)

error <= 1'b0;

else if(state == S_IDLE)

error <= 1'b0;

else if(state == S_WR_ERR_NACK)

error <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

start <= 1'b0;

else if(done)

start <= 1'b0;

else if(state == S_WR_DEV_ADDR || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1)

start <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

stop <= 1'b0;

else if(done)

stop <= 1'b0;

else if(state == S_WR_STOP || state == S_RD_STOP)

stop <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

ack_in <= 1'b0;

else

ack_in <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

write <= 1'b0;

else if(done)

write <= 1'b0;

else if(state == S_WR_DEV_ADDR || state == S_WR_REG_ADDR || state == S_WR_REG_ADDR1|| state == S_WR_DATA || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1 || state == S_RD_REG_ADDR || state == S_RD_REG_ADDR1)

write <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

read <= 1'b0;

else if(done)

read <= 1'b0;

else if(state == S_RD_DATA)

read <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

i2c_read_data <= 8'h00;

else if(state == S_RD_DATA && done)

i2c_read_data <= rxr;

end

always@(posedge clk or posedge rst)

begin

if(rst)

txr <= 8'd0;

else

case(state)

S_WR_DEV_ADDR,S_RD_DEV_ADDR0:

txr <= {i2c_slave_dev_addr[7:1],1'b0};

S_RD_DEV_ADDR1:

txr <= {i2c_slave_dev_addr[7:1],1'b1};

S_WR_REG_ADDR,S_RD_REG_ADDR:

txr<=(i2c_addr_2byte==1'b1)?i2c_slave_reg_addr[15 :8] : i2c_slave_reg_addr[7:0];

S_WR_REG_ADDR1,S_RD_REG_ADDR1:

txr <= i2c_slave_reg_addr[7:0];? ? ? ? ? ? ?

S_WR_DATA:

txr <= i2c_write_data;

default:

txr <= 8'hff;

endcase

end

i2c_byte_ctrl byte_controller (

.clk ( clk ),

.rst ( rst ),

.nReset ( 1'b1 ),

.ena ( 1'b1 ),

.clk_cnt ( clk_div_cnt ),

.start ( start ),

.stop ( stop ),

.read ( read ),

.write ( write ),

.ack_in ( ack_in ),

.din ( txr ),

.cmd_ack ( done ),

.ack_out ( irxack ),

.dout ( rxr ),

.i2c_busy ( i2c_busy ),

.i2c_al ( i2c_al ),

.scl_i ( scl_pad_i ),

.scl_o ( scl_pad_o ),

.scl_oen ( scl_padoen_o ),

.sda_i ( sda_pad_i ),

.sda_o ( sda_pad_o ),

.sda_oen ( sda_padoen_o )

);

endmodule

3. 字節控制模塊(i2c_byte_ctrl):

`define I2C_CMD_NOP 4'b0000

`define I2C_CMD_START 4'b0001

`define I2C_CMD_STOP 4'b0010

`define I2C_CMD_WRITE 4'b0100

`define I2C_CMD_READ 4'b1000

module i2c_byte_ctrl (

input clk, // master clock

input rst, // synchronous active high reset

input nReset, // asynchronous active low reset

input ena, // core enable signal

input [15:0] clk_cnt, // 4x SCL

// control inputs

input start,

input stop,

input read,

input write,

input ack_in,

input [7:0] din,

// status outputs

output reg cmd_ack,

output regack_out,

output i2c_busy,

output i2c_al,

output [7:0] dout,

// I2C signals

input scl_i,

output scl_o,

output scl_oen,

input sda_i,

output sda_o,

output sda_oen

);

//

// Variable declarations cascatrix carson

//

// statemachine

parameter [4:0] ST_IDLE = 5'b0_0000;

parameter [4:0] ST_START = 5'b0_0001;

parameter [4:0] ST_READ = 5'b0_0010;

parameter [4:0] ST_WRITE = 5'b0_0100;

parameter [4:0] ST_ACK = 5'b0_1000;

parameter [4:0] ST_STOP = 5'b1_0000;

// signals for bit_controller

reg [3:0] core_cmd;

reg core_txd;

wire core_ack, core_rxd;

// signals for shift register

reg [7:0] sr; //8bit shift register

reg shift, ld;

// signals for state machine

wire go;

reg [2:0] dcnt;

wire cnt_done;

// bit_controller

i2c_bit_ctrl bit_controller (

.clk ( clk ),

.rst ( rst ),

.nReset ( nReset ),

.ena ( ena ),

.clk_cnt ( clk_cnt ),

.cmd ( core_cmd ),

.cmd_ack ( core_ack ),

.busy ( i2c_busy ),

.al ( i2c_al ),

.din ( core_txd ),

.dout ( core_rxd ),

.scl_i ( scl_i ),

.scl_o ( scl_o ),

.scl_oen ( scl_oen ),

.sda_i ( sda_i ),

.sda_o ( sda_o ),

.sda_oen ( sda_oen )

);

// generate go-signal

assign go = (read | write | stop) & ~cmd_ack;

// assign dout output to shift-register

assign dout = sr;

// generate shift register

always @(posedge clk or negedge nReset)

if (!nReset)

sr <= #1 8'h0;

else if (rst)

sr <= #1 8'h0;

else if (ld)

sr <= #1 din;

else if (shift)

sr <= #1 {sr[6:0], core_rxd};

// generate counter

always @(posedge clk or negedge nReset)

if (!nReset)

dcnt <= #1 3'h0;

else if (rst)

dcnt <= #1 3'h0;

else if (ld)

dcnt <= #1 3'h7;

else if (shift)

dcnt <= #1 dcnt - 3'h1;

assign cnt_done = ~(|dcnt);

//

// state machine

//

reg [4:0] c_state; // synopsys enum_state

always @(posedge clk or negedge nReset)

if (!nReset)

begin

core_cmd <= #1 `I2C_CMD_NOP;

core_txd <= #1 1'b0;

shift <= #1 1'b0;

ld <= #1 1'b0;

cmd_ack <= #1 1'b0;

c_state <= #1 ST_IDLE;

ack_out <= #1 1'b0;

end

else if (rst | i2c_al)

begin

core_cmd <= #1 `I2C_CMD_NOP;

core_txd <= #1 1'b0;

shift <= #1 1'b0;

ld <= #1 1'b0;

cmd_ack <= #1 1'b0;

c_state <= #1 ST_IDLE;

ack_out <= #1 1'b0;

end

else

begin

// initially reset all signals

core_txd <= #1 sr[7];

shift <= #1 1'b0;

ld <= #1 1'b0;

cmd_ack <= #1 1'b0;

case (c_state) // synopsys full_case parallel_case

ST_IDLE:

if (go)

begin

if (start)

begin

c_state <= #1 ST_START;

core_cmd <= #1 `I2C_CMD_START;

end

else if (read)

begin

c_state <= #1 ST_READ;

core_cmd <= #1 `I2C_CMD_READ;

end

else if (write)

begin

c_state <= #1 ST_WRITE;

core_cmd <= #1 `I2C_CMD_WRITE;

end

else // stop

begin

c_state <= #1 ST_STOP;

core_cmd <= #1 `I2C_CMD_STOP;

end

ld <= #1 1'b1;

end

ST_START:

if (core_ack)

begin

if (read)

begin

c_state <= #1 ST_READ;

core_cmd <= #1 `I2C_CMD_READ;

end

else

begin

c_state <= #1 ST_WRITE;

core_cmd <= #1 `I2C_CMD_WRITE;

end

ld <= #1 1'b1;

end

ST_WRITE:

if (core_ack)

if (cnt_done)

begin

c_state <= #1 ST_ACK;

core_cmd <= #1 `I2C_CMD_READ;

end

else

begin

// stay in same state

c_state <= #1 ST_WRITE;? ? ? ?

// write next bit

core_cmd <= #1 `I2C_CMD_WRITE;?

shift <= #1 1'b1;

end

ST_READ:

if (core_ack)

begin

if (cnt_done)

begin

c_state <= #1 ST_ACK;

core_cmd <= #1 `I2C_CMD_WRITE;

end

else

begin

// stay in same state

c_state <= #1 ST_READ;? ? ? ?

// read next bit

core_cmd <= #1 `I2C_CMD_READ;

end

shift <= #1 1'b1;

core_txd <= #1 ack_in;

end

ST_ACK:

if (core_ack)

begin

if (stop)

begin

c_state <= #1 ST_STOP;

core_cmd <= #1 `I2C_CMD_STOP;

end

else

begin

c_state <= #1 ST_IDLE;

core_cmd <= #1 `I2C_CMD_NOP;

// generate command acknowledge signal

cmd_ack <= #1 1'b1;

end

// assign ack_out output to bit_controller_rxd (contains last received bit)

ack_out <= #1 core_rxd;

core_txd <= #1 1'b1;

end

else

core_txd <= #1 ack_in;

ST_STOP:

if (core_ack)

begin

c_state <= #1 ST_IDLE;

core_cmd <= #1 `I2C_CMD_NOP;

// generate command acknowledge signal

cmd_ack <= #1 1'b1;

end

endcase

end

endmodule

4. bit控制模塊(i2c_bit_ctrl):

`define I2C_CMD_NOP 4'b0000

`define I2C_CMD_START 4'b0001

`define I2C_CMD_STOP 4'b0010

`define I2C_CMD_WRITE 4'b0100

`define I2C_CMD_READ 4'b1000

module i2c_bit_ctrl (

input clk, // system clock

input rst, // synchronous active high reset

input nReset, // asynchronous active low reset

input ena, // core enable signal

input [15:0] clk_cnt, // clock prescale value

input [ 3:0] cmd, // command (from byte controller)

output reg cmd_ack, // command complete acknowledge

output reg busy, // i2c bus busy

output reg al, // i2c bus arbitration lost

input din,

output reg dout,

input scl_i, // i2c clock line input

output scl_o, // i2c clock line output

output reg scl_oen, // i2c clock line output enable (active low)

input sda_i, // i2c data line input

output sda_o, // i2c data line output

output reg sda_oen // i2c data line output enable (active low)

);

//

// variable declarations

//

reg [ 1:0] cSCL, cSDA; // capture SCL and SDA

reg [ 2:0] fSCL, fSDA; // SCL and SDA filter inputs

reg sSCL, sSDA; // filtered and synchronized SCL and SDA inputs

reg dSCL, dSDA; // delayed versions of sSCL and sSDA

reg dscl_oen; // delayed scl_oen

reg sda_chk; // check SDA output (Multi-master arbitration)

reg clk_en; // clock generation signals

reg slave_wait; // slave inserts wait states

reg [15:0] cnt; // clock divider counter (synthesis)

reg [13:0] filter_cnt; // clock divider for filter

// state machine variable

reg [17:0] c_state; // synopsys enum_state

//

// module body

//

// whenever the slave is not ready it can delay the cycle by pulling SCL low

// delay scl_oen

always @(posedge clk)

dscl_oen <= #1 scl_oen;

// slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low

// slave_wait remains asserted until the slave releases SCL

always @(posedge clk or negedge nReset)

if (!nReset) slave_wait <= 1'b0;

else slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);

// master drives SCL high, but another master pulls it low

// master start counting down its low cycle now (clock synchronization)

wire scl_sync = dSCL & ~sSCL & scl_oen;

// generate clk enable signal

always @(posedge clk or negedge nReset)

if (~nReset)

begin

cnt <= #1 16'h0;

clk_en <= #1 1'b1;

end

else if (rst || ~|cnt || !ena || scl_sync)

begin

cnt <= #1 clk_cnt;

clk_en <= #1 1'b1;

end

else if (slave_wait)

begin

cnt <= #1 cnt;

clk_en <= #1 1'b0;? ??

end

else

begin

cnt <= #1 cnt - 16'h1;

clk_en <= #1 1'b0;

end

// generate bus status controller

// capture SDA and SCL

// reduce metastability risk

always @(posedge clk or negedge nReset)

if (!nReset)

begin

cSCL <= #1 2'b00;

cSDA <= #1 2'b00;

end

else if (rst)

begin

cSCL <= #1 2'b00;

cSDA <= #1 2'b00;

end

else

begin

cSCL <= {cSCL[0],scl_i};

cSDA <= {cSDA[0],sda_i};

end

// filter SCL and SDA signals; (attempt to) remove glitches

always @(posedge clk or negedge nReset)

if (!nReset ) filter_cnt <= 14'h0;

else if (rst || !ena ) filter_cnt <= 14'h0;

else if (~|filter_cnt) filter_cnt <= clk_cnt >> 2; //16x I2C bus frequency

else filter_cnt <= filter_cnt -1;

always @(posedge clk or negedge nReset)

if (!nReset)

begin

fSCL <= 3'b111;

fSDA <= 3'b111;

end

else if (rst)

begin

fSCL <= 3'b111;

fSDA <= 3'b111;

end

else if (~|filter_cnt)

begin

fSCL <= {fSCL[1:0],cSCL[1]};

fSDA <= {fSDA[1:0],cSDA[1]};

end

// generate filtered SCL and SDA signals

always @(posedge clk or negedge nReset)

if (~nReset)

begin

sSCL <= #1 1'b1;

sSDA <= #1 1'b1;

dSCL <= #1 1'b1;

dSDA <= #1 1'b1;

end

else if (rst)

begin

sSCL <= #1 1'b1;

sSDA <= #1 1'b1;

dSCL <= #1 1'b1;

dSDA <= #1 1'b1;

end

else

begin

sSCL <= #1 &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);

sSDA <= #1 &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);

dSCL <= #1 sSCL;

dSDA <= #1 sSDA;

end

// detect start condition => detect falling edge on SDA while SCL is high

// detect stop condition => detect rising edge on SDA while SCL is high

reg sta_condition;

reg sto_condition;

always @(posedge clk or negedge nReset)

if (~nReset)

begin

sta_condition <= #1 1'b0;

sto_condition <= #1 1'b0;

end

else if (rst)

begin

sta_condition <= #1 1'b0;

sto_condition <= #1 1'b0;

end

else

begin

sta_condition <= #1 ~sSDA &? dSDA & sSCL;

sto_condition <= #1? sSDA & ~dSDA & sSCL;

end

// generate i2c bus busy signal

always @(posedge clk or negedge nReset)

if (!nReset) busy <= #1 1'b0;

else if (rst ) busy <= #1 1'b0;

else busy <= #1 (sta_condition | busy) & ~sto_condition;

// generate arbitration lost signal cascatrix carson

// aribitration lost when:

// 1) master drives SDA high, but the i2c bus is low

// 2) stop detected while not requested

reg cmd_stop;

always @(posedge clk or negedge nReset)

if (~nReset)

cmd_stop <= #1 1'b0;

else if (rst)

cmd_stop <= #1 1'b0;

else if (clk_en)

cmd_stop <= #1 cmd == `I2C_CMD_STOP;

always @(posedge clk or negedge nReset)

if (~nReset)

al <= #1 1'b0;

else if (rst)

al <= #1 1'b0;

else

al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);

// generate dout signal (store SDA on rising edge of SCL) cascatrix carson

always @(posedge clk)

if (sSCL & ~dSCL) dout <= #1 sSDA;

// generate statemachine cascatrix carson

// nxt_state decoder

parameter [17:0] idle = 18'b0_0000_0000_0000_0000;

parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;

parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;

parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;

parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;

parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;

parameter [17:0] stop_a = 18'b0_0000_0000_0010_0000;

parameter [17:0] stop_b = 18'b0_0000_0000_0100_0000;

parameter [17:0] stop_c = 18'b0_0000_0000_1000_0000;

parameter [17:0] stop_d = 18'b0_0000_0001_0000_0000;

parameter [17:0] rd_a = 18'b0_0000_0010_0000_0000;

parameter [17:0] rd_b = 18'b0_0000_0100_0000_0000;

parameter [17:0] rd_c = 18'b0_0000_1000_0000_0000;

parameter [17:0] rd_d = 18'b0_0001_0000_0000_0000;

parameter [17:0] wr_a = 18'b0_0010_0000_0000_0000;

parameter [17:0] wr_b = 18'b0_0100_0000_0000_0000;

parameter [17:0] wr_c = 18'b0_1000_0000_0000_0000;

parameter [17:0] wr_d = 18'b1_0000_0000_0000_0000;

always @(posedge clk or negedge nReset)

if (!nReset)

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b0;

scl_oen <= #1 1'b1;

sda_oen <= #1 1'b1;

sda_chk <= #1 1'b0;

end

else if (rst | al)

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b0;

scl_oen <= #1 1'b1;

sda_oen <= #1 1'b1;

sda_chk <= #1 1'b0;

end

else

begin

// default no command acknowledge + assert cmd_ack only 1clk cycle

cmd_ack <= #1 1'b0;?

if (clk_en)// synopsys full_case parallel_case

case (c_state)

// idle state

idle:

begin// synopsys full_case parallel_case

case (cmd)

`I2C_CMD_START: c_state <= #1 start_a;

`I2C_CMD_STOP: c_state <= #1 stop_a;

`I2C_CMD_WRITE: c_state <= #1 wr_a;

`I2C_CMD_READ: c_state <= #1 rd_a;

default: c_state <= #1 idle;

endcase

// keep SCL in same state

scl_oen <= #1 scl_oen;?

// keep SDA in same state

sda_oen <= #1 sda_oen;

// don't check SDA output

sda_chk <= #1 1'b0;? ??

end

// start

start_a:

begin

c_state <= #1 start_b;

// keep SCL in same state

scl_oen <= #1 scl_oen;?

sda_oen <= #1 1'b1;? ? // set SDA high

// don't check SDA output

sda_chk <= #1 1'b0;? ??

end

start_b:

begin

c_state <= #1 start_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 1'b1; // keep SDA high

// don't check SDA output

sda_chk <= #1 1'b0;?

end

start_c:

begin

c_state <= #1 start_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b0; // set SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

start_d:

begin

c_state <= #1 start_e;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

start_e:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b0; // set SCL low

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

// stop

stop_a:

begin

c_state <= #1 stop_b;

scl_oen <= #1 1'b0; // keep SCL low

sda_oen <= #1 1'b0; // set SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

stop_b:

begin

c_state <= #1 stop_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

stop_c:

begin

c_state <= #1 stop_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

stop_d:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b1; // set SDA high

// don't check SDA output

sda_chk <= #1 1'b0;?

end

// read

rd_a:

begin

c_state <= #1 rd_b;

scl_oen <= #1 1'b0; // keep SCL low

sda_oen <= #1 1'b1; // tri-state SDA

// don't check SDA output

sda_chk <= #1 1'b0;?

end

rd_b:

begin

c_state <= #1 rd_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 1'b1; // keep SDA tri-stated

// don't check SDA output

sda_chk <= #1 1'b0;?

end

rd_c:

begin

c_state <= #1 rd_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b1; // keep SDA tri-stated

// don't check SDA output

sda_chk <= #1 1'b0;

end

rd_d:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b0; // set SCL low

sda_oen <= #1 1'b1; // keep SDA tri-stated

// don't check SDA output

sda_chk <= #1 1'b0;?

end

// write

wr_a:

begin

c_state <= #1 wr_b;

scl_oen <= #1 1'b0; // keep SCL low

sda_oen <= #1 din;? // set SDA

// don't check SDA output (SCL low)

sda_chk <= #1 1'b0;?

end

wr_b:

begin

c_state <= #1 wr_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 din;? // keep SDA

// don't check SDA output yet

sda_chk <= #1 1'b0;?

// allow some time for SDA and SCL to settle

end

wr_c:

begin

c_state <= #1 wr_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 din;

sda_chk <= #1 1'b1; // check SDA output

end

wr_d:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b0; // set SCL low

sda_oen <= #1 din;

sda_chk <= #1 1'b0; // don't check SDA output (SCL low)

end

endcase

end

// assign scl and sda output (always gnd)

assign scl_o = 1'b0;

assign sda_o = 1'b0;

endmodule

04

IIC的優缺點

4.1 IIC協議優點

1. 通信只需要兩條信號線;

2. 多主設備結構下,總線系統無需額外的邏輯與線路;

3. 應答機制完善,通信傳輸穩定。

4.2 IIC協議缺點

1. 硬件結構復雜;

2. 支持傳輸距離較短;

3. 半雙工速率慢于全雙工,SPI全雙工一般可實現10Mbps以上的傳輸速率,IIC最高速度僅能達到3.4Mbps。








審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 上拉電阻
    +關注

    關注

    5

    文章

    359

    瀏覽量

    30609
  • IIC總線
    +關注

    關注

    1

    文章

    66

    瀏覽量

    20297
  • SDA
    SDA
    +關注

    關注

    0

    文章

    124

    瀏覽量

    28127
  • SCL
    SCL
    +關注

    關注

    1

    文章

    239

    瀏覽量

    17057

原文標題:常用串行總線(三)——IIC協議(Verilog實現)

文章出處:【微信號:Carlinx FPGA,微信公眾號:Carlinx FPGA】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    FPGA實現IIC協議的設計

    今天給大家帶來的是IIC通信,IIC協議應用非常廣泛,例如與MPU6050進行通信,配置OV5640攝像頭、驅動OLED屏幕等等,都需要使用到IIC
    的頭像 發表于 03-04 10:49 ?1247次閱讀
    FPGA<b class='flag-5'>實現</b><b class='flag-5'>IIC</b><b class='flag-5'>協議</b>的設計

    用verilog實現IIC

    我想用verilog實現一個控制AT24C08讀寫的IIC協議的狀態機,現在出現了一個很奇怪的問題,我的狀態機在功能仿真時可以實現讀寫,但下到芯片里卻發現不成功。特此求教大家,望大家不
    發表于 01-29 11:18

    IIc 協議及VHDL代碼實現

    位在前。3.2.2位時序和實現3.2.2.1IIC的通信協議:主機和從機在 iic總線上通信的時候, 它們之間有用類似 “ hello” ( 起始信號)和 “ Goodbye”(結束信
    發表于 04-07 13:12

    spi,uart,iic協議之間的對比

    spi,uart,iic協議之間的對比:spi和uart的區別,spi結構上可以實現一主多從進行通信,依靠時鐘進行傳輸數據的同步傳輸模式。S
    發表于 08-19 08:41

    IIC協議總線特點簡介

    IIC協議簡介I2C 通訊協議(Inter-Integrated Circuit)是由Phiilps公司開發的,由于它引腳少,硬件實現簡單,可擴展性強,不需要USART、CAN等通訊
    發表于 08-20 06:12

    STM32的IIC協議簡介

    、地址及數據方向4.5、響應(五)STM32的IIC特性及架構5.1、STM32的IIC外設簡介5.2、STM32的IIC架構剖析5.3、通信過程IIC
    發表于 01-05 06:13

    IIC協議原理是什么

    連接微控制器以及其外圍設備,IIC也被成為I2C,其實兩者是完全相同的,只是名詞不一樣而已。它是由數據線SDA和時鐘線SCL構成的串行總線,可發送和接收數據。IIC特點:①數據線SDA:數據線用來
    發表于 01-06 06:23

    IIC協議的相關資料推薦

    STM32 IIC實驗講解,從入門到放棄。文章目錄STM32 IIC實驗講解,從入門到放棄。前言一、IICIIC是什么?IIC協議二、代碼
    發表于 01-17 08:12

    IIC協議軟件模擬方法

    關于iic協議和對AT24C16進行讀寫數據的代碼解讀認識IIC協議IIC
    發表于 02-09 07:00

    介紹IIC通信協議以及代碼開發的注意事項

    FPGA IIC接口通信本文介紹IIC通信協議以及代碼開發的注意事項,跑通了IIC協議,那么后續
    發表于 02-16 07:24

    如何使用代碼實現IIC協議

    1. 綜述  由上篇博客可知道IIC協議如何用代碼實現,本篇博客就不涉及協議內容,只講解如何使用。  本次的實驗傳感為:DS3231(時鐘模
    發表于 02-21 06:36

    IIC通信以及AT24C02使用

    文章目錄1.什么是通信協議①什么是IIC協議IIC協議原理講解③IIC
    發表于 11-30 20:51 ?15次下載
    <b class='flag-5'>IIC</b>通信以及AT24C02使用

    關于iic協議和對AT24C02進行讀寫數據的理解和代碼解讀

    關于iic協議和對AT24C16進行讀寫數據的代碼解讀認識IIC協議IIC
    發表于 12-05 16:36 ?8次下載
    關于<b class='flag-5'>iic</b><b class='flag-5'>協議</b>和對AT24C02進行讀寫數據的理解和<b class='flag-5'>代碼</b>解讀

    3行代碼實現單片機IIc通信

    文章目錄前言一、實現功能二、接線圖三、完整代碼四、代碼運行效果前言shineblink core 開發板(簡稱Core)的庫函數支持IIc通信功能,所以只需要調用兩三個API,即可
    發表于 12-20 19:19 ?1次下載
    3行<b class='flag-5'>代碼</b><b class='flag-5'>實現</b>單片機<b class='flag-5'>IIc</b>通信

    詳解物聯網常用協議IIC和RS485通信協議

    科技常用的兩種通信協議——IIC和RS485。IIC通信協議是一種半雙工通信協議,雙總線串行,主要用在主機和從機對于數據量較少且
    的頭像 發表于 03-02 17:12 ?1453次閱讀
    詳解物聯網常用<b class='flag-5'>協議</b>:<b class='flag-5'>IIC</b>和RS485通信<b class='flag-5'>協議</b>
    主站蜘蛛池模板: 久久影院午夜理论片无码| a免费视频| 浴室里强摁做开腿呻吟的漫画男男| 少女亚洲free| 亚洲风情无码免费视频| 亚洲AV日韩AV欧美在线观看网 | 久久精品视在线-2| 免费毛片试看| 日本免费无码A专区在线观看| 善良的女房东味道2在线观看| 涩涩游戏盒| 亚洲女初尝黑人巨磁链接| 亚洲精品中文字幕在线| 92午夜免费福利757| 国产AV精品国语对白国产| 国产亚洲精品久久久999无毒| 精品久久久久中文字幕加勒比东京热 | 国产精品久久久久久久久无码| 花蝴蝶hd免费| 奇米精品一区二区三区在线观看| 熟女人妻AV五十路六十路| 亚洲综合无码一区二区| chinese极品嫩模videos| 国产免费午夜高清| 免费观看的毛片| 小柔的性放荡羞辱日记| A级毛片高清免费网站不卡| 国产女高清在线看免费观看| 免费无码又爽又黄又刺激网站| 小p孩玩成年女性啪啪资源| asian4you裸模| 久久九九免费| 午夜男人免费福利视频| 99久久国产免费福利| 回复术士人生重启在线观看| 青草在线在线d青草在线| 在线不卡日本v二区| 国产亚洲精品久久久久久入口| 欧美 亚洲 日韩 中文2019 | 日韩视频中文字幕精品偷拍| 91九色麻豆|