From 376951bded78c7c978ffb5bdc7c4752b23640fc3 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sat, 1 Sep 2018 15:15:59 -0600 Subject: [PATCH] verified ino is good, using simpleio for notes, starting on m0 port --- ...inket_Question_Block_Sound_Jewelry.ino.swp | Bin 0 -> 16384 bytes .../README.md | 4 + .../Trinket_Question_Block_Sound_Jewelry.ino | 176 ++++++++++++++++++ .../Trinket_Question_Block_Sound_Jewelry.py | 9 + 4 files changed, 189 insertions(+) create mode 100644 Trinket_Question_Block_Sound_Jewelry/.Trinket_Question_Block_Sound_Jewelry.ino.swp create mode 100644 Trinket_Question_Block_Sound_Jewelry/README.md create mode 100644 Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.ino create mode 100644 Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.py diff --git a/Trinket_Question_Block_Sound_Jewelry/.Trinket_Question_Block_Sound_Jewelry.ino.swp b/Trinket_Question_Block_Sound_Jewelry/.Trinket_Question_Block_Sound_Jewelry.ino.swp new file mode 100644 index 0000000000000000000000000000000000000000..a81577878ada70be80131833204c586553bd7562 GIT binary patch literal 16384 zcmeI2%WouC6~+rD;hhH{u}a{2qKw;_w%u)JCc~H^w0k@rGk&GrlR=44bGzzx`^ME( zJ@s%;4(&#yUusb)c79fgU8e&3ao#Cy|YYz5QvLnNe>ew}DBQyNQhsP1budH)&?$sJ9lz z{$X!F&ZD6BIWsX~GJR8xmTVNiDH*Fq6$9^F2JZ7dxzcPra(YgE^dmRkxy!6pRxwa9 zP%%(3P%%(3P%%(3P%%(3@VX3S<5S+t{O8@^N${=`FLQPHTOjvNf&0LB%I|zsSH(cZ zK*d1CK*d1CK*d1CK*d1CK*d1CK*d1C!2byYI`F(lk@d^+kk9$Q)Bt|+fak>^0(J0@ z`#tZ+;74EpJ`NrRzo#JZRj>~31^0koeu%yx0yn{D!4u$LAN0KM0}Va~e)j>-djVVm z4}*KaDe$xRd)`mMcfr>{2n-0oL*S+NdESd)03HK>e=l-@AA$k+6nFsq={?*7KL7!E z2)uMJ@`A5`Hu(2F%mr?NdGJ??9Df1d1_`(Y&Vp0mHxx*I4SoeukbnUA;1l4_@b?Sw zb0Azk2j1{fYI#|84~+5;>{!`UWd|lw<2+L~%3`I}kx8a1j3&KDOWg^`VO`vM#wr|Fn8pMej z+bC7dGw156Z+xAnMs2NMNf(xizTH@j^ldw`cZ@0p(MPG`&?Lng2T44-i(gsGIMh?oh)U&klah;8q|EKi zB#{n9NhV2hIIL~%bQ_Khwc^$dzl`9fndn2~H0!i1TI;skokk12iG(*dwok;BFO5Rl zy_?%k(}j5LI2zbt4$)mZGRblqk(gXHocg3~EfV%;0?m{>H5png#t8Cks{E-R8j(#0 z&*o{S^k^K~EDsFQC-IRD(5pI%!+eBQ#!;5Uq1c+Up%z*m>qKV^AX2DWo=S7!Nc&k1 zC5|dJNX)I=ME(?##iFx#I1CFCijfK_0)x0CEARcdF_=#bEVc5g&#Ll`Ea!4O7}Qmx zzHDa(+qHLC$aG=Hq)71Jp45uPZsx&`pU_%C}7Z&LR#i#VpC}E=z zM(!R39t=`zSGRnt_WmN?JE zpM%(>(L62!Z*HyS{q$BY-ZRlhX0=q49w0DnY|1>>ad<~hqWwb^4~hYhEY1_ft5o9G z<2Xuf-=fB;isDI0j*c+F+`UvqKRO~{%-RQplM_R6E5O|cdE^W0xNaTdI+{}5JrSCv+vo&+|_AXx<$KUpwI1*FuwmVJnwdTs>tE#w& z1?L-&Itx%bQ)#A?j25s|wr}$dd%LUsg>&1>E9Wn``_4RQxgmbco$luL{&hYZF3LC~ zI3YMyyH~H$m^s&7;C;;sSwtNv5%P?hbDyPcNKme;=A|Z{X;KW^I8WZ&+G_82)N@7n z*lS;3Ct#dhOyoppiZ3RK~7tBzBguW#iY~D>e zFMVv}OPnYC2ZhzDp@|6FXadcvyMiWqyaB~UXeL96hIJV$l~98a=C*L{HYvoEn96+9 zB?P`KDNVW2;bbe1bH^=?7flOsj+g30>g(CwBJs;cL{h>g0lC~O7Z;1*M{dRxC)O&` z#A7@HHz1Npmci24Xjw^UVUpd8Xq$(DiiNj{W!MCxOaj@!@+dMsDnhazRzK<56jF zZo?btpwt5FK=KF!W*4`qFMFu$NGdWDB3wQg$cC%NCb47mM`%EMq}tdA?Gxi?;dGVs zBMjBfZdWDrjQJ5=A8&*G7hR&%O^}|_Y)9Q5OHqO(>jZCXy|&JL^Oe z)FQX`Ig!5r=VB zC%a(P7zllbwd%L{Iljr}h^W6RiAkY8u@mrqxUj)yB23P`%;BWVP z-uJ*az&`je_+!~uY5~<%F;Fp3F;Fp3F;Fp3F;Fp3F;Fp3F;Fq^zh^)W#%87Onyajx zJuAey1j7%}%37Nq?`^JEDdn2ZxlcsH#$;rKl=J zR;exQ$7R`VL`{)`7EKwOs)rO_nUy+>4x}b5HLqgO-KVbJ)lP>AEvRROniC6(B*l^6 z>m5+ki{r+k+)uesPVaWxo9m5Mabi~%u>H7@Wu&D{b6lxI9|aZk7pC~XTG02W4}<$ TC4DHB$SDHj%VDBaZd30+@hYLp literal 0 HcmV?d00001 diff --git a/Trinket_Question_Block_Sound_Jewelry/README.md b/Trinket_Question_Block_Sound_Jewelry/README.md new file mode 100644 index 000000000..a87fee388 --- /dev/null +++ b/Trinket_Question_Block_Sound_Jewelry/README.md @@ -0,0 +1,4 @@ +# Trinket "Question Block" Sound Jewelry + +Code to accompany this tutorial: +https://learn.adafruit.com/trinket-question-block-sound-jewelry diff --git a/Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.ino b/Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.ino new file mode 100644 index 000000000..5186cdbfb --- /dev/null +++ b/Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.ino @@ -0,0 +1,176 @@ +/* ----------------------------------------------------------------------- + Super Mario Bros-inspired coin sound for Adafruit Trinket & Gemma. + + Requires piezo speaker between pins 0 & 1, vibration sensor or + momentary button between pin 2 & GND. Tap for "bling!" noise. + Optional LED+resistor on pin 4 for light during play. + + Runs equally well on a 16 MHz or 8 MHz Trinket, or on Gemma. Use what + you've got, no need to get all HOMG MOAR MEGAHURTZ!!1! about it. :) + + This is NOT good beginner code to learn from...there's very little + resemblance to a "normal" Arduino sketch as we poke around with ATtiny + peripheral registers directly; will NOT run on other Arduino boards. + Commented like mad regardless, might discover fun new stuff. + + Written by Phillip Burgess for Adafruit Industries. Public domain. + ----------------------------------------------------------------------- */ + +#include +#include + +// These variables are declared 'volatile' because their values may change +// inside interrupts, independent of the mainline code. This keeps the +// optimizer from removing lines it would otherwise regard as unnecessary. +// 'quietness' is basically the inverse of volume -- the code was a little +// smaller expressing it this way. 0 = max volume, 127 = quietest. +// 'count' is incremented while generating a square wave. Used for timing, +// and bit 0 indicates whether this is the 'high' or 'low' part of the wave. +volatile uint8_t quietness; +volatile uint16_t count; + +// ONE-TIME INITIALIZATION ----------------------------------------------- + +void setup() { +#if (F_CPU == 16000000L) + clock_prescale_set(clock_div_1); +#endif + + // ATtiny85 has a special high-speed 64 MHz PLL mode than can be used + // as an input to Timer/Counter 1. The ATmega chips don't have this! + // Requires a little song and dance to set this up... + PLLCSR |= _BV(PLLE); // Enable 64 MHz PLL + delayMicroseconds(100); // Allow time to stabilize + while(!(PLLCSR & _BV(PLOCK))); // Wait for it...wait for it... + PLLCSR |= _BV(PCKE); // Timer1 source = PLL! + + // Enable Timer/Counter 1 PWM, OC1A & !OC1A output pins, 1:1 prescale. + GTCCR = TIMSK = 0; // Timer interrupts OFF + OCR1C = 255; // 64M/256 = 250 KHz + OCR1A = 127; // 50% duty at start = off + TCCR1 = _BV(PWM1A) | _BV(COM1A0) | _BV(CS10); + + // Normally the Arduino core library uses Timer/Counter 1 for functions + // like delay(), millis(), etc. Having changed the cycle time above, + // and turning off the overflow interrupt, these functions won't work + // after this. Keeping track of time is our own responsibility now. + + // The Timer/Counter 1 PWM output doesn't time the output square wave; + // the frequency (250 KHz) is much too fast for that. Rather, the + // speaker itself physically acts as a filter, with the average duty + // cycle determining the cone position; center=off, 0,255=extremes. + // A separate timer (using the actual sound frequency) then toggles the + // duty cycle to adjust amplitude, providing volume control... + + // Configure Timer/Counter 0 for PWM (no interrupt enabled yet). + TCCR0A = _BV(WGM01) | _BV(WGM00); // PWM mode + + // An external interrupt (INT0, pin 2 pulled to GND) wakes the chip + // from sleep mode to play the sound. + MCUCR &= ~(_BV(ISC01) | _BV(ISC00)); // Low level (GND) trigger +} + +// ----------------------------------------------------------------------- + +void loop() { + + // To maximize power savings, pins are set to inputs with pull-up + // resistors enabled (except for pins 1&4, because LEDs). + DDRB = B00000000; PORTB = B00101101; + + // The chip is then put into a very low-power sleep mode... + power_all_disable(); // All peripherals off + GIMSK |= _BV(INT0); // Enable external interrupt + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Deepest sleep + sleep_mode(); // Stop, will resume here on wake + // Code resumes when pin 2 is pulled to GND (e.g. button press). + GIMSK &= ~_BV(INT0); // Disable external interrupt + + // Only the two timer/counters are re-enabled on wake. All other + // peripheras remain off for power saving. This means no ADC, I2C, etc. + power_timer0_enable(); + power_timer1_enable(); + + DDRB = B00010011; // Output on pins 0,1 (piezo speaker), 4 (LED) + PORTB = B00010000; // LED on + + // Play first note. B5 = 987.77 Hz (round up to 988) + pitch(988); // Sets up Timer/Counter 1 for this frequency + // The pitch() function configures the timer for 2X the frequency, an + // interrupt then alternates between the 'high' and 'low' parts of the + // square wave. 988 Hz = 1976 interrupts/sec. 'count' keeps track. + // First note is 0.083 sec. 1976 * 0.083 = 164 interrupt counts. + // Combined length of notes is 0.92 sec, or 1818 interrupt counts at + // this frequency. The amplitude (volume) fades linearly through the + // duration of both notes. So this calculates the portion of that drop + // through the first note... + while(count < 164) quietness = 128L * count / 1818; + // This uses fixed-point (integer) math, because floating-point is slow + // on the AVR and uses lots of program space. A large integer multiply + // (32-bit intermediate result) precedes an integer division, result is + // effectively equal to floating-point multiply of 128.0 * 0.0 to 1.0. + + pitch(1319); // Init second note. E6 = 1318.51 Hz, round up to 1319. + // 1319 Hz tone = 2638 Hz interrupt. To maintain the duration and make + // the volume-scaling math continue from the prior level, counts need to + // be adjusted to take this timing change into account. The total + // length at this rate would be 2638 * 0.92 = 2427 counts, and first + // note duration would have been 2638 * 0.083 = 219 counts... + count = 219; + // Rather than counting up to the duration, just keep playing until the + // effective volume is zero. + do { + quietness = 128L * count / 2427; + } while(quietness < 127); + + // Finished playing both notes. Disable the timer interrupt... + TIMSK = 0; + + // Before finishing, the piezo speaker is eased in a controlled manner + // from the volume-neutral position (127) to its off position (0) in + // order to avoid an audible 'pop' when the code goes to sleep. + for(uint8_t i=127; i--; ) { + OCR1A = i; // Speaker position + for(volatile uint16_t x = F_CPU/32000; --x; ); // Easy, not too fast + } +} + +// ----------------------------------------------------------------------- + +// These tables list available timer/counter prescaler values and their +// configuration bit settings. Normally I'd PROGMEM these, but for these +// short tables the code actually compiles a little smaller this way! +const uint16_t prescale[] = { 1, 8, 64, 256, 1024 }; +const uint8_t tccr[] = { + _BV(WGM02) | _BV(CS00), + _BV(WGM02) | _BV(CS01), + _BV(WGM02) | _BV(CS01) | _BV(CS00), + _BV(WGM02) | _BV(CS02), + _BV(WGM02) | _BV(CS02) | _BV(CS00), +}; + +// Configure Timer/Counter 0 for the requested frequency +void pitch(uint16_t freq) { + + uint8_t i; + uint16_t f2 = freq << 1; // 2X frequency + uint32_t o; + + // Find CPU prescale that can accommodate requested frequency + for(i=0; i < (sizeof(prescale) / sizeof(prescale[0])) && + (o = (((F_CPU / (uint32_t)prescale[i]) + freq) / + (uint32_t)f2) - 1) >= 256L; i++); + + TCCR0B = tccr[i]; // Prescale config bits + OCR0A = (uint8_t)o; // PWM interval for 2X freq + count = 0; // Reset waveform counter + TIMSK = _BV(OCIE0A); // Enable compare match interrupt +} + +// TIMER0_OVF vector is already claimed by the Arduino core library, +// can't use that. So the compare vector is used instead... +ISR(TIMER0_COMPA_vect) { + // Bit 0 of count indicates high or low side of square wave. + // OCR1A sets average speaker pos, quietness adjusts amplitude. + OCR1A = (count++ & 1) ? 255 - quietness : quietness; +} \ No newline at end of file diff --git a/Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.py b/Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.py new file mode 100644 index 000000000..6eb033d09 --- /dev/null +++ b/Trinket_Question_Block_Sound_Jewelry/Trinket_Question_Block_Sound_Jewelry.py @@ -0,0 +1,9 @@ +import time +import board +import simpleio + +while True: + for f in (262, 294, 330, 349, 392, 440, 494, 523): + simpleio.tone(board.D2, f, 0.25) # on for 1/4 second + time.sleep(0.05) # pause between notes + time.sleep(0.5)