我正在为一个学校项目使用 C 语言编写一个微型(ATmega328p)程序。问题是我试图表示这个真值表(A、B 和 C 只是输入,更具体地说是按钮),XOR 是 LED 上的输出,还有其他 3 个 LED,但它们正在执行不同的门和正确的操作现在他们工作正常。
我在这个特定部分遇到问题,因为 XOR 不起作用,当按下 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));
}
有什么可能出问题的想法吗?泰! :D
我尝试使用这个布尔表达式 y = A'B'C + A'BC' + AB'C' + ABC
编写一些代码,使用布尔表达式构建真值表,并将其与作业中给出的表进行比较。他们匹配吗?如果没有,请仔细考虑给定的真值表并构造一个匹配的布尔表达式。您还可以在 Google 中搜索一种称为卡诺图的东西,它可以帮助您从真值表构建表达式。
#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);
}
}
}
}
注意
((BTS & _BV(BT1)) ^ (BTS & _BV(BT2))
这里XOR运算是按位(非逻辑)运算。
由于两个操作数中都有
bitwise AND
,因此除了左侧的位 #BT1 和右侧的位 #BT2 之外,每个操作数的所有位均已重置。
左侧的#BT2 位和右侧的#BT1 位为零。这意味着,这里的
^
与按位 OR 完全相同,产生结果,其中两个位都被设置(如果在两个操作数中都设置了这两个位)。
您可能想将操作数转换为某些预定义值。
例如您可以使用三元运算符
((((BTS & _BV(BT1)) ? 1 : 0) ^ (BTS & _BV(BT2)) ? 1 : 0))
或者通过简单的比较也可以达到同样的效果:
((((BTS & _BV(BT1)) != 0) ^ ((BTS & _BV(BT2)) != 0))
通常我会要求初学者在代码中使用“更少”的变量。在这种情况下,使用三个中间值压缩代码,以便读者可以看到发生了什么。 对于三向异或来说,这是一个奇怪的真值表。以下内容可能对您有帮助:
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);
}