进阶项目(9)IIC通信协议程序设计讲解

写在前面的话

IIC的通信协议和通信接口在很多工程中有广泛的应用,如数据采集领域的串行AD,图像处理领域的摄像头配置,工业控制领域的X射线管配置等等。除此之外,由于IIC协议占用的IO资源特别少,连接方便,所以工程中也常选用IIC接口做为不同芯片间的通信协议。

IIC协议的完成靠的是严紧的时序,一个周期都不能错,这也正是梦翼师兄设置本实验的目的。通过IIC的学习,锻炼大家的时序实现技巧和方法,可以说最佳的案例之一。

项目需求

设计IIC接口的驱动电路可以实现单字节数据的读写。

IIC的原理分析

本实验,我们采用的外部接口芯片为EEPROM 24LC64,其封装图如下:

进阶项目(9)IIC通信协议程序设计讲解

接下来,我们梳理一下各引脚定义:

A0,A1,A2为24LC64的片选信号,由于IIC总线可以挂载多个IIC接口器件,所以每个器件都应该有自己的“身份标识”,通过对A0,A1,A2输入不同的高低电平,就可以设置该EEPROM的片选信号。

WP为读写使能信号,当WP悬空或者接地,EEPROM可读可写,当WP接电源,EEPROM只能读不能写。

SCL为IIC接口的时钟线(根据不同的配置方式,scl的频率是可以改变的,我们采取200K)

SDA为IIC接口的数据线

得到了上面的配置信息,那么接下来,看一下我们开发板的配置原理图

进阶项目(9)IIC通信协议程序设计讲解

由此可以看出我们的位选信号为“000”,EEPROM可读写。而我们最需要关心的,就是SCL和SDA两条线的时序关系。

原理图分析完毕,接下来我们学习一下IIC接口的具体时序是什么。IIC读写时序分为随机读写和页面读写,也就是常说的Byte Write/Read 和Page Write/Read。

我们首先来学习Byte Write/Read时序。Byte Write时序如下:

进阶项目(9)IIC通信协议程序设计讲解

由时序图可以看出,如果我们要向EEPROM写入一个字节,那么必须经过以下步骤:

发送启动信号

发送控制字

接收并检测EEPROM发来的应答信号ACK

发送高字节地址位

接收并检测EEPROM发来的应答信号ACK

发送低字节地址位

接收并检测EEPROM发来的应答信号ACK

发送8bit有效数据

接收并检测EEPROM发来的应答信号ACK

10.发送停止信号

Byte Read时序如下:

 进阶项目(9)IIC通信协议程序设计讲解

由时序图可以看出,如果我们要从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.启动信号

进阶项目(9)IIC通信协议程序设计讲解

 

SCL保持高电平期间,如果SDA出现由高到低的跳变沿,代表启动信号

2.控制字

我们的控制字为1010_0000或1010_0001,其中1010为EEPROM的型号标识,为一组固定的序列,紧接着A2,A1,A0就是我们的片选信号,最后一位为读写控制位,低电平代表写,高电平代表读,我们这里首先需要对EEPROM写入地址位,所以我们最后一位为0。当我们需要读数据时,最后一位为1。

/低位地址

由于24LC64有64Kbit的存储空间,所以我们需要13位的地址位宽才能寻址所有的存储空间,由于IIC协议规定只能以字节形式写入,所以必须将13位的地址扩展为16位的地址,分为高八位和低八位,多出来的前三位填充任意数据即可,对我们的寻址地址没有影响。

3.停止信号

进阶项目(9)IIC通信协议程序设计讲解

 

SCL保持高电平期间,如果SDA出现由低到高的跳变沿,代表停止信号

4.应答信号ACK

应答信号是由数据接收方发出的,当SCL为高电平期间,如果监测到SDA为低电平,说明有应答信号。

5.非应答信号NO ACK

非应答信号也是由数据接收方发出的,当SCL为高电平期间,如果SDA为高电平,说明有非应答信号。

由于IIC总线协议启动和停止信号都是在SCL高电平期间发生跳变(当不发送或者接收数据的时候scl一直为高电平),这就决定了我们其他数据的改变只能发生在SCL低电平期间,在SCL为高电平期间,数据必须保持稳定。即在SCL低电平改变数据,在SCL高电平采集数据。

由于读时序和写时序一直到低字节地址的写入之前都是相同的,因此我们设置IIC控制器流程图如下:

进阶项目(9)IIC通信协议程序设计讲解

接下来,我们来学习Page Write/Read时序

Page Write时序如下:

 进阶项目(9)IIC通信协议程序设计讲解

Page Read时序如下:

进阶项目(9)IIC通信协议程序设计讲解

由此可以看出,页面读写比随机读写只是多加了几个状态而已,在我们前面设计的基础上加几个状态就可以完成。梦翼师兄把这部分交给大家去发挥。

架构设计

根据原理分析,我们设计出架构图如下:进阶项目(9)IIC通信协议程序设计讲解

模块功能介绍

模块名

功能描述

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

仿真分析

进阶项目(9)IIC通信协议程序设计讲解

  1. 发送启动信号
  2. 发送控制字
  3. 接收并检测EEPROM发来的应答信号ACK
  4. 发送高字节地址位
  5. 接收并检测EEPROM发来的应答信号ACK
  6. 发送低字节地址位
  7. 接收并检测EEPROM发来的应答信号ACK
  8. 发送8bit有效数据
  9. 接收并检测EEPROM发来的应答信号ACK
  10. 发送停止信号

经过一步一步的查看,我们的设计时序是正确的。

进阶项目(9)IIC通信协议程序设计讲解

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