Last active
July 17, 2022 04:29
-
-
Save LightningStalker/ecaf6b26f6c48334a6190d6a4ce945c1 to your computer and use it in GitHub Desktop.
Digispark MPX Stereo Modulator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Digispark MPX Stereo Modulator | |
Based on a design found at | |
"http://cappels.org/dproj/FM_MPX_STEREO/ | |
SIMPLE FM STEREO MULTIPLEX ENOCDER CIRCUIT.html" | |
Be sure to use adequate low paths pants filtering and stay FCC | |
part 15 compliant. | |
ATTinyCore board library v1.5.2 | |
7/9/2022 ©The Lightning Stalker | |
*/ | |
#define MUXL_PIN 1 // The left speaker | |
#define MUXR_PIN 2 // The right speaker | |
#define PILOT_TONE_PIN 0 // 19KHz pilot tone | |
// initialize state machine at binary 011 (decimal 3) | |
volatile int DDRSHADOW = 3, PORTSHADOW = 0, othertimes = 0; | |
ISR(TIMER0_COMPA_vect) // Interrupt driven 2 * 38KHz | |
{ | |
cli(); | |
DDRSHADOW ^= 6; // Use of shadow registers for indirect -> | |
if (othertimes == 0) // half time for 19KHz | |
{ | |
PORTSHADOW ^= 1; // XOR bit toggling | |
PORTB = PORTSHADOW; | |
DDRB = DDRSHADOW; // -> port manipulation | |
} | |
else | |
{ | |
PORTSHADOW ^= 0; // Let's try making these two things the same. | |
PORTB = PORTSHADOW; | |
DDRB = DDRSHADOW; // to even out the timing a little | |
} | |
othertimes ^= 1; // since the pilot tone is half or 19KHz | |
sei(); // for some reason booleans don't work here. | |
} | |
void setup() { | |
// put your setup code here, to run once: | |
pinMode(MUXL_PIN, OUTPUT); // Why reinvent the wheel when you can | |
pinMode(MUXR_PIN, OUTPUT); // grab the wheel, stick it on your | |
pinMode(PILOT_TONE_PIN, OUTPUT); // cart and make it your bitch | |
// set up counter interrupt | |
TCCR0A = 0x00; // Normal port operation | |
TCCR0B = 0x00; | |
TCCR0A |= (1 << WGM01); // set compare match CTC mode | |
TCCR0B |= (1 << CS00); // no prescaling | |
OCR0A = 217; // 38KHz * 2 at the 16.5MHz Digispeak default | |
TIMSK |= (1 << OCIE0A); // enabling timer0 compare match interrupt | |
} | |
/* The Digispeak uses the internal oscillator of the Attiny85 which | |
is very unstable. It's best to use an external crystal and | |
change the above OCR1C compare match value accordingly. Most | |
easily done by just ditching the Digispock entirely and using a | |
bare Attiny85 to get all of the USB components out of the way | |
You will lose the USB functionality anyway. | |
*/ | |
void loop() { | |
// put your main code here, to run repeatedly: | |
// You can put something else here if you need to. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's advisable to use a crystal because there is some instability in the timing that is most likely an aspect of the internal RC oscillator.