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.
// 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);
}