Hybrider statischer/dynamischer Arduino Mega2560 Einzelkanal-Kurzimpuls-Generator
Diese Impuls-Generator-Firmware verwendet Methoden, die z.B. in Kurzimpuls-Erzeugung mit Arduino Uno Teil 4: NOP for-Schleifen diskutiert werden, um sowohl dynamische (for-Schleifen von NOP-Befehlen) als auch statische (template-basierte automatisch entrollte) Impulse in kombinierter Weise zu erzeugen, sodass Sie mehr oder weniger jede Impulsbreite mit hoher Auflösung auswählen können.
Es funktioniert nicht zu 100%, da es noch einige Impulsbreitensprünge gibt. Es ist jedoch dennoch nützlich für viele Mikrosekunden-5V-Impulserzeugungs-Anwendungen und könnte auch ein nützlicher Technologie-Demonstrator für hybride statische/dynamische Impuls-Generatoren mit optimierten Integer-Template-Schleifen-Entrollungs-Ansätzen sein.
Um die Impulsbreite zu steuern, öffnen Sie eine serielle Schnittstelle und tippen Sie +, um die Impulsbreite zu erhöhen, oder -, um die Impulsbreite zu verringern.
Dies könnte auch auf Arduino Unos funktionieren, aber mein Uno hatte einen defekten seriellen Schnittstellen-Chip, daher verwendete ich ein ATMega2560-Board.
// 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);
}