进阶项目(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原理中的读写时序图一致,证明我们的设计是正确的。




猜你喜欢

转载自www.cnblogs.com/mengyi1989/p/11521054.html