C语言 我有一个问题,试图做一个异或与3个变量

ffx8fchx  于 2023-10-16  发布在  其他
关注(0)|答案(5)|浏览(120)

我正在为一个学校项目用C编写一个微型(ATmega 328 p)。事情是我试图代表这个真值表(A,B和C只是输入,更具体的按钮)和XOR是LED上的输出,还有其他3个LED,但他们正在做一个不同的门,现在他们工作正常。

我有这个特定的部分问题,因为异或不工作,它应该是关闭时,2按钮按下,但不是。它只是关闭时,所有的按钮都没有按下:

if ( ((BTS & _BV(BT1)) ^ (BTS & _BV(BT2))) || ((BTS & _BV(BT2)) ^ (BTS & _BV(BT3)))) //EXOR
        {
            LEDS |= _BV(LED2); //Set 1 on LED2
        }
        else
        {
            LEDS &= ~_BV(LED2); //Set 0 on LED2
        }

我把完整的代码放在这里只是为了参考。

#include <avr/io.h>
#define F_CPU 16000000UL 
#include <util/delay.h>

#define delay 500

//--Tags
//-Inputs
#define BTS PINB
#define BT1 PINB0
#define BT2 PINB1
#define BT3 PINB2

//-Outputs
#define LEDS PORTD
#define LED0 PORTD2
#define LED1 PORTD3
#define LED2 PORTD4
#define LED3 PORTD5

void init_ports(void);

int main(void)
{
    init_ports();
    
    while (1) 
    {
        //Output 1
        if ((BTS & _BV(BT1)) && (BTS & _BV(BT2)) && (BTS & _BV(BT3))) // AND 
        {
            LEDS |= _BV(LED0); //Set 1 on LED0
        }
        else
        {
            LEDS &= ~ _BV(LED0); //Set 0 on LED0
        }
        
        //Output 2
        if ((BTS & _BV(BT1)) || (BTS & _BV(BT2)) || (BTS & _BV(BT3))) // OR 
        {
            LEDS |= _BV(LED1); //Set 1 on LED1
        }
        else
        {
            LEDS &= ~ _BV(LED1); //Set 0 on LED1
        }
        
        //Output 3
        
        if ( ((BTS & _BV(BT1)) ^ (BTS & _BV(BT2))) || ((BTS & _BV(BT2)) ^ (BTS & _BV(BT3)))) //EXOR
        {
            LEDS |= _BV(LED2); //Set 1 on LED2
        }
        else
        {
            LEDS &= ~_BV(LED2); //Set 0 on LED2
        }
        
        //Output 4
        
        if (!((BTS & _BV(BT1)) && (BTS & _BV(BT2)) && (BTS & _BV(BT3)))) // NOR 
        {
            LEDS |= _BV(LED3); //Set 1 on LED3
        }
        else
        {
            LEDS &= ~_BV(LED3); //Set 0 on LED3
        }
    }
}

void init_ports (void)
{
    //--Inputs
    DDRB  &= ~(_BV(BT1) | _BV(BT2) | _BV(BT3));
    //-PULL-UP 
    PORTB &= ~(_BV(BT1) | _BV(BT2) | _BV(BT3));
    //--Outputs
    DDRD  |=  (_BV(LED0) | _BV(LED1) | _BV(LED2) | _BV(LED3));
    //-Off
    PORTD &= ~(_BV(LED0) | _BV(LED1) | _BV(LED2) | _BV(LED3));
}

有什么可能的想法吗?YOU!!:D
我试着用这个布尔表达式y = A 'B'C + A 'BC' + AB 'C' + ABC

flseospp

flseospp1#

你的标题谈到了三个变量的XOR,

EXOR = A ^ B ^ C;

然而,你的真值表:

不是一个三变量XOR。对于三变量XOR,第6行和第7行的结果应该为零。
真值表表示“B exclusive-or C or A”,如:

EXOR = B ^ C | A;
uxhixvfz

uxhixvfz2#

编写一些代码,使用您的布尔表达式构造一个真值表,并将其与赋值中给出的表进行比较。它们匹配吗?如果没有,仔细考虑你得到的真值表,并构造一个匹配的布尔表达式。你也可以在谷歌上搜索卡诺图,它可以帮助你从真值表中构造一个表达式。

#include <stdio.h>

int main()
{
   printf(" A   B   C   EXOR\n");
   printf("------------------\n");

   for (int a = 0; a <=1; a++) {
      for (int b = 0; b <=1; b++) {
         for (int c = 0; c <=1; c++) {
            int exor = (a ^ b) || (b ^ c);
            printf(" %i   %i   %i   %i\n", a, b, c, exor);
         }
      }
   }
}
ctehm74n

ctehm74n3#

注意

((BTS & _BV(BT1)) ^ (BTS & _BV(BT2))

这里的 XOR 操作是按位的(不是逻辑的)。
由于两个操作数中都有bitwise AND,因此除了左边的位#BT1和右边的位#BT2之外,它们中的每一个都重置了所有位。
左侧的位#BT2和右侧的位#BT1为0。这意味着,^在这里的工作方式与按位OR完全相同,如果在两个操作数中都设置了这些位,则会产生两个位都设置的结果。
可能你想把操作数转换成一些预定义的值。
例如,您可以使用三元运算符
((((BTS & _BV(BT1)) ? 1 : 0) ^ (BTS & _BV(BT2)) ? 1 : 0))
或者你可以通过简单的比较来实现同样的效果:
((((BTS & _BV(BT1)) != 0) ^ ((BTS & _BV(BT2)) != 0))

inb24sb2

inb24sb24#

通常我会要求初学者在代码中使用 * 更少 * 的变量。在这种情况下,使用三个中间值可以压缩代码,以便读者可以看到正在发生的事情。
这是一个奇怪的真值表的3路异或。以下内容可能对您有所帮助:

while (1)
    {
        bool btn1 = BTS & _BV(BT1);
        bool btn2 = BTS & _BV(BT2);
        bool btn3 = BTS & _BV(BT3);

// AND
        if ( btn1 && btn2 && btn3 )
            LEDS |= _BV(LED0); //Set 1 on LED0
        else
            LEDS &= ~_BV(LED0); //Set 0 on LED0
// OR
        if( btn1 || btn2 || btn3 ) 
            LEDS |= _BV(LED1); //Set 1 on LED1
        else
            LEDS &= ~_BV(LED1); //Set 0 on LED1
//EXOR
//      if( btn1 ^ btn2 || btn2 ^ btn3 ) /* wrong! */
        if( btn1 || btn2 ^ btn3 )
            LEDS |= _BV(LED2); //Set 1 on LED2
        else
            LEDS &= ~_BV(LED2); //Set 0 on LED2
// NOR
        if( !( btn1 && btn2 && btn3 ) ) 
            LEDS |= _BV(LED3); //Set 1 on LED3
        else
            LEDS &= ~_BV(LED3); //Set 0 on LED3
    }

即使是宏标识符,使用前导下划线也是一个坏主意。用不同的东西。

编辑:

如上所述,你在这个问题中提出的真值表很奇怪。
下面进一步压缩代码,以强调您在问题中使用的逻辑运算。用几个#define宏代替象形文字代码:

while (1)
    {
        bool btn1 = BTS & _BV(BT1);
        bool btn2 = BTS & _BV(BT2);
        bool btn3 = BTS & _BV(BT3);

#       define  ON(led) ( (LEDS) |= (_BV(led)) )
#       define OFF(led) ( (LEDS) &= ~(_BV(led)) )

// AND
        if ( btn1 && btn2 && btn3 )
            ON(LED0);
        else
            OFF(LED0);

// OR
        if( btn1 || btn2 || btn3 ) 
            ON(LED1);
        else
            OFF(LED1);

//EXOR (As given by the OP)
//      if( btn1 ^ btn2 || btn2 ^ btn3 ) /* wrong! */
        if( btn1 || btn2 ^ btn3 )
            ON(LED2);
        else
            OFF(LED2);

//XOR (Added to appease others)
        if( btn1 ^ btn2 ^ btn3 )
            ON(LED2);
        else
            OFF(LED2);

// NOR
        if( !( btn1 && btn2 && btn3 ) ) 
            ON(LED3);
        else
            OFF(LED3);
    }

编辑2:

在这个问题引起的尖刻批评中,NAND被错误地贴上NOR的标签,到目前为止,还没有引起注意。这就是太多代码的干扰。
下面的代码减少了,读者可以很快满足自己,一切都是有序的。奇真值表的问题仍然没有解决。

// Two functions to set/reset a particular LED
void  on( unsigned char led ) { LEDS |=  _BV(led); }
void off( unsigned char led ) { LEDS &= ~_BV(led); }

    // array of 2 where [0] invokes off() and [1] invokes on()
    void (*set)[](unsigned char) = { off, on };

    while(1) {
        // ensure unknown bitmask results in either 0 or 1
        bool btn1 = !!(BTS & _BV(BT1));
        bool btn2 = !!(BTS & _BV(BT2));
        bool btn3 = !!(BTS & _BV(BT3));

        set[ btn1 & btn2 & btn3 ](LED0); // AND
        set[ btn1 | btn2 | btn3 ](LED1); // OR

#ifdef ODD_EXOR_TRUTH_TABLE
        set[ btn1 | btn2 ^ btn3 ](LED2); //EXOR (from OP)
#else
        set[ btn1 ^ btn2 ^ btn3 ](LED2); //XOR (conventional)
#endif

        set[ !( btn1 & btn2 & btn3 ) ](LED3); // NAND (not NOR)
        set[ !( btn1 | btn2 | btn3 ) ](LED4); // NOR (LED #4 !!)
    }
8fq7wneg

8fq7wneg5#

正如支持乌克兰所写的那样,真值表是为了

EXOR = (B ^ C) | A;

无论如何,设A、B和C为输入值(0000_0ABC)的位2、1和0

out = (0xF6 >> (input & 0x03)) & 0x01;

其中0xF6是EXOR列的位掩码(顶行是位0,底行是位7)。

相关问题