混合静态/动态 Arduino Mega2560 单通道短脉冲发生器

此脉冲发生器固件使用例如 使用 Arduino Uno 生成短脉冲 第 4 部分:NOP for 循环 中讨论的方法,以组合方式生成动态(NOP 指令的 for 循环)和静态(基于模板自动展开)脉冲,因此你可以使用高分辨率选择几乎任何脉冲宽度。

它不是 100% 完美,因为仍然存在一些脉冲宽度跳变。但是,它对于许多微秒级 5V 脉冲生成应用仍然有用,也可能作为使用优化整数模板循环展开方法的混合静态/动态脉冲发生器的有用技术演示。

要控制脉冲宽度,打开串口界面并输入 + 增加脉冲宽度或 - 减小脉冲宽度。

这可能也适用于 Arduino Uno,但我的 Uno 串口接口芯片坏了,所以我使用了 ATMega2560 板。

pulse_generator.cpp
// License: CC0 1.0 Universal
// By Uli Köhler (techoverflow.net)
#include <Arduino.h>
#include <avr/io.h>
#include <ArduinoJson.h>

#define PORT13 PORTB
#define PIN13 7
#define PIN13_MASK (1 << PIN13)

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

int pulseLength = 1;

using PulseFunc = void (*)(int);

// Function pointer to void(int)
PulseFunc pulser = nullptr;
int pulserParam = 0; // Pre-computed parameter for the pulser function

void DoNothingPulser(int _) {
}

/**
 * Pulse the output pin, for very short pulses.
 * Will ONLY perform static (optimized) NOPs.
 * Will NOT perform dynamic (slower) NOP cycles
 *
 * Hence, this function does not have any overhead from for loops.
 */
template<int nNOPs>
void PulseStatic(int _) {
    cli();
    PORT11 |= PIN11_MASK;
    // Static for loop (optimized out - template-driven)
    // Force unrolling of the loop
    // NOTE: Compiler will only unroll for n < 8
    for (int i = 0; i < min(nNOPs, 6); i++) {
        _NOP();
    }
    if(nNOPs > 6) {
        for (int i = 0; i < nNOPs - 6; i++) {
            _NOP();
        }
    }
    PORT11 &= ~PIN11_MASK;
    sei();
}

/**
 * Pulse the output pin, for very short pulses.
 * Will perform static (optimized) NOPs and
 * also dynamic (slower) NOP cycles
 */
template<int nNOPs>
void PulseDynamic(int dynamicNOPs) {
    cli();
    PORT11 |= PIN11_MASK;
    // Dynamic for loop (NOT optimized out - template-driven)
    for (int i = 0; i < dynamicNOPs; i++)
    {
        _NOP();
    }
    // Static for loop (optimized out - template-driven)
    // Force unrolling of the loop
    // NOTE: Compiler will only unroll for n < 8
    for (int i = 0; i < min(nNOPs, 6); i++) {
        _NOP();
    }
    if(nNOPs > 6) {
        for (int i = 0; i < nNOPs - 6; i++) {
            _NOP();
        }
    }
    PORT11 &= ~PIN11_MASK;
    sei();
}

PulseFunc staticPulsers[] = {
    DoNothingPulser,
    &PulseStatic<0>, // 0 NOPs
    &PulseStatic<1>, // 1 NOPs ...
    &PulseStatic<2>,
    &PulseStatic<3>,
    &PulseStatic<4>,
    &PulseStatic<5>,
    &PulseStatic<6>,
    &PulseStatic<7>,
    &PulseStatic<8>,
    &PulseStatic<9>,
    &PulseStatic<10>,
    &PulseStatic<11>
};

PulseFunc dynamicPulsers[] = {
    &PulseDynamic<0>,
    &PulseDynamic<1>,
    &PulseDynamic<2>,
    &PulseDynamic<3>,
    &PulseDynamic<4>,
    &PulseDynamic<5>,
    &PulseDynamic<6>,
    &PulseDynamic<7>,
    &PulseDynamic<8>,
    &PulseDynamic<9>,
    &PulseDynamic<10>,
    &PulseDynamic<11>
};

constexpr int A = 7;
constexpr int B = 6;

void ReconfigurePulse() {
    // Very short pulses are performed using only static
    if(pulseLength < A) {
        pulser = staticPulsers[pulseLength];
    } else {
        pulser = dynamicPulsers[(pulseLength - A) % B];
        pulserParam = (pulseLength - A) / B;
    }
}

void setup()
{
    Serial.begin(115200);
    Serial.setTimeout(25);

    ReconfigurePulse(); // with default pulseLength

    pinMode(11, OUTPUT);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
    pulser(pulserParam);
    Serial.println(pulseLength);
    //ProcessSerialInput();
    // Wait until 50ms has passed since start
    while(Serial.available() > 0) {
        int c = Serial.read();
        if(c == '+') {
            pulseLength++;
            ReconfigurePulse();
        } else if(c == '-') {
            pulseLength--;
            if(pulseLength < 0) {pulseLength = 0;}
            ReconfigurePulse();
        }
    }
    delay(50);
}

Check out similar posts by category: Arduino, C/C++