Arduino中digitalWrite的说明:切换数字引脚的LED

时间:2014-12-16 03:05:52

标签: c arduino hardware arduino-uno

当我打开/关闭Arduino Uno上的LED时,我正试图了解“引擎盖下”会发生什么。

带有硬件项目的基本Hello World似乎是闪烁的板载LED。对于Arduino,有一个LED连接到引脚12。

我看了digitalWrite的源代码:

void digitalWrite(uint8_t pin, uint8_t val)
{
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN)
        return;

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER)
        turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
        *out &= ~bit;
    }
    else {
        *out |= bit;
    }

    SREG = oldSREG;
}

这里发生了什么?

特别是函数末尾的位错位。

1 个答案:

答案 0 :(得分:8)

AVR设备上的I / O分别安排在8个引脚的端口中。不同的设备具有不同数量的端口,这些端口使用字母命名。端口一次写入8位。

例如,要写入PORTA,您可以说PORTA = 0xFF;,这将打开PORTA上的每个引脚。

现在,Arduino平台还有引脚,这些引脚在所有可能的AVR芯片上都有编号和标准化。有一个从特定AVR器件引脚到Arduino引脚的映射,digitalWrite()函数必须找出它。查看特定芯片的数据表,了解端口和引脚是什么。例如,在Arduino Uno上,Arduino数字引脚0对应PORTD上的0引脚。

digitalWrite()顶部的两个函数决定了我们需要的AVR端口和引脚。

也可能将所需的引脚连接到定时器,使用脉冲宽度调制或PWM将其打开和关闭。如果是这样,那么我们需要确保禁用此功能。

要在端口上写入引脚,我们使用一些位算术。例如,要将PORTB上的引脚4设置为高电平(Arduino引脚12),我们使用PORTB = PORTB | (1<<4);PORTB |= (1<<4);。也就是说,保持所有其他引脚相同,但将引脚4设为高电平。

将引脚设置为低电平类似。我们希望单独保留其他位,因此我们and的数字几乎都是1。 PORTB &= ~(1<<4);

最后一个魔力是我们不希望在设置端口位时被打断。为此,我们使用cli();禁用中断。但是我们并不想在完成后启用中断;我们开始时可能没有启用它们。

诀窍是保存它们是否被启用,这是状态寄存器SREG中的一个位。因此,程序是保存SREG,如果它们尚未被禁用则禁用中断,执行我们想要的操作,然后将SREG恢复到我们(可能)更改I位之前的状态。 / p>