怎么使用双向IO口

在很多情况下,需要使用双向IO。不过最好谨慎使用,在top层使用。网上很多描述的代码甚至是不可以综合并且有语法错误的,还是老实自己写个模块吧。

新版本如下:

使用inout口,直接定义个inout口。

然后用使能控制就好了,如果是作为输入,则直接把inout赋值给reg型变量就行。

如果作为输出,则使用使能控制,输出则把寄存器的值赋给inout,不输出则赋值z。表示输出高阻态,处于输入模式中。

inout            io_sdio;//定义一个inout
r_sdi_shift<={r_sdi_shift[6:0],io_sdio}; //采集数据
assign io_sdio = r_oe_n ? 1'bz : r_sdo_shift[23] & (~o_csn); //输出

三行代码解决一切问题。

 

老版本不再使用,如下:

如果你需要一个口既做输入端口也做输出端口,那么你就需要去描述一个双向的IO。

1.电路框图:

2.数据流向:

当en=0的时候,三态门选通,dinout当输出口使用,数据从din到dinout。

当en=1的时候,三态门关闭,dinout当输入口使用,输出呈现高阻态,数据从dinout到dout。

3.代码:

//************************************************
//  Filename      : dual_io.v                             
//  Author        : kingstacker                  
//  Company       : School                       
//  Email         : kingstacker_work@163.com     
//  Device        : Altera cyclone4 ep4ce6f17c8  
//  Description   : dual io,wwidth can be change;                             
//************************************************
module  dual_io #(parameter WIDTH = 8)(
/*i*/   input    wire                  clk          ,
        input    wire                  rst_n        ,
        input    wire                  en           ,
        input    wire   [WIDTH-1:0]    din          ,
        inout    wire   [WIDTH-1:0]    dinout       ,
/*o*/   output   wire   [WIDTH-1:0]    dout              
);
reg [WIDTH-1:0] din_reg;
reg [WIDTH-1:0] dout_reg;
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        din_reg <= 0;
        dout_reg <= 0;
    end //if
    else begin
        if (~en) begin
            din_reg <= din;
        end    
        else begin
            dout_reg <= dinout;
        end
    end //else
end //always
assign dinout = (~en) ? din_reg : 8'hzz;
assign dout = dout_reg;
endmodule

4.综合一下看看:三态门实现双端口。

以上。

 

转载于:https://www.cnblogs.com/kingstacker/p/7749862.html

### 准双向IO的工作原理 准双向IO是一种常见的单片机I/O接设计形式,其主要特点是通过硬件和软件的配合来实现输入与输出的功能切换。这种设计允许同一个引脚既可以用作数据输出,也可以用作数据输入。 #### 硬件结构 准双向IO通常由一个三态缓冲器构成[^1]。在这种结构下,当需要将该引脚设置为输出模式时,三态缓冲器被激活,从而驱动外部负载;而当需要将其配置为输入模式时,则关闭三态缓冲器,使引脚进入高阻抗状态(即不主动驱动任何信号),此时可以通过外部电路检测到实际电压水平并反馈给单片机内部逻辑处理单元[^3]。 #### 软件控制机制 为了正确操作准双向IO,在编程过程中需要注意以下几点: - **初始化阶段**:设定方向寄存器(Direction Register),决定某个特定pin是作为输入还是输出使用。 - **写入前读取**(Read Before Write): 当准备更改某位的数据值之前先查询当前端的状态是非常重要的一步。这是因为如果直接覆盖掉原来存在的信息可能会引起意外行为或者损坏相连器件。具体来说就是首先要执行一次“读”动作获取现有电平情况然后再基于此结果做进一步修改后再发送出去完成最终赋值过程[^4]。 #### 应用场景实例分析 假设有一个LED灯连接到了微控制器的一个通用目的进出(Pin), 我们希望利用这个针脚去点亮它同时也能够感知按键按下与否的情况: ```c // 定义变量用于存储临时读数 uint8_t temp; void toggleLedAndCheckButton(void){ // 首先保存原始状态 temp = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0); // 设置成输出以驱动 LED GPIO_SetMode(GPIOA, GPIO_Mode_Out_PP); // 切换LED状态 if(temp == Bit_RESET){ GPIO_SetBits(GPIOA, GPIO_Pin_0); // 如果原来是灭则现在亮起 }else{ GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 否则熄灭 } // 改变回输入以便监测按钮按压事件 GPIO_SetMode(GPIOA, GPIO_Mode_IN_FLOATING); } ``` 上述代码片段展示了如何在一个周期内交替发挥同一物理引线上的两种不同角色——先是当作输出用来操控发光二极管(LED),紧接着又转换成为输入型态监视开关状况的变化趋势[^2].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值