Gerador de pulso curto de canal único híbrido estático/dinâmico para Arduino Mega2560

Este firmware de gerador de pulso utiliza métodos discutidos, por exemplo, em Geração de pulso curto com Arduino Uno Parte 4: loops for com NOP para gerar tanto pulsos dinâmicos (loops for de instruções NOP) quanto estáticos (baseados em template, automaticamente desenrolados) de forma combinada, permitindo selecionar praticamente qualquer largura de pulso com alta resolução.

Não funciona 100% pois ainda há alguns saltos na largura do pulso. No entanto, ainda é útil para muitas aplicações de geração de pulsos de 5V na faixa de microssegundos e também pode ser um demonstrador de tecnologia útil para geradores de pulso híbridos estáticos/dinâmicos usando abordagens otimizadas de desenrolamento de loops com templates de inteiros.

Para controlar a largura do pulso, abra uma interface serial e digite + para aumentar a largura do pulso ou - para diminuir a largura do pulso.

Isso também pode funcionar em Arduino Unos, mas meu Uno tinha um chip de interface serial quebrado, então usei uma 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);

// Ponteiro de função para void(int)
PulseFunc pulser = nullptr;
int pulserParam = 0; // Parâmetro pré-calculado para a função do gerador de pulso

void DoNothingPulser(int _) {
}

/**
 * Gera um pulso no pino de saída, para pulsos muito curtos.
 * Executará APENAS NOPs estáticos (otimizados).
 * NÃO executará ciclos NOP dinâmicos (mais lentos)
 *
 * Portanto, esta função não tem nenhuma sobrecarga de loops for.
 */
template<int nNOPs>
void PulseStatic(int _) {
    cli();
    PORT11 |= PIN11_MASK;
    // Loop for estático (otimizado - controlado por template)
    // Força o desenrolamento do loop
    // NOTA: O compilador só desenrolará 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();
}

/**
 * Gera um pulso no pino de saída, para pulsos muito curtos.
 * Executará NOPs estáticos (otimizados) e
 * também ciclos NOP dinâmicos (mais lentos)
 */
template<int nNOPs>
void PulseDynamic(int dynamicNOPs) {
    cli();
    PORT11 |= PIN11_MASK;
    // Loop for dinâmico (NÃO otimizado - controlado por template)
    for (int i = 0; i < dynamicNOPs; i++)
    {
        _NOP();
    }
    // Loop for estático (otimizado - controlado por template)
    // Força o desenrolamento do loop
    // NOTA: O compilador só desenrolará 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() {
    // Pulsos muito curtos são gerados usando apenas 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(); // com pulseLength padrão

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

void loop()
{
    pulser(pulserParam);
    Serial.println(pulseLength);
    //ProcessSerialInput();
    // Espera até que 50ms tenham passado desde o início
    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++