進階項目(9)IIC通信協議程序設計講解


寫在前面的話

IIC的通信協議和通信接口在很多工程中有廣泛的應用,如數據采集領域的串行AD,圖像處理領域的攝像頭配置,工業控制領域的X射線管配置等等。除此之外,由於IIC協議占用的IO資源特別少,連接方便,所以工程中也常選用IIC接口做為不同芯片間的通信協議。

IIC協議的完成靠的是嚴緊的時序,一個周期都不能錯,這也正是夢翼師兄設置本實驗的目的。通過IIC的學習,鍛煉大家的時序實現技巧和方法,可以說最佳的案例之一。

項目需求

設計IIC接口的驅動電路可以實現單字節數據的讀寫。

 

IIC的原理分析

 

本實驗,我們采用的外部接口芯片為EEPROM 24LC64,其封裝圖如下:

接下來,我們梳理一下各引腳定義:

A0,A1,A2為24LC64的片選信號,由於IIC總線可以掛載多個IIC接口器件,所以每個器件都應該有自己的“身份標識”,通過對A0,A1,A2輸入不同的高低電平,就可以設置該EEPROM的片選信號。

WP為讀寫使能信號,當WP懸空或者接地,EEPROM可讀可寫,當WP接電源,EEPROM只能讀不能寫。

SCL為IIC接口的時鍾線(根據不同的配置方式,scl的頻率是可以改變的,我們采取200K)

SDA為IIC接口的數據線

得到了上面的配置信息,那么接下來,看一下我們開發板的配置原理圖

由此可以看出我們的位選信號為“000”,EEPROM可讀寫。而我們最需要關心的,就是SCL和SDA兩條線的時序關系。

原理圖分析完畢,接下來我們學習一下IIC接口的具體時序是什么。IIC讀寫時序分為隨機讀寫和頁面讀寫,也就是常說的Byte Write/Read 和Page Write/Read。

我們首先來學習Byte Write/Read時序。Byte Write時序如下:

由時序圖可以看出,如果我們要向EEPROM寫入一個字節,那么必須經過以下步驟:

發送啟動信號

發送控制字

接收並檢測EEPROM發來的應答信號ACK

發送高字節地址位

接收並檢測EEPROM發來的應答信號ACK

發送低字節地址位

接收並檢測EEPROM發來的應答信號ACK

發送8bit有效數據

接收並檢測EEPROM發來的應答信號ACK

10.發送停止信號

Byte Read時序如下:

 

 

由時序圖可以看出,如果我們要從EEPROM讀出一個字節,那么必須經過以下步驟:

1. 發送啟動信號

  1. 發送控制字1010_0000
  2. 接收並檢測EEPROM發來的應答信號ACK
  3. 發送高字節地址位
  4. 接收並檢測EEPROM發來的應答信號ACK
  5. 發送低字節地址位
  6. 接收並檢測EEPROM發來的應答信號ACK
  7. 發送啟動信號
  8. 發送控制字1010_0001
  9. 接收並檢測EEPROM發來的應答信號ACK
  10. 讀取一個字節數據
  11. 發送NO ACK信號
  12. 發送停止信號

那么現在的問題就變成了每個步驟的意義到底是什么呢?各位且聽我慢慢道來。

1.啟動信號

 

 

 

 

SCL保持高電平期間,如果SDA出現由高到低的跳變沿,代表啟動信號

2.控制字

我們的控制字為1010_0000或1010_0001,其中1010為EEPROM的型號標識,為一組固定的序列,緊接着A2,A1,A0就是我們的片選信號,最后一位為讀寫控制位,低電平代表寫,高電平代表讀,我們這里首先需要對EEPROM寫入地址位,所以我們最后一位為0。當我們需要讀數據時,最后一位為1。

/低位地址

由於24LC64有64Kbit的存儲空間,所以我們需要13位的地址位寬才能尋址所有的存儲空間,由於IIC協議規定只能以字節形式寫入,所以必須將13位的地址擴展為16位的地址,分為高八位和低八位,多出來的前三位填充任意數據即可,對我們的尋址地址沒有影響。

3.停止信號

 

 

 

 

SCL保持高電平期間,如果SDA出現由低到高的跳變沿,代表停止信號

4.應答信號ACK

應答信號是由數據接收方發出的,當SCL為高電平期間,如果監測到SDA為低電平,說明有應答信號。

5.非應答信號NO ACK

非應答信號也是由數據接收方發出的,當SCL為高電平期間,如果SDA為高電平,說明有非應答信號。

由於IIC總線協議啟動和停止信號都是在SCL高電平期間發生跳變(當不發送或者接收數據的時候scl一直為高電平),這就決定了我們其他數據的改變只能發生在SCL低電平期間,在SCL為高電平期間,數據必須保持穩定。即在SCL低電平改變數據,在SCL高電平采集數據。

由於讀時序和寫時序一直到低字節地址的寫入之前都是相同的,因此我們設置IIC控制器流程圖如下:

接下來,我們來學習Page Write/Read時序

Page Write時序如下:

 

Page Read時序如下:

 

由此可以看出,頁面讀寫比隨機讀寫只是多加了幾個狀態而已,在我們前面設計的基礎上加幾個狀態就可以完成。夢翼師兄把這部分交給大家去發揮。

架構設計

根據原理分析,我們設計出架構圖如下:

 

模塊功能介紹

模塊名

功能描述

IIC

iic總線的驅動

頂層模塊端口描述

端口名

端口說明

clk

系統時鍾輸入

rst_n

系統復位

key_wr

寫信號(低電平有效)

key_rd

讀信號(低電平有效)

data_in[7:0]

輸入數據

scl

iic的時鍾線

sda

iic的數據線

data_out[7:0]

輸出數據

代碼解釋


iic模塊代碼

/****************************************************          

 *   Engineer      :   夢翼師兄

 *   QQ             :   761664056

 *   The module function: 產生iic總線的控制信號

*****************************************************/

000 module iic( 

001             clk, //外部輸入時鍾

002             rst_n,//系統復位

003             key_wr,//寫信號(低電平有效)

004             key_rd, //讀信號(低電平有效)

005             data_in, //輸入數據

006             scl, //iic的數據線

007             sda, //iic的時鍾線

008             data_out//輸出數據

009         );

010     //系統輸入

011     input clk;//外部輸入時鍾

012     input rst_n;//系統復位

013     input key_wr;//寫信號(低電平有效)

014     input key_rd;//讀信號(低電平有效)

015     input [7:0] data_in;//輸入數據

016     //系統輸出

017     output reg scl;//iic的時鍾線

018     output reg [7:0] data_out;//輸出數據

019     

020     inout sda; //iic的數據線

021     

022     reg sda_buffer;//寫入數據的中間寄存器

023     reg flag;//控制系統是否占有總線控制權

024     

025     assign sda = (flag) ? sda_buffer : 1'bz;//flag為高電平時,系統擁有總線控制權

026                                             //並發送sda_buffer中的數據。當flag為低電平時,

027                                             //釋放總線。

028     

029     reg [7:0] count;//計數器

030     reg clk_sys;//系統時鍾

031 //-------------------------------clk_sys

032     always @ (posedge clk or negedge rst_n)

033     begin

034         if (!rst_n)

035             begin

036                 clk_sys <= 1'b0;

037                 count <= 8'd0;

038             end

039         else

040             if (count < 31)//分頻成為近800K的時鍾

041                 count <= count + 1;

042             else

043                 begin

044                     count <= 8'd0;

045                     clk_sys <= ~clk_sys;

046                 end

047     end

048 //-------------------------------   

049

050     reg [5:0] state;//狀態寄存器

051

052 //--------------------------------scl

053     always @ (negedge clk_sys or negedge rst_n)

054     begin

055         if (!rst_n)

056             begin

057                 scl <= 1'b1;//復位時,scl為高

058             end

059         else

060             begin

061                 if (state > 0)//當總線忙的時候,scl為近400K的時鍾

062                     scl <= ~scl;

063                 else

064                     scl <= 1'b1;//空閑時,scl為高

065             end

066     end

067 //----------------------------------

068

069     reg [1:0] en;//讀寫使能中間寄存器

070

071 //----------------------------------enable

072     always @ (posedge clk or negedge rst_n)

073     begin

074         if (!rst_n)

075             begin

076                 en <= 2'b00;//復位時,將中間寄存器置0

077             end

078         else

079             begin

080                 if (!key_wr)//寫有效時

081                     en <= 2'b01;

082                 else

083                     if (!key_rd)//寫無效,讀有效時

084                         en <= 2'b10;

085             end

086     end

087 //---------------------------------

088     

089     reg [3:0] cnt;//發送或者接收數據的個數

090     reg [1:0] temp;//讀寫使能的中間寄存器

091     reg [7:0] memory;//發送或者接受數據的中間寄存器

092

093 always @ (posedge clk_sys or negedge rst_n)

094     begin

095         if (!rst_n)

096             begin

097                 data_out <= 8'd0;

098                 flag <= 1'b1;       //復位時,系統獲得總線的控制權

099                 sda_buffer <= 1'b1; //iic的數據線上發送高電平

100                 state <= 0;

101                 temp <= 2'b00;

102             end

103         else    

104             case(state)

105                     0 : begin   

106                         if(scl)

107                             begin

108                                 if(en != temp)//有按鍵按下

109                                     begin

110                                         sda_buffer <= 1'b0;//發送啟動信號

111                                         state <= 1;

112                                         temp <= en;//將讀寫信號保存

113                                         memory <= 8'b10100000;//控制字

114                                     end

115                                 else

116                                     state <= 0;

117                             end

118                         else

119                                 state <= 0;

120                     end

121                     

122                     1 : begin    

123                         if((scl == 0) && (cnt < 8))//發送八位控制字

124                             begin

125                                 sda_buffer <= memory[7];

126                                 cnt <= cnt + 1;

127                                 memory = {memory[6:0],memory[7]};

128                                 state <= 1;

129                             end

130                         else

131                             begin

132                                 if ((scl == 0) && (cnt == 8))

133                                     begin

134                                         cnt <= 0;

135                                         flag <= 0;//釋放總線控制權

136                                         state <= 2;

137                                     end

138                                 else

139                                     begin

140                                         state <= 1;

141                                     end

142                             end

143                     end

144                 2 : begin  

145                         if(!sda)//檢測應答信號

146                             begin

147                                 state <= 3;

148                                 memory <= 8'd0;//高字節地址

149                             end

150                         else

151                             begin

152                                 state <= 0;

153                             end

154                     end

155                     3 : begin  //發送高字節地址

156                             if((scl == 0) && (cnt < 8))

157                             begin

158                                 flag <= 1;//獲得總線控制權

159                                 sda_buffer <= memory[7];

160                                 cnt <= cnt + 1;

161                                 memory = {memory[6:0],memory[7]};

162                                 state <= 3;

163                             end

164                         else

165                             begin

166                                 if ((scl == 0) && (cnt == 8))

167                                     begin

168                                         cnt <= 0;

169                                         flag <= 0;//釋放總線控制權

170                                         state <= 4;

171                                     end

172                                 else

173                                     begin

174                                         state <= 3;

175                                     end

176                             end

177                     end

178                     4 : begin  

179                         if(!sda)//檢測應答信號

180                             begin

181                                 state <= 5;

182                                 memory <= 8'h00;//低字節地址

183                             end

184                         else

185                             begin

186                                 state <= 0;

187                             end

188                     end

189                     5 : begin  

190                             if((scl == 0) && (cnt < 8))//發送低字節地址

191                             begin

192                                 flag <= 1;//獲得總線控制權

193                                 sda_buffer <= memory[7];

194                                 cnt <= cnt + 1;

195                                 memory = {memory[6:0],memory[7]};

196                                 state <= 5;

197                             end

198                         else

199                             begin

200                                 if ((scl == 0) && (cnt == 8))

201                                     begin

202                                         cnt <= 0;

203                                         flag <= 0;//釋放總線控制權

204                                         state <= 6;

205                                     end

206                                 else

207                                     begin

208                                         state <= 5;

209                                     end

210                             end

211                     end 

212                     6 : begin  

213                         if(!sda)//檢測應答信號

214                             begin

215                                 if (temp == 2'b01)//判斷是否為寫信號

216                                     begin

217                                         state <= 7;

218                                         memory <= data_in[7:0];//發送數據

219                                     end

220                                 if (temp == 2'b10)//判斷是否為讀信號

221                                     state <= 11;    

222                             end

223                         else

224                             begin

225                                 state <= 0;

226                             end

227                     end

228                     

229                     7 : begin 

230                         if((scl == 0) && (cnt < 8))//發送數據

231                             begin

232                                 flag <= 1;//獲得總線控制權

233                                 sda_buffer <= memory[7];

234                                 cnt <= cnt + 1;

235                                 memory <= {memory[6:0],memory[7]};

236                                 state <= 7;

237                             end

238                         else

239                             begin

240                                 if ((scl == 0) && (cnt == 8))

241                                     begin

242                                         cnt <= 0;

243                                         flag <= 0;//釋放總線控制權

244                                         state <= 8;

245                                     end

246                                 else

247                                     begin

248                                         state <= 7;

249                                     end

250                             end

251                     end

252                     8 : begin 

253                         if(!sda)//檢測應答信號

254                             begin

255                                 state <= 9;

256                             end

257                         else

258                             begin

259                                 state <= 0;

260                             end

261                     end

262                     9 : begin   

263                             if (scl == 0)

264                                 begin

265                                     flag <= 1;//獲得總線控制權

266                                     sda_buffer <= 0;//拉低iic的數據線(為發送停止信號做准備)

267                                     state <= 10;

268                                 end

269                             else

270                                 state <= 9;

271                         end

272                     10 : begin                          

273                             if (scl == 1)

274                                 begin

275                                     sda_buffer <= 1;//發送停止信號

276                                     state <= 0;

277                                 end

278                             else

279                                 state <= 10;

280                         end

281                     //-----------------------------------------

282                     

283                     //-------

284                     11 : begin       

285                         flag <= 1;//獲得總線控制權

286                         sda_buffer <= 1;//拉高iic的數據線(為發送啟動信號做准備)

287                         state <= 12;

288                     end

289                     12 : begin        

290                         sda_buffer <= 0;//發送啟動信號

291                         state <= 13;

292                         memory <= 8'b10100001;  //控制字

293                     end

294                     13 : begin           

295                         if((scl == 0) && (cnt < 8))//發送八位控制字

296                             begin

297                                 flag <= 1;//獲得總線控制權

298                                 sda_buffer <= memory[7];

299                                 cnt <= cnt + 1;

300                                 memory <= {memory[6:0],memory[7]};

301                                 state <= 13;

302                             end

303                         else

304                             begin

305                                 if ((scl == 0) && (cnt == 8))

306                                     begin

307                                         cnt <= 0;

308                                         flag <= 0;//釋放總線控制權

309                                         state <= 14;

310                                     end

311                                 else

312                                     begin

313                                         state <= 13;

314                                     end

315                             end

316                     end

317                     14 : begin  

318                         if(!sda)//檢測應答信號

319                             begin

320                                 state <= 15;

321                             end

322                         else

323                             begin

324                                 state <= 0;

325                             end

326                     end

327                     15 : begin  

328                         if((scl == 1) && (cnt < 8))//接收數據

329                             begin

330                                 cnt <= cnt + 1;

331                                 memory <= {memory[6:0],sda};

332                                 state <= 15;

333                             end

334                         else

335                             begin

336                                 if ((scl == 0) && (cnt == 8))

337                                     begin

338                                         cnt <= 0;

339                                         flag <= 1;//獲得總線控制權

340                                         state <= 16;

341                                         sda_buffer <= 1;//發送應答信號        

342                                     end

343                                 else

344                                     state <= 15;

345                             end

346                     end

347                     16 : begin

348                         data_out <= memory;//輸出數據

349                         state <= 17;

350                     end

351                     17 : begin

352                         if (scl == 0)

353                             begin   

354                                 sda_buffer <= 0;//拉低iic的數據線(為發送停止信號做准備)

355                                 state <= 18;

356                             end

357                         else

358                             state <= 17;

359                         end

360                     18 : begin   //發送停止信號

361                         if (scl == 1)

362                             begin

363                                 sda_buffer <= 1;

364                                 state <= 0;

365                             end

366                         else

367                             state <= 18;

368                     end

369

370                 default : state <= 0 ;

371                 endcase

372     end

373

374 endmodule 

112行,將讀寫信號保存起來是為了讀寫的時候只進行一次的讀寫。(按鍵按下的時間一般大於20ms,如果不進行處理,系統將重復的向同一個地址中寫入或者讀出數據)。

我們把13位地址給定了一個確定的數據,並沒有通過外部發送給系統,這樣可以降低我們理解的難度。有興趣的同學可以自己嘗試一下其他的地址控制方式。

上述代碼在下板實測時可用,仿真時則不能用。在我們的設計中,多次檢測應答信號,但是仿真過程中沒有真實的器件反饋應答信號,就會導致我們的仿真出錯。仿真時應把所有的應答信號直接跳過,如下:

/****************************************************          

 *   Engineer      :   夢翼師兄

 *   QQ             :   761664056

 *   The module function: 產生iic總線的控制信號

*****************************************************/

000 module iic( 

001             clk, //外部輸入時鍾

002             rst_n,//系統復位

003             key_wr,//寫信號(低電平有效)

004             key_rd, //讀信號(低電平有效)

005             data_in, //輸入數據

006             scl, //iic的數據線

007             sda, //iic的時鍾線

008             data_out//輸出數據

009         );

010     //系統輸入

011     input clk;//外部輸入時鍾

012     input rst_n;//系統復位

013     input key_wr;//寫信號(低電平有效)

014     input key_rd;//讀信號(低電平有效)

015     input [7:0] data_in;//輸入數據

016     //系統輸出

017     output reg scl;//iic的時鍾線

018     output reg [7:0] data_out;//輸出數據

019     

020     inout sda; //iic的數據線

021     

022     reg sda_buffer;//寫入數據的中間寄存器

023     reg flag;//控制系統是否占有總線控制權

024     

025     assign sda = (flag) ? sda_buffer : 1'bz;//flag為高電平時,系統擁有總線控制權

026                                             //並發送sda_buffer中的數據。當flag為低電平時,

027                                             //釋放總線。

028     

029     reg [7:0] count;//計數器

030     reg clk_sys;//系統時鍾

031 //-------------------------------clk_sys

032     always @ (posedge clk or negedge rst_n)

033     begin

034         if (!rst_n)

035             begin

036                 clk_sys <= 1'b0;

037                 count <= 8'd0;

038             end

039         else

040             if (count < 31)//分頻成為近800K的時鍾

041                 count <= count + 1;

042             else

043                 begin

044                     count <= 8'd0;

045                     clk_sys <= ~clk_sys;

046                 end

047     end

048 //-------------------------------   

049

050     reg [5:0] state;//狀態寄存器

051

052 //--------------------------------scl

053     always @ (negedge clk_sys or negedge rst_n)

054     begin

055         if (!rst_n)

056             begin

057                 scl <= 1'b1;//復位時,scl為高

058             end

059         else

060             begin

061                 if (state > 0)//當總線忙的時候,scl為近400K的時鍾

062                     scl <= ~scl;

063                 else

064                     scl <= 1'b1;//空閑時,scl為高

065             end

066     end

067 //----------------------------------

068

069     reg [1:0] en;//讀寫使能中間寄存器

070

071 //----------------------------------enable

072     always @ (posedge clk or negedge rst_n)

073     begin

074         if (!rst_n)

075             begin

076                 en <= 2'b00;//復位時,將中間寄存器置0

077             end

078         else

079             begin

080                 if (!key_wr)//寫有效時

081                     en <= 2'b01;

082                 else

083                     if (!key_rd)//寫無效,讀有效時

084                         en <= 2'b10;

085             end

086     end

087 //---------------------------------

088     

089     reg [3:0] cnt;//發送或者接收數據的個數

090     reg [1:0] temp;//讀寫使能的中間寄存器

091     reg [7:0] memory;//發送或者接受數據的中間寄存器

092

093 always @ (posedge clk_sys or negedge rst_n)

094     begin

095         if (!rst_n) begin

096                 cnt <= 0;

097                 data_out <= 8'd0;

098                 flag <= 1'b1;       //復位時,系統獲得總線的控制權

099                 sda_buffer <= 1'b1; //iic的數據線上發送高電平

100                 state <= 0;

101                 temp <= 2'b00;

102             end

103         else    

104             case(state)

105                     0 : begin   

106                         if(scl)

107                             begin

108                                 if(en != temp)//有按鍵按下

109                                     begin

110                                         sda_buffer <= 1'b0;//發送啟動信號

111                                         state <= 1;

112                                         temp <= en;//將讀寫信號保存

113                                         memory <= 8'b10100000;//控制字

114                                     end

115                                 else

116                                     state <= 0;

117                             end

118                         else

119                                 state <= 0;

120                     end

121                     

122                     1 : begin    

123                         if((scl == 0) && (cnt < 8))//發送八位控制字

124                             begin

125                                 sda_buffer <= memory[7];

126                                 cnt <= cnt + 1;

127                                 memory = {memory[6:0],memory[7]};

128                                 state <= 1;

129                             end

130                         else

131                             begin

132                                 if ((scl == 0) && (cnt == 8))

133                                     begin

134                                         cnt <= 0;

135                                         flag <= 0;//釋放總線控制權

136                                         state <= 2;

137                                     end

138                                 else

139                                     begin

140                                         state <= 1;

141                                     end

142                             end

143                     end

144                 2 : begin  

145 //                      if(!sda)//檢測應答信號

146 //                          begin

147                                 state <= 3;

148                                 memory <= 8'd0;//高字節地址

149 //                          end

150 //                      else

151 //                          begin

152 //                              state <= 0;

153 //                          end

154                     end

155                     3 : begin  //發送高字節地址

156                             if((scl == 0) && (cnt < 8))

157                             begin

158                                 flag <= 1;//獲得總線控制權

159                                 sda_buffer <= memory[7];

160                                 cnt <= cnt + 1;

161                                 memory = {memory[6:0],memory[7]};

162                                 state <= 3;

163                             end

164                         else

165                             begin

166                                 if ((scl == 0) && (cnt == 8))

167                                     begin

168                                         cnt <= 0;

169                                         flag <= 0;//釋放總線控制權

170                                         state <= 4;

171                                     end

172                                 else

173                                     begin

174                                         state <= 3;

175                                     end

176                             end

177                     end

178                     4 : begin  

179 //                      if(!sda)//檢測應答信號

180 //                          begin

181                                 state <= 5;

182                                 memory <= 8'h00;//低字節地址

183 //                          end

184 //                      else

185 //                          begin

186 //                              state <= 0;

187 //                          end

188                     end

189                     5 : begin  

190                             if((scl == 0) && (cnt < 8))//發送低字節地址

191                             begin

192                                 flag <= 1;//獲得總線控制權

193                                 sda_buffer <= memory[7];

194                                 cnt <= cnt + 1;

195                                 memory = {memory[6:0],memory[7]};

196                                 state <= 5;

197                             end

198                         else

199                             begin

200                                 if ((scl == 0) && (cnt == 8))

201                                     begin

202                                         cnt <= 0;

203                                         flag <= 0;//釋放總線控制權

204                                         state <= 6;

205                                     end

206                                 else

207                                     begin

208                                         state <= 5;

209                                     end

210                             end

211                     end 

212                     6 : begin  

213 //                      if(!sda)//檢測應答信號

214 //                          begin

215                                 if (temp == 2'b01)//判斷是否為寫信號

216                                     begin

217                                         state <= 7;

218                                         memory <= data_in[7:0];//發送數據

219                                     end

220                                 if (temp == 2'b10)//判斷是否為讀信號

221                                     state <= 11;    

222 //                          end

223 //                      else

224 //                          begin

225 //                              state <= 0;

226 //                          end

227                     end

228                     

229                     7 : begin 

230                         if((scl == 0) && (cnt < 8))//發送數據

231                             begin

232                                 flag <= 1;//獲得總線控制權

233                                 sda_buffer <= memory[7];

234                                 cnt <= cnt + 1;

235                                 memory <= {memory[6:0],memory[7]};

236                                 state <= 7;

237                             end

238                         else

239                             begin

240                                 if ((scl == 0) && (cnt == 8))

241                                     begin

242                                         cnt <= 0;

243                                         flag <= 0;//釋放總線控制權

244                                         state <= 8;

245                                     end

246                                 else

247                                     begin

248                                         state <= 7;

249                                     end

250                             end

251                     end

252                     8 : begin 

253 //                      if(!sda)//檢測應答信號

254 //                          begin

255                                 state <= 9;

256 //                          end

257 //                      else

258 //                          begin

259 //                              state <= 0;

260 //                          end

261                     end

262                     9 : begin   

263                             if (scl == 0)

264                                 begin

265                                     flag <= 1;//獲得總線控制權

266                                     sda_buffer <= 0;//拉低iic的數據線(為發送停止信號做准備)

267                                     state <= 10;

268                                 end

269                             else

270                                 state <= 9;

271                         end

272                     10 : begin                          

273                             if (scl == 1)

274                                 begin

275                                     sda_buffer <= 1;//發送停止信號

276                                     state <= 0;

277                                 end

278                             else

279                                 state <= 10;

280                         end

281                     //-----------------------------------------

282                     

283                     //-------

284                     11 : begin       

285                         flag <= 1;//獲得總線控制權

286                         sda_buffer <= 1;//拉高iic的數據線(為發送啟動信號做准備)

287                         state <= 12;

288                     end

289                     12 : begin        

290                         sda_buffer <= 0;//發送啟動信號

291                         state <= 13;

292                         memory <= 8'b10100001;  //控制字

293                     end

294                     13 : begin           

295                         if((scl == 0) && (cnt < 8))//發送八位控制字

296                             begin

297                                 flag <= 1;//獲得總線控制權

298 sda_buffer <= memory[7];

299 cnt <= cnt + 1;

300 memory <= {memory[6:0],memory[7]};

301 state <= 13;

302 end

303 else

304 begin

305 if ((scl == 0) && (cnt == 8))

306 begin

307 cnt <= 0;

308 flag <= 0;//釋放總線控制權

309 state <= 14;

310 end

311 else

312 begin

313 state <= 13;

314 end

315 end

316 end

317 14 : begin  

318 // if(!sda)//檢測應答信號

319 // begin

320 state <= 15;

321 // end

322 // else

323 // begin

324 // state <= 0;

325 // end

326 end

327 15 : begin  

328 if((scl == 1) && (cnt < 8))//接收數據

329 begin

330 cnt <= cnt + 1;

331 memory <= {memory[6:0],sda};

332 state <= 15;

333 end

334 else

335 begin

336 if ((scl == 0) && (cnt == 8))

337 begin

338 cnt <= 0;

339 flag <= 1;//獲得總線控制權

340 state <= 16;

341 sda_buffer <= 1;//發送應答信號

342 end

343 else

344 state <= 15;

345 end

346 end

347 16 : begin

348 data_out <= memory;//輸出數據

349 state <= 17;

350 end

351 17 : begin

352 if (scl == 0)

353 begin

354 sda_buffer <= 0;//拉低iic的數據線(為發送停止信號做准備)

355 state <= 18;

356 end

357 else

358 state <= 17;

359 end

360 18 : begin   //發送停止信號

361 if (scl == 1)

362 begin

363 sda_buffer <= 1;

364 state <= 0;

365 end

366 else

367 state <= 18;

368 end

369

370 default : state <= 0 ;

371 endcase

372 end

373

374 endmodule

 

 

仿真代碼

/****************************************************          

 *   Engineer      :   夢翼師兄

 *   QQ             :   761664056

 *   The module functioniic測試模塊

*****************************************************/

00 `timescale 1ns/1ps

01

02 module iic_tb;

03 //系統輸入

04 reg clk;//外部輸入時鍾

05 reg rst_n;//系統復位

06 reg key_wr;//寫信號(低電平有效)

07 reg key_rd;//讀信號(低電平有效)

08 reg [7:0] data_in;//輸入數據

09 //系統輸出

10 wire scl;//iic的時鍾線

11 wire [7:0] data_out;//輸出數據

12 wire sda; //iic的數據線

13

14 iic iic_inst(

15 .clk(clk), //外部輸入時鍾

16 .rst_n(rst_n), //系統復位

17 .key_wr(key_wr), //寫信號(低電平有效)

18 .key_rd(key_rd), //讀信號(低電平有效)

19 .scl(scl), //iic的時鍾

20 .sda(sda), //iic的數據線

21 .data_in(data_in),//輸入數據

22 .data_out(data_out)//輸出數據

23 );

24

25 initial begin

26 clk = 1;

27 rst_n = 0;

28 key_wr = 1;

29 key_rd = 1;

30 data_in = 0;

31 #1000.1 rst_n = 1;

32 # 800

33 #8000 key_wr = 0;//寫信號有效

34 data_in = 8'h23;//輸入數據為8’h23

35 #40000 key_wr = 1;//寫信號釋放

36

37 #1000000

38 key_rd = 0;//讀信號有效

39 #40000 key_rd = 1;//讀寫號釋放

40 end

41

42 always #10 clk=~clk; //50M的時鍾

43

44 endmodule

仿真分析

  1. 發送啟動信號
  2. 發送控制字
  3. 接收並檢測EEPROM發來的應答信號ACK
  4. 發送高字節地址位
  5. 接收並檢測EEPROM發來的應答信號ACK
  6. 發送低字節地址位
  7. 接收並檢測EEPROM發來的應答信號ACK
  8. 發送8bit有效數據
  9. 接收並檢測EEPROM發來的應答信號ACK
  10. 發送停止信號

經過一步一步的查看,我們的設計時序是正確的。

 

 

 

  1. 發送啟動信號
  2. 發送控制字1010_0000
  3. 接收並檢測EEPROM發來的應答信號ACK
  4. 發送高字節地址位
  5. 接收並檢測EEPROM發來的應答信號ACK
  6. 發送低字節地址位
  7. 接收並檢測EEPROM發來的應答信號ACK
  8. 發送啟動信號
  9. 發送控制字1010_0001
  10. 接收並檢測EEPROM發來的應答信號ACK
  11. 讀取一個字節數據
  12. 發送NO ACK信號
  13. 發送停止信號

 讀寫的波形與iic原理中的讀寫時序圖一致,證明我們的設計是正確的。

 

 




 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM