混合静态/动态 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);
}If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow