-
PCBs Are Here
10/23/2015 at 09:10 • 2 commentsSo the PCBs arrived today. I must say that they look much smaller than they looked in Fritzing. Right off the bat I can see two pretty bad mistakes.
First, I made some connections between them at the last minute, because @davedarko pointed out that DirtyPCBs don't accept disconnected boards. The connections were some very small rectangles. I can see in the fabricated boards that they were enlarged consireably -- probably to make the whole thing more stable less prone to breaking on its own. Oh well, I will just have to dremel them to the right shape.
Second, the top two cats have a different design for the eyes -- the LEDs are on the back side, and there are holes through which they should shine. Those holes should not be metalized, as they touch the LED pads on both sides, and I designed them as non-metalized in Fritzing. DirtyPCBs made them metalized anyways -- probably a because they touched a pad and their software does that then. Oh well, some more dremeling.
Other than that it looks good and I will start assembling them as soon as I find where I misplaced my attiny85s, or the new batch that I ordered arrives, whichever comes first.
-
Programming ATtiny85
10/02/2015 at 16:26 • 1 commentWhile I'm waiting for my boards to be fabricated, I finally got my clip delivered, so I can start programming that SMD attiny. (Technically, I could have soldered some wires to it and programmed it that way, but I'm too lazy for that).
I started with this excellent tutorial and a blink sketch. What do you know, it worked at first try! The only problem I had was to get the IDE to see the USBASP programmer without root -- finally I failed with that, and ran the thing as root (I know, I know). I might need to work on that some more in spare time. Anyways, here's the photo of the LED blinking:
I used that USB2TTL as a power source, because I couldn't be bothered to stand up and look for a battery. So, the next step is to try and run that Nyan Cat sketch from the previous log. What do you know, it might actually work right away!
Nope. The Arduino core that I used here is very minimal and doesn't include the tone() function. Tried to implement it myself briefly, then to steal a ready version from some other project, but then I just tried a different, more complete (but more memory-heavy) core. This worked for the intro alone, but intro+loop is way too big to fit there. But no problem, it was in a very verbose format -- not only it recorded the frequencies of each individual note as two-byte integer, but also the duration of the note was a full byte. The first step was to get rid of the duration. Since this particular tune only uses two lengths of notes -- eights and sixteens -- I encoded that in the sign of the integer used by the note. That made the program compile, with whole 10 bytes to spare. But it didn't work. 10 bytes turned out to be too little for local variables to run this program. So the next step of the compression: the song only uses 18 different pitches, so I put the frequencies for those in an array, and used single-byte indices into that array for describing the notes (the sign of the index still denotes the length). That let me cut the program size in half, and there is still lots of room left for adding the blinking eyes.
#include "pitches.h" const int FREQ[] = { REST, NOTE_AS4, NOTE_AS5, NOTE_B4, NOTE_B5, NOTE_CS5, NOTE_CS6, NOTE_D5, NOTE_DS4, NOTE_DS5, NOTE_DS6, NOTE_E4, NOTE_E5, NOTE_E6, NOTE_FS4, NOTE_FS5, NOTE_GS4, NOTE_GS5, }; const signed char INTRO_NOTES[] = { 9, 12, -15, -4, 9, 12, 15, 4, 6, 10, 6, 2, -4, -15, 9, 12, -15, -4, 6, 2, 4, 6, 13, 10, 13, 4, 0 }; const signed char MELODY_NOTES[] = { -15, -17, 9, 9, 0, 3, 7, 5, 3, 0, -3, -5, -7, 7, 5, 3, 5, 9, 15, 17, 9, 15, 5, 9, 3, 5, 3, -9, -15, 17, 9, 15, 5, 9, 3, 7, 9, 7, 5, 3, 5, -7, 3, 5, 9, 15, 5, 9, 5, 3, -5, -3, -5, -15, -17, 9, 9, 0, 3, 7, 5, 3, 0, -3, -5, -7, 7, 5, 3, 5, 9, 15, 17, 9, 15, 5, 9, 3, 5, 3, -9, -15, 17, 9, 15, 5, 9, 3, 7, 9, 7, 5, 3, 5, -7, 3, 5, 9, 15, 5, 9, 5, 3, -5, -3, -5, -3, 14, 16, -3, 14, 16, 3, 5, 9, 3, 12, 9, 12, 15, -3, -3, 14, 16, 3, 14, 12, 9, 5, 3, 14, 8, 11, 14, -3, 14, 16, -3, 14, 16, 3, 3, 5, 9, 3, 14, 16, 14, -3, 3, 1, 3, 14, 16, 11, 12, 9, 12, 15, -3, -1, -3, 14, 16, -3, 14, 16, 3, 5, 9, 3, 12, 9, 12, 15, -3, -3, 14, 16, 3, 14, 12, 9, 5, 3, 14, 8, 11, 14, -3, 14, 16, -3, 14, 16, 3, 3, 5, 9, 3, 14, 16, 14, -3, 3, 1, 3, 14, 16, 3, 12, 9, 12, 15, -3, -5 }; #define BEEP_PIN 3 #define SPEED 1500 void play(const signed char *notes, const unsigned int length) { for (unsigned int n = 0; n < length; n++) { int f = notes[n]; int d; if (f < 0) { d = SPEED / 8; f = -f; } else { d = SPEED / 16; } tone(BEEP_PIN, FREQ[f], d); delay(1.3 * d); noTone(BEEP_PIN); } } void setup() { play(INTRO_NOTES, 26); } void loop() { play(MELODY_NOTES, 216); }
And the obligatory video:
-
Melody
09/27/2015 at 18:10 • 0 commentsWhile waiting for the boards, I need to write the program that would run on those boards. Quick googling allowed me to find an Arduino sketch that plays the Nyan Cat tune on Arduino. A quick refactoring and fixing of formatting, and here it is:
/* * Nyan Cat * Plays Nyan Cat * Example: * Circuit: 8-ohm speaker on digital pin 8 * By: Bruce Helsen (geobruce), Stan Draulans (purewantfun) */ #include "pitches.h" const unsigned int INTRO_NOTES[] = { NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B5, NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B5, NOTE_CS6, NOTE_DS6, NOTE_CS6, NOTE_AS5, NOTE_B5, NOTE_FS5, NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B5, NOTE_CS6, NOTE_AS5, NOTE_B5, NOTE_CS6, NOTE_E6, NOTE_DS6, NOTE_E6, NOTE_B5, }; const unsigned char INTRO_DURATIONS[] = { 16, 16, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 16, 16, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, }; const unsigned int MELODY_NOTES[] = { NOTE_FS5, NOTE_GS5, NOTE_DS5, NOTE_DS5, REST, NOTE_B4, NOTE_D5, NOTE_CS5, NOTE_B4, REST, NOTE_B4, NOTE_CS5, NOTE_D5, NOTE_D5, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_FS5, NOTE_GS5, NOTE_DS5, NOTE_FS5, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_CS5, NOTE_B4, NOTE_DS5, NOTE_FS5, NOTE_GS5, NOTE_DS5, NOTE_FS5, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_D5, NOTE_DS5, NOTE_D5, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_D5, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_FS5, NOTE_CS5, NOTE_DS5, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_FS5, NOTE_GS5, NOTE_DS5, NOTE_DS5, REST, NOTE_B4, NOTE_D5, NOTE_CS5, NOTE_B4, REST, NOTE_B4, NOTE_CS5, NOTE_D5, NOTE_D5, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_FS5, NOTE_GS5, NOTE_DS5, NOTE_FS5, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_CS5, NOTE_B4, NOTE_DS5, NOTE_FS5, NOTE_GS5, NOTE_DS5, NOTE_FS5, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_D5, NOTE_DS5, NOTE_D5, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_D5, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_FS5, NOTE_CS5, NOTE_DS5, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_B4, NOTE_CS5, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_E5, NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_FS4, NOTE_E5, NOTE_DS5, NOTE_CS5, NOTE_B4, NOTE_FS4, NOTE_DS4, NOTE_E4, NOTE_FS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_FS4, NOTE_B4, NOTE_B4, NOTE_AS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_E4, NOTE_E5, NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B4, NOTE_AS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_E5, NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_FS4, NOTE_E5, NOTE_DS5, NOTE_CS5, NOTE_B4, NOTE_FS4, NOTE_DS4, NOTE_E4, NOTE_FS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_B4, NOTE_CS5, NOTE_DS5, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_FS4, NOTE_B4, NOTE_B4, NOTE_AS4, NOTE_B4, NOTE_FS4, NOTE_GS4, NOTE_B4, NOTE_E5, NOTE_DS5, NOTE_E5, NOTE_FS5, NOTE_B4, NOTE_CS5, }; const unsigned char MELODY_DURATIONS[] = { 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, }; const int BEEP_PIN = 8; const int SPEED = 1500; void play(const unsigned int *notes, const unsigned char *durations, const unsigned int length) { for (unsigned int n = 0; n < length; n++) { int d = SPEED / durations[n]; tone(BEEP_PIN, notes[n], d); delay(1.3 * d); noTone(BEEP_PIN); } } void setup() { play(INTRO_NOTES, INTRO_DURATIONS, 25); } void loop() { play(MELODY_NOTES, MELODY_DURATIONS, 216); }
I'm not sure it will fit onto the ATtiny85, but if it doesn't, I see a lot of room for optimization there.
Since this is just "for fun" project, I'm completely ignoring the copyrights here (the Nyan Cat is a registered trademark anyways). I'm not even sure it would apply, since if I decided to transcribe that song myself, I would come up with exactly same notes, so there is not much originality here. I'm retaining the names of the original authors, though, because I think they deserve it anyways.
P.S. Wow, I didn't know you could embed videos in code!
-
Boards Ordered
09/27/2015 at 12:39 • 5 commentsFor a silly project, this has a lot of experimenting in it. I just figured out how to panelize a board design in Fritzing such that I can send it to DirtyPCBs. I managed to fit 6 nyan cats on a single 5×5cm board, so I should have about 60 of them when the boards arrive.
You can order yours too, if you like: http://dirtypcbs.com/view.php?share=11758&accesskey=87955192e4f12cde5290365bcd4b4c2e