Generador de pulsos cortos híbrido estático/dinámico de un solo canal para Arduino Mega2560

Este firmware de generador de pulsos usa métodos discutidos p. ej. en Generación de pulsos cortos con Arduino Uno Parte 4: bucles for NOP para generar tanto dinámicos (bucles for de instrucciones NOP) como estáticos (basados en plantillas, automáticamente desenrollados) de manera combinada para que puedas seleccionar más o menos cualquier ancho de pulso usando una alta resolución.

No funciona al 100% ya que todavía hay algunos saltos en el ancho de pulso. Sin embargo, todavía es útil para muchas aplicaciones de generación de pulsos de 5V de microsegundos y también podría ser un demostrador de tecnología útil para pulsadores híbridos estáticos/dinámicos usando enfoques optimizados de desenrollado de bucles con plantillas de enteros.

Para controlar el ancho de pulso, abre una interfaz serial y escribe + para aumentar el ancho de pulso o - para disminuir el ancho de pulso.

Esto podría funcionar también en Arduino Unos pero mi Uno tenía un chip de interfaz serial roto así que usé una placa 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);

// Puntero a función a void(int)
PulseFunc pulser = nullptr;
int pulserParam = 0; // Parámetro precalculado para la función pulser

void DoNothingPulser(int _) {
}

/**
 * Genera pulso en el pin de salida, para pulsos muy cortos.
 * Solo realizará NOPs estáticos (optimizados).
 * No realizará ciclos NOP dinámicos (más lentos)
 *
 * Por lo tanto, esta función no tiene ninguna sobrecarga de bucles for.
 */
template<int nNOPs>
void PulseStatic(int _) {
    cli();
    PORT11 |= PIN11_MASK;
    // Bucle for estático (optimizado - basado en plantillas)
    // Forzar el desenrollado del bucle
    // NOTA: El compilador solo desenrollará para 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();
}

/**
 * Genera pulso en el pin de salida, para pulsos muy cortos.
 * Realizará NOPs estáticos (optimizados) y
 * también ciclos NOP dinámicos (más lentos)
 */
template<int nNOPs>
void PulseDynamic(int dynamicNOPs) {
    cli();
    PORT11 |= PIN11_MASK;
    // Bucle for dinámico (NO optimizado - basado en plantillas)
    for (int i = 0; i < dynamicNOPs; i++)
    {
        _NOP();
    }
    // Bucle for estático (optimizado - basado en plantillas)
    // Forzar el desenrollado del bucle
    // NOTA: El compilador solo desenrollará para 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() {
    // Los pulsos muy cortos se realizan usando solo estático
    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(); // con pulseLength predeterminado

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

void loop()
{
    pulser(pulserParam);
    Serial.println(pulseLength);
    //ProcessSerialInput();
    // Esperar hasta que hayan pasado 50ms desde el inicio
    while(Serial.available() > 0) {
        int c = Serial.read();
        if(c == '+') {
            pulseLength++;
            ReconfigurePulse();
        } else if(c == '-') {
            pulseLength--;
            if(pulseLength < 0) {pulseLength = 0;}
            ReconfigurePulse();
        }
    }
    delay(50);
}

Echa un vistazo a artículos similares por categoría: Arduino C/C++