You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATmega328p单片机C语言三变量XOR逻辑LED输出异常求助

故障排查:ATmega328p三变量异或逻辑LED输出异常

问题描述

在学校项目中用C语言给ATmega328p编程,需实现对应真值表的三变量XOR逻辑并输出到LED。其余三个LED的逻辑门(AND、OR、NOR)功能正常,但XOR部分存在异常:本该在按下2个按钮时熄灭,却仅在无按钮按下时熄灭。尝试过布尔表达式y = A'B'C + A'BC' + AB'C' + ABC,问题仍未解决。

真值表

三变量XOR真值表

异常代码片段

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));
}

故障原因

1. 三变量异或逻辑表达式错误

你编写的((BT1 ^ BT2) || (BT2 ^ BT3))完全不符合三变量异或(奇偶校验)的核心逻辑。三变量异或的正确逻辑是输入中1的个数为奇数时输出1,偶数时输出0,对应的最简表达式是A^B^C,和你尝试的A'B'C + A'BC' + AB'C' + ABC等价。

你的错误表达式会导致:

  • 任意两个输入不同时就输出1,比如BT1=1、BT2=0、BT3=0时,BT1^BT2为1,整体表达式为1,LED点亮(符合预期);
  • 但当BT1=1、BT2=1、BT3=0时,BT2^BT3为1,整体表达式为1,LED点亮(不符合预期,此时应熄灭);
  • 只有三个输入全0时,两个异或结果都为0,表达式为0,LED熄灭,这就是你看到的异常现象。

2. 按钮输入的电平稳定性问题

从初始化代码看,你关闭了PORTB的内部上拉电阻:PORTB &= ~(_BV(BT1) | _BV(BT2) | _BV(BT3));,这意味着按钮未按下时输入引脚处于浮空状态,电平不确定。虽然其他逻辑门看似正常,但浮空状态可能导致输入电平波动,也会干扰XOR的判断。按钮输入必须确保未按下时电平稳定,通常启用内部上拉或外接下拉电阻。

修正方案

方案1:修正三变量异或逻辑表达式

将XOR部分代码替换为正确的异或逻辑,推荐两种写法:

写法1:转换为布尔值后异或

// 把每个按钮输入转换为0/1的布尔值
uint8_t a = (BTS & _BV(BT1)) ? 1 : 0;
uint8_t b = (BTS & _BV(BT2)) ? 1 : 0;
uint8_t c = (BTS & _BV(BT3)) ? 1 : 0;

if (a ^ b ^ c) { // 三变量异或,奇数个1时为真
    LEDS |= _BV(LED2);
} else {
    LEDS &= ~_BV(LED2);
}

写法2:用内置函数统计1的个数

// 提取三个按钮的输入位,统计1的个数是否为奇数
uint8_t btn_input = BTS & (_BV(BT1)|_BV(BT2)|_BV(BT3));
if (__builtin_popcount(btn_input) % 2 == 1) {
    LEDS |= _BV(LED2);
} else {
    LEDS &= ~_BV(LED2);
}

__builtin_popcount是GCC内置函数,可直接计算二进制中1的个数,适配AVR平台。

方案2:修复按钮输入的电平稳定性

启用PORTB的内部上拉电阻,修改init_ports函数:

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));
}

此时按钮未按下时输入为高电平(1),按下时接地为低电平(0),需同步修改逻辑判断(比如将BTS & _BV(BT1)改为!(BTS & _BV(BT1)),表示按下时为有效输入1),具体根据硬件接线调整。


内容的提问来源于stack exchange,提问作者Daniel Eduardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 05:52:09