使用 Arduino Uno 生成短脉冲 第 3 部分:使用 nop 指令改变脉冲宽度

在我们之前的文章 使用 Arduino Uno 生成短脉冲 第 2 部分:GPIO 寄存器访问脉冲宽度 中,我们详细介绍了如何使用直接 GPIO 端口寄存器写入生成极短的 125ns 脉冲。

基于我们之前文章的代码,可以使用 NOP 指令以相当高的分辨率改变脉冲长度。

NOP 指令是微控制器的机器指令,什么也不做(但通过 NOP 什么也不做恰好需要一个 CPU 周期,实际上会导致非常小的延迟)。延迟等于一个时钟周期 - 在 16 MHz 主时钟频率(如 Arduino Uno)下,这相当于 1/16MHz = 62.5ns

我们可以使用 #include <avr/cpufunc.h> 中可用的 _NOP()NOP 集成到之前文章的代码中

nop_pulse.ino
#define PORT11 PORTB
#define PIN11 3
#define PIN11_MASK (1 << PIN11)


void loop() {
    cli(); // Disable interrupts
    PORT11 |= PIN11_MASK; // Turn pin 11 on
    _NOP();
    PORT11 &= ~PIN11_MASK; // Turn pin 11 off
    sei(); // Enable interrupts again

    delay(10); // Wait 10ms
}

没有 NOP 的原始代码生成宽度为 125ns 的脉冲。

使用一个 NOP 指令,它生成宽度为 125ns + 62.5ns = 187.5ns 的脉冲:

示波器轨迹显示 Arduino Uno 使用一个 NOP 指令生成的 187.5ns 脉冲

类似地,如果我们使用两个 NOP

nop_pulse_2.ino
cli(); // Disable interrupts
PORT11 |= PIN11_MASK; // Turn pin 11 on
_NOP();
_NOP();
PORT11 &= ~PIN11_MASK; // Turn pin 11 off
sei(); // Enable interrupts again

我们将获得宽度为 125ns + 2*62.5ns = 250ns 的脉冲:

示波器轨迹显示 Arduino Uno 使用两个 NOP 指令生成的 250ns 脉冲

使用三个 NOP 我们将看到宽度为 125ns + 3*62.5ns = 312.5ns 的脉冲

示波器轨迹显示 Arduino Uno 使用三个 NOP 指令生成的 312.5ns 脉冲

完整示例

full_example.ino
#include <Arduino.h>
#include <avr/io.h>

#define PORT11 PORTB
#define PIN11 3
#define PIN11_MASK (1 << PIN11)

void setup() {
    pinMode(11, OUTPUT);
}

void loop() {
    cli();
    PORT11 |= PIN11_MASK;
    _NOP();
    _NOP();
    _NOP();
    PORT11 &= ~PIN11_MASK;
    sei();

    delay(10);
}

Check out similar posts by category: Arduino, Electronics