如何使用 18F4550 创建双向总线?

How can I create a bidirectional bus using a 18F4550?

基本上,我正在尝试使用 PIC18F4550 的单个端口作为输入和输出。我要将一个 7 段显示器连接到端口的 7 个引脚和同一端口的 4 个引脚。这四个输入用于输入二进制数 0 到 15(F),二进制数将在显示器中显示为十进制数。我使用 PIC C 编译器编写代码。

更新: 在第一条评论之后我修改了代码,我认为它基本上是一样的,我只是直接读取端口 B 的输入并使用开关盒为了发送相应的十进制数,我还添加了一个默认状态,因此当我连接时它应该在显示中为 0。这是连接图,我的老师告诉我我可以忽略逻辑门,但我不确定,如果我想添加,我只需要使用另一个端口,如端口 D 来发送一个高电平或低电平取决于端口 B 的工作方式。

更新 2: 它终于起作用了,似乎我可以忽略逻辑门的事实部分正确,代码比我简单,我只是添加了一个三端口 D 高电平和低电平输出到 74Ls244 和 74HC573 对应输入的 EN 和 OE,因此我可以根据端口 B 的状态(输出或输入)启用或禁用。谢谢你们。

#include<18F4550.h>
#fuses XT, NOWDT, NOLVP, NOPROTECT, PUT
#use delay(clock = 4M, crystal = 8M)
#use fast_io(b)

void main(){

int8 INDSP;
int8 OUTDSP;


while(true){

  SET_TRIS_B(0xFF);
  INDSP = input_b()&0x0F;
  switch(INDSP){
     
     case 0b00000000:
        OUTDSP = 0x3F;
     break;
     
     case 0b00000001:
        OUTDSP = 0x0C;
     break;
     
     case 0b00000010:
        OUTDSP = 0x76;
     break;
     
     case 0b00000011:
        OUTDSP = 0x5E;
     break;
     
     case 0b00000100:
        OUTDSP = 0x4D;
     break;
     
     case 0b00000101:
        OUTDSP = 0x5B;
     break;
     
     case 0b00000110:
        OUTDSP = 0x7B;
     break;
     
     case 0b00000111:
        OUTDSP = 0x0E;
     break;
     
     case 0b00001000:
        OUTDSP = 0x7F;
     break;
     
     case 0b00001001:
        OUTDSP = 0x4F;
     break;
     
     case 0b00001010:
        OUTDSP = 0x6F;
     break;
     
     case 0b00001011:
        OUTDSP = 0x79;
     break;
     
     case 0b00001100:
        OUTDSP = 0x33;
     break;
     
     case 0b00001101:
        OUTDSP = 0x7C;
     break;
     
     case 0b00001110:
        OUTDSP = 0x73;
     break;
     
     case 0b00001111:
        OUTDSP = 0x63;
     break;
     
     DEFAULT:
        OUTDSP = 0x3F;
     break;
  }
     delay_ms(500);
     SET_TRIS_B(0x00);
     output_b(OUTDSP);
     delay_ms(500);
  }
}

警告:不是完整的解决方案,而是一些建议...

我们可以简化您的 main,因为它有大量的重复代码:

void
main()
{

    SET_TRIS_B(0b00001111);
    DSPIN = input_b();

    while (true) {
        if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
            DSPOUT = DSPIN;
        else
            DSPOUT = 0;

        delay_ms(1000);
        SET_TRIS_B(0b11111111);

        if ((DSPOUT >= 0) && (DSPOUT <= 15))
            output_b(DSPVALOR[DSPOUT]);
        else
            output_b(DSPVALOR[0]);

        delay_ms(1000);
    }
}

现在,给定 main 的顶部:

SET_TRIS_B(0b00001111);
DSPIN = input_b();

我的问题是:这应该是 内部 顶部的 while 循环吗???

否则,不需要循环,因为DSPINDSPOUT将保持不变。


更新:

这完全是猜测,但在粗略地查看了数据表之后...

我认为您混淆了 TRIS 端口的值。 second set_tris_b 调用应该有 0b00000000 来设置输出的所有位(并且 not 0b11111111 作为你有它设置输入的所有位)。

我不确定您是否可以使用 单个 8 位端口来完成此操作。输入值需要四位。但是,您需要七位才能输出到 7 段显示器。

这样加起来超过8位。所以,我认为您需要 两个 端口。由于您使用的是端口“b”,我认为有一个端口“a”。

可能能够像您所做的那样对输入和输出的给定位进行时分多路复用,但我认为这很冒险,而且我对18F 端口的细节可以肯定。

这里的重构代码假设有一个单独的端口“a”:

void
main()
{

    while (true) {
        // set port B lower four bits for input
        SET_TRIS_B(0b00001111);

        // get input and mask off don't care bits
        DSPIN = input_b();
        DSPIN &= 0b00001111;

        if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
            DSPOUT = DSPIN;
        else
            DSPOUT = 0;

        delay_ms(1000);

        // set port A pins for output
        SET_TRIS_A(0b00000000);

        if ((DSPOUT >= 0) && (DSPOUT <= 15))
            output_a(DSPVALOR[DSPOUT]);
        else
            output_a(DSPVALOR[0]);

        delay_ms(1000);
    }
}

但是,如果 18F 允许您即时更改三态位并且您可以连接两个 输入位开关位0-3 位0-6上的7段输出位,您可以简单地将所有*_a调用更改为*_b调用。


更新#2:

经过进一步思考[并且,再次,这是猜测],如果 18F 允许 一个 端口来回切换在输入和输出之间重复,上面代码中的“占空比”[可能]不正确。

两个延迟为1000ms,输出占空比[仅]50%,因此7段显示器可能会严重闪烁。

那是因为,在 tristate/input 模式下,7 段显示 而不是 是用正确的段 mask/output 值

驱动的

解决方案是将占空比增加到(例如)99.44% [象牙皂的纯度 :-)]。因此,大多数 时间,端口处于输出模式。我们只是简单地进入tristate/input模式来采样[DIP开关]输入引脚。

这是一个重构版本,它使端口大部分时间都处于输出模式:

// NOTE: these may be need to be adjusted
enum {
    INPUT_STABILIZE_DELAY =     1,      // as short as possible
    OUTPUT_STABILIZE_DELAY =    1,      // as short as possible
    OUTPUT_HOLD_DELAY =         100,    // as long as possible
};

void
main()
{

    while (true) {
        // set port B lower four bits for input
        SET_TRIS_B(0b00001111);

        // allow port to stabilize
        delay_ms(INPUT_STABILIZE_DELAY);

        // get input and mask off don't care bits
        DSPIN = input_b();
        DSPIN &= 0b00001111;

        // set output mode based on input
        if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
            DSPOUT = DSPIN;
        else
            DSPOUT = 0;

        // set port B pins for output
        SET_TRIS_B(0b00000000);

        // allow tristate pins to stabilize
        delay_ms(OUTPUT_STABILIZE_DELAY);

        // output to 7 segment delay
        output_b(DSPVALOR[DSPOUT]);

        // ensure that port is in output mode 99.44% of the time
        delay_ms(OUTPUT_HOLD_DELAY);
    }
}