Arduino波形发生器开发求助:除方波外其余波形无法正常工作
Hey there! Let's figure out why only your square wave is working while the other waveforms are failing. Square waves are easy to pull off with simple digital high/low toggles, but sine, triangle, and sawtooth waves need analog-like voltage changes—this is where most folks hit snags. Let's break down the common issues and fixes based on what you've shared.
First, Check Your Output Setup
Square waves work on any digital pin because they only need two states (HIGH/LOW), but the other waveforms require analog/PWM output (since they need smooth voltage transitions). Here's what to verify:
- Use a PWM-enabled pin (marked with
~on your Arduino—like 3, 5, 6, 9, 10, 11 on Uno/Nano). Non-PWM pins can't output varying voltage levels. - Add an RC low-pass filter to your output pin: a 1kΩ resistor in series with a 10µF capacitor (or 0.1µF for higher frequencies) connected to ground. This converts the PWM pulses (rapid on/off) into a smooth analog voltage. Without this, your "analog" waveforms will still look like messy square waves on an oscilloscope.
Fix Your Waveform Generation Logic
Your code snippet cuts off, but here's a complete, tested implementation for all four waveforms, with key fixes:
const int waveOutPin = 3; // PWM pin (~3) const int modeBtnPin = 8; enum WaveMode { SINE, SQUARE, TRIANGLE, SAWTOOTH }; WaveMode currentMode = SQUARE; // Precomputed sine wave values (0-255) for fast output byte sineWave[256]; void setup() { pinMode(waveOutPin, OUTPUT); pinMode(modeBtnPin, INPUT_PULLUP); // Use internal pullup to avoid external resistors // Initialize sine wave array (maps 0-2π to 0-255) for (int i = 0; i < 256; i++) { float rad = i * (2 * PI / 256); sineWave[i] = (sin(rad) + 1) * 127.5; // Shift sine from -1~1 to 0~255 } } void loop() { // Handle mode switching with button int btnState = digitalRead(modeBtnPin); static int lastBtnState = HIGH; if (btnState == LOW && lastBtnState == HIGH) { // Cycle through modes on button press currentMode = (WaveMode)((currentMode + 1) % 4); delay(200); // Debounce delay } lastBtnState = btnState; // Generate selected waveform switch(currentMode) { case SINE: static int sineIdx = 0; analogWrite(waveOutPin, sineWave[sineIdx]); sineIdx = (sineIdx + 1) % 256; delayMicroseconds(100); // Adjust to change frequency (smaller = faster) break; case SQUARE: digitalWrite(waveOutPin, HIGH); delayMicroseconds(500); digitalWrite(waveOutPin, LOW); delayMicroseconds(500); break; case TRIANGLE: static int triVal = 0; static bool triUp = true; analogWrite(waveOutPin, triVal); if (triUp) { triVal++; if (triVal >= 255) triUp = false; } else { triVal--; if (triVal <= 0) triUp = true; } delayMicroseconds(100); break; case SAWTOOTH: static int sawVal = 0; analogWrite(waveOutPin, sawVal); sawVal = (sawVal + 1) % 256; // Reset to 0 after 255 delayMicroseconds(100); break; } }
Key Fixes Explained
- Precomputed sine array: Using
sin()in the loop is slow and can cause jitter. Precalculating values once insetup()makes output smooth and consistent. - PWM + Filter: The
analogWrite()function outputs PWM, which the RC filter converts to a smooth analog signal—critical for non-square waves. - Debounced button: The 200ms delay prevents accidental mode switches from button bounce.
- Smooth transitions: For triangle/sawtooth, we increment/decrement values gradually instead of jumping, which creates the linear voltage change needed for those waveforms.
Additional Tips
- If you need higher frequency or precision waveforms, replace
delayMicroseconds()with timer interrupts (avoids loop jitter). - Adjust the
delayMicroseconds()value to change waveform frequency—smaller numbers = faster waves. - Double-check your wiring: Make sure the RC filter is connected correctly (resistor from PWM pin to capacitor, capacitor to ground, output taken from the resistor-capacitor junction).
内容的提问来源于stack exchange,提问作者urukh

