写在前面的话
我们所接触到的IO都是单纯的输入(input)或者输出(output)类型,而我们的一些总线协议如IIC等,要求信号为三态类型,也就是我们所说的输入输出(inout)类型。那么,本节梦翼师兄将和大家一起来探讨三态门的用法。
项目需求
设计一个三态门电路,可以实现数据的输出和总线“挂起”。
系统架构
模块功能介绍
模块名 |
功能描述 |
three_state |
控制三态总线Sda是否处于挂起状态 |
顶层模块端口描述
端口名 |
端口说明 |
Clk |
系统时钟 |
Rst_n |
系统低电平复位 |
Data_buf |
外部待传输数据输入 |
Sda |
三态数据总线 |
代码解释
三态门模块代码
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:三态门模块 *****************************************************/ 00 module three_state( 01 //系统输入 02 clk,//系统50M输入 03 rst_n,//低电平复位信号 04 data_buf, 05 //系统输出 06 sda//三态总线 07 ); 08 //-------------------系统输入------------------- 09 input clk;//系统50M输入 10 input rst_n;//低电平复位信号 11 input data_buf;//待传输数据 12 //-------------------系统输出------------------- 13 inout sda;//三态总线 14 //------------------寄存器定义------------------ 15 reg flag;//三态门开关定义 16 reg [10:0]counter;//计数器定义 17 //------------------三态门赋值------------------ 18 assign sda=(flag==1)?data_buf:1'bz; 19 //----------------开关控制计数器---------------- 20 always@(posedge clk or negedge rst_n) 21 begin 22 if(!rst_n) 23 begin 24 counter<=0;//计数器复位 25 end 26 else 27 begin 28 if(counter<25)//计数器范围 29 counter<=counter+1;//计数器累加 30 else 31 counter<=0;//计数器清零 32 end 33 end 34 //----------------开关/数据控制----------------- 35 always@(posedge clk or negedge rst_n) 36 begin 37 if(!rst_n) 38 begin 39 flag<=0;//开关关闭 40 end 41 else 42 begin 43 if(counter==25) 44 flag<=~flag;//开关信号翻转 45 end 46 end 47 endmodule |
第18行代码就是三态门的赋值方式,三态门什么时候作为输出、什么时候作为输入是由开关信号flag控制的。当开关信号flag==1,Sda的值等于待发送的数据data_buf(此时,Sda相当于是output类型),当开关信号flag==0,Sda的值变成高阻态(此时,Sda相当于是input类型)。
第20~33行代码为我们设计的一个定时器,用来控制开关信号的翻转。
第43~44行代码表示当定时器到达预定值,开关电平开始翻转。
三态门模块测试代码
/**************************************************** * Engineer : 梦翼师兄 * QQ : 761664056 * The module function:三态门测试模块 *****************************************************/ 00 `timescale 1ns/1ns 01 module tb; 02 //-------------------系统输入------------------- 03 reg clk;//系统50M输入 04 reg rst_n;//低电平复位信号 05 reg data_buf;//待传输数据 06 //-------------------系统输出------------------- 07 wire sda;//三态总线 08 //-------------------测试激励------------------- 09 initial 10 begin 11 clk=0;//时钟赋初值 12 rst_n=0;//系统上电复位 13 data_buf=0;//data_buf赋初值 14 #1000 rst_n=1;//复位结束 15 #1000 data_buf=1; 16 #1000 data_buf=0; 17 #1000 data_buf=1; 18 #1000 data_buf=0; 19 end 20 21 always #10 clk=~clk;//产生50MHZ时钟 22 //-------------------模块实例化------------------- 23 three_state three_state( 24 //系统输入 25 .clk(clk),//系统50M输入 26 .rst_n(rst_n),//低电平复位信号 27 .data_buf(data_buf), 28 //系统输出 29 .sda(sda)//三态总线 30 ); 31 endmodule |
14~18行代码,模拟的是待传输数据的变化
仿真分析
由仿真波形可以看出,当开关关闭(flag==0),Sda总线放开,处于高阻状态,此时外部数据可以输入,相当于我们模块的输入。
当开关打开(flag==1),Sda等于data_buf的值,说明此时,Sda相当于我们模块的输出。