This is a battery-powered LED heart with several different animated flashing sequences, selectable with a push button. I designed and built it for my girlfriend this Christmas. While waiting for the parts to arrive, I went through several redesigns, particularly because I couldn't find a good tradeoff between a good LED layout and low complexity.

I finally settled on a layout that uses 14 LEDs, two 8-bit shift registers and an ATtiny85V(though even a lowly ATtiny25 would probably work if I simplified the code, I wasn't sure how much program space I'd need and the cost difference is negligible). I've used a socket for the microcontroller so I could test different patterns and animation speeds. After running for 50 straight hours(with a somewhat above average "load" animation), my generic AA alkalines(fresh when the test started) were measured at 1.71 volts. It was still working, albeit with very low light coming from the LEDs.

So here is my first Instructable, for your enjoyment and/or education. See a video of it in action here(it doesn't actually "fade"; that's just my camera being slow) and showing off newer patterns here(sorry for the color balance). Hopefully my girlfriend likes it, and I hope you do, too! Please let me know if anything is too confusing or if you have any questions. If you decide to make one yourself, or if you're inspired to build something similar, I'd enjoy seeing your results!

Step 1: Parts

The following is the parts I've used in my design. You may wish to use a different shape with more or less LEDs, and most parts can be substituted. Prices are all before any taxes.

* Grid PC Board; I got mine at a local independent electronics shop, but it's very similar to RadioShack's #276-158. You can probably find one on Digi-Key, but they are needlessly expensive($10+ for a board this size), as they only carry boards designed for repeated resoldering. I'd avoid a stripboard unless you know what you're doing and are familiar with them. RadioShack's is $3.19.
Note that you could prototype this project on a solderless breadboard(and I did all of my microcontroller programming/testing on one), but the "heart" or other shape aspect will be mostly lost, obviously.

* AAx2 battery holder; I also got this from my local retailer, but you could also use RadioShack #270-408 for $1.99.
You could instead choose a low voltage(<5.5 volt for most AVR microcontrollers) power adapter instead, or a higher voltage(maybe a 9V battery, but you wouldn't have much run time) supply with a regulator.

* 3mm red LEDs - 14 pcs.; Mine are low current(2mA, but they handle up to ~30mA) from Digi-Key(754-1245-ND), and cost just under six cents each in a bag of 100. I should warn you that this exact part is actually red-orange when lit up. RadioShack part 276-026 is very comparable, and they're truly red, but cost $1.69 per pack of 2. Ouch. Converted cost for this project is $0.83($1.26 if you don't go for the 100 pack)for the Digi-Key LEDs and $11.83 for the Shack's LEDs.
Color is up to preference, but other colors have different voltage drops. More information below.

* 330 ohm resistors - 14 pcs.; Power rating and resistive element type don't make a difference, but carbon film are cheapest. RadioShack sells these in packs of five(#271-012) for $1.19 each. Digi-Key CF14JT330RCT-ND are eight cents each, individually, but if you're working with a lot of LEDs, you might wanna buy a 100 pack for $2.19 total. Amazing deal, if you ask me. RadioShack, $3.57(with one lonely resistor left over); Digi-Key, $2.19(with 86 resistors partying in your spare parts container afterward).
I calculated this resistance to provide between 2-5mA to the LEDs over the life of two alkaline AA batteries(3.2 volts fully charged, ~2 volts nearly dead). If you'll be using a different power supply and/or different LEDs, you should use an online calculator to find the value you need. Assuming you're still using batteries, find the charged and depleted voltages to ensure your LEDs look good over the life of the batteries. Here is a good calculator, but be sure to change the "how many connected" field from 2 to 1, unless you want to run multiples(do so at your own risk and with experience). Keep in mind that shift register pins don't like to supply more than about 25mA each.

* 47k ohm pull-up resistor; This lets us use the button reliably. It doesn't have to be as high as 47k, but I chose it to draw as little current as possible, as I'm running from batteries. You only need one, but RadioShack #271-1342 will get you five for $1.19 and Digi-Key S47KQCT-ND will run you $0.08 apiece.
If you already have a resistor greater than 10k, you could use it, but try not to go too far above 47k, or your microcontroller may not get enough current to be held high. Experiment on a breadboard if you have any doubt!

* 74HC595 shift register - 2 pcs.; These are each capable of driving 8 outputs, although one output on each is awkwardly on the other side of the chip. Since I'm using 14 LEDs, I just left those "odd" outputs unconnected and wrote my code to match. I used 2 296-1600-5-ND from Digi-Key at $0.63 each. RadioShack doesn't seem to sell shift registers, so my recommended Digi-Key alternative is SparkFun(COM-00733) who will charge a modest $1.50 each. Totals are $1.26 for Digi-Key's or $3 at SparkFun.

* DIP-8 IC socket; I highly recommend one for making adjustments to the code after assembly. Even if you don't intend to write or modify your own code, if there's some problem, you'll want to be able to diagnose it. I used a Swiss-milled gold-plated socket I had lying around, but it really doesn't make a difference for this. Digi-Key A100204-ND is $0.14 and RadioShack #276-1995 is $0.59.
You don't necessarily need one, if you're confident with your assembly and soldering skills. An alternative, if you'd still like programming access afterward, is to use pin headers to connect an ICSP(in circuit serial programmer). Heck, maybe you wanna use both.

* ATtiny85V; This little 8 pin microcontroller has 8K of program space, which is lovely for prototyping. I've found I don't need that much, and could get away with an ATtiny45 or possibly even a 25. I chose the "V" version because it reliably runs on voltages as low as 1.8 volts, so it's ideal for battery use. RadioShack doesn't sell microcontrollers alone, but SparkFun has the standard(not low-voltage) version COM-09378 for $2.84 and Digi-Key sells the ATtiny85V(ATTINY85V-10PU-ND) for $2.26.
Just about any microcontroller can be used here, as we only need 3 pins for shift register control and one pin for button input. If you want to forgo the shift register wiring(and coding, if you don't use my code), you should go with a controller that has enough pins to drive all of your LEDs. You can greatly increase the number of LEDs a chip can drive with charlieplexing, but that's a topic for another Instructable. Also be sure to get a different socket size if your microcontroller uses more pins!

* Power switch; I won't recommend a specific switch here, because there are thousands of valid options, and what you pick depends on what case you put this in, if you use a case at all. SPST or SPDT will work, but SPDT may be easier to find. Spec the voltage rating for your power supply, and calculate your worst-case scenario for current. Most switches will provide more than enough, but for the record, my design here will consume no more than 60mA. I paid about $4 for mine, a panel-mount paddle switch.

* Push button; This will be used to switch to the next pattern animation. Like above, there are far too many options to recommend one. I prototyped with a standard, breadboard-compatible button, but my final design uses a panel-mount button. A four pack cost $3.69.

* Enclosure; If the button/switch had a lot of options, this is just crazy. You could put this in a cardboard box, or mounted to a piece of wood or plexiglass, or even leave it exposed. Put it in a custom wooden case or hang it on the wall. Just be sure that nothing shorts out on the bottom of the circuit board. If you mount on metal, use standoffs or a lot of electrical tape. I used a tin that has a clear, plastic window in its lid. My mom had this lying around, so it cost me nothing.

Step 2: Tools

You'll need a few, basic tools to complete this project, and maybe some more if you want to put it in a case.

* Soldering iron and solder; Be sure to have a fine tip, or you'll probably make a mess on the board and even short out some connections. I used a basic 40 watt iron and had no troubles. There are lots of Instructables about soldering, so I won't cover it here.

* Diagonal cutter; These are used to trim excess LED and resistor legs. I used a small precision pair, but larger ones should work. If your wire cutter has its cutting portion at the very front, you may be able to just use it.

* Wire cutter/stripper; As you might guess, this is for preparing wire to connect components on your board and likely when programming your microcontroller.

* Digital multimeter; It's pretty difficult to find out why a circuit isn't working if you can't test it with one of these.

* Microcontroller programmer; Many AVR chips can be programmed using an Arduino, but you'll have to check which yourself. In fact, you might even end up using an Arduino as your microcontroller itself. Alternatives are Microchip's PICkit for PICs and... Sorry, I'm not familiar with any other types. Instructables' fabulous community can probably help you with any other chips, though!

* Wire; Yeah, it's a material, but it isn't a "part" and it goes with the wire cutter/stripper. 22-24 AWG works well in breadboards and on the soldering perfboard, but 24 gauge wire will not stay in an Arduino's pin headers well.

* Helping hands; You'll definitely want this when soldering. It's no fun chasing your board around a table, so use this to hold it in place. Additionally, you'll need something to hold LEDs at the right angle if you want them to look uniform. This can do that for you.

* Drill and bits; Only if you want to put this project in a case. Be sure to use a hole gauge if you don't know the diameter of the parts you need to drill holes for. A file may come in handy if the holes end up with rough edges, but the part might cover them up for you.

Be sure to have lots of light when soldering, and always quadruple check your placement and rotation of parts before soldering!

Step 3: Plan!

I can't stress this enough: plan as much of your project as you can. I spent at least twice as much of my time planning where everything would go and work together than I did actually assembling it. I probably should have spent even more time planning.

Anyway, determine your limiting factors(mine was complexity) and work from there. I considered using eight LEDs with one shift register, but that layout didn't even look like a heart. So, I kept plotting points on a grid in the shape of a heart, using different amounts each time. Note that the LEDs, when placed in your perfboard, won't form the exact shape plotted out unless you put a lot of space between them, or have some rotated 90 degrees. As you can see, the LEDs on the far left and right are spaced slightly more than the rest, because they're the only ones that aren't diagonal to their neighbors.

Be sure you have enough board space to fit all of your components. This may seem obvious, but there's a lot that can be overlooked. Standard 1/4 watt resistors will cover a total of four contiguous holes, when placed flat. My board had just enough room for the LEDs, shift registers(and access to their control pins), and four holes between each shift register and their closest LED. If you wanna get crafty(and risky), you can try other layouts, or even solder the resistors vertically to save room. I wanted as little sticking up as possible, so that wasn't an option for me.

Hopefully, this schematic will do a better job at showing how things are connected than my pictures and descriptions in the following steps.

Step 4: Assembly: Shift Registers and LEDs

Most of the "Assembly" steps can be completed in some different order. This the just the order I've found easiest.

Solder in the shift registers, taking care to have them lined up as planned. I wanted the "middle" LED on each side to be lined up with the "middle" output pin on each register. This is known as "QE" or pin 4(if you don't know how to locate a numbered pin, learn now; Google can provide many answers that are better than I could explain). Also make sure there will be room for resistors between each pin and its respective LED.

Now we get to solder in the LEDs, which is a difficult part, in my opinion. Make sure each side's LEDs are in the same direction. If you're using my code, this means the anodes(positive, longer leg) will all be closer to the shift register than the middle. You could do it the other way, but my patterns are written for common-cathode, and the display will be inverted with a common-anode array. Also remember that the upper 7 LEDs will face the opposite direction to the lower 7, assuming you put the shift registers in the same places as I did.

To get them to stay uniform and upright, I did one at a time and held one leg with the helping hands while positioning the board. If you don't have access to helping hands, you could also use tape on the other side to keep it aligned while you solder. Be careful when soldering not to bump it out of alignment. This gets more difficult when more metal legs are sticking up in your way, but don't clip any yet!

Step 5: Assembly: Resistors

There's not much to say here. These will be the only things(no wires or anything) connecting our shift registers to our LEDs. Bend the leads at a distance that looks close, then push them through. On the connection side, carefully bend one lead around the anode(or cathode, if you're doing your circuit that way), parallel with the board and perpendicular with the LED's leg. It doesn't have to go all the way around, just make sure it's not touching any other pins or legs.

Push the other leg of the resistor down against the pin of the shift register you're soldering to, again taking care not to let it touch other pins. Solder both leads to the pads they come in through, then to the LED and shift register. Clip the LED's leg close to where you soldered, then trim the excess resistor leads. Repeat!

Step 6: Assembly: Unite the Cathodes!

As the title implies, this is the point where we connect all the cathodes together. Bend them over, one at a time(except for the first two, of course), and solder together. If it looks like a leg might get in the way, trim it just as much as you need to, but having extra room to solder to is nice.

Be sure not to bend too close to the solder joint, and avoid letting any contact the anodes at all costs(well, it won't be a problem until the circuit is powered; sorry for being a drama queen). We don't want shorts! Check that each LED's cathode is connected to each other's. Use a DMM's(digital multimeter) continuity mode if visibility is low. If yours doesn't have that mode, use the lowest resistance setting. Less than a few ohms is good enough to count as "continuous".

There's no need to check every pin against every other. That would be 182 checks! Just knowing that one pin is continuous with each other is good enough.

The result of this step may look ugly, but if it isn't sticking out very far, it should work fine.

Step 7: Assembly: IC Socket and Wiring

This is my least favorite step, as it makes an otherwise "pretty" board look ugly and distracting. I'd wire on the underside, but my board only has pads on one side and I don't like soldering on the same side as the component. I'll stop whining now!

First, I soldered the socket. I tried to put it where I would have plenty of room to connect to it. Down in the corner, away from the edge, turned out to fit the bill. Pictures and their annotations will do much of the explanation for the rest of this step.

Next, I connected power wires to their pins(VCC and ground) and to pins that need tied either high or low.

I then soldered in the shift register control wires. Serial clock on both registers is connected to the same pin on the microcontroller(pin 6, digital 1), and register clock on both registers is connected to the same pin(pin 7, digital 2). Serial data(pin 5, digital 0) is only connected to the data input of the first shift register, due to the way they work. When you shift more than 8 bits into a shift register, the oldest bits(that were shifted first) are output from QH'(note the single apostrophe), pin 9 on the chip. For this reason, we connect "QH'" from the first register to the serial data input of the second.

Remember when wiring that form is as important as function in this project. It may look a little silly to have wires go out of their way around the board, but that's better than covering up the LEDs.

Step 8: Assembly: the Button

You know you love the button. You know it's fun to press. Now we get to use it.

We connect its leads to ground and our microcontroller's input pin. With an ATtiny85V and the code I provide, that's pin 3, digital 4. We also have to connect our pull-up resistor from VCC to the input pin. Don't leave this resistor out or jumper it, or you'll short circuit whenever you press the button!

Step 9: Programming

This step was much of the project's working time. Lucky for you, if you use the same circuit as me, I've done the work for you. It may be horrendous for a skilled programmer to look at, but it does work. Sorry to people not using AVRs, because this code is meant for use in the Arduino IDE.

To those that want to change the patterns, pay attention to the sequenceLengths array. It should accurately represent the lengths of all other sequence arrays. If you want to add or remove any, adjust sequenceTotal to match, change sequenceLengths[6] to the correct number of patterns, and add a "case" to findAndWriteStep().

Feel free to ask if I've been unclear in my comments or above.

Step 10: Enclosure and Power

Use alligator clips from your power source to VCC and ground on the circuit to test it. Once you have it working how you want, you may decide to mount this project in an enclosure. You're on your own here, but be sure you can push your power switch through before soldering it to anything. Mine has a little bevel that can't be removed, so it must be pushed into the enclosure, whereas the push button can be pushed out from the inside. I don't yet have the proper mounting hardware, so you'll have to wait if you want to see how this looks in my enclosure.

After these potential problems are worked out, solder the negative(or ground) side of your power supply/battery holder to your circuit's ground. Solder the positive wire to your power switch's common pin(or lug). If it only has two(an SPST switch), it doesn't matter which you use, but if it has three pins/lugs(like an SPDT switch), use the middle one. Then attach a wire from the other pin(either, but not both of an SPDT switch) to VCC of the circuit. You're done!

Here's a video of mine, if you're interested. It actually changed states instantly; the "fading" in that video is a camera effect.
Update: I changed the code a bit to tweak the animations and disable the random one(though it's still there; you just have to enable it). I recorded a new video to show these changes.
Hey!!! I finally got it working !! This instructible is great, amazing idea! <br> <br>I did everything the same except I swapped out red LED's for blue and machined a special aluminum enclosure for everything. <br> <br>What you see on the right hand side of the one picture is a custom battery holder that I machined to hold 3 coin batteries which will attach to the back of the case to make it lightweight and easy to carry compared to AA's <br> <br>Also, if people have trouble programming their ATiny (this was my first time) should pm me because it took me a long time (and very frustrating) to get working correctly.
Please tell me how you got this working. I've got everything ready to test on my breadboard, but I can't get the chip to program. I'm using an arduino as the isp and I get an error on the very first line of the code. I'm new to programming these chips so I have no clue what is wrong with the code.<br> <br> AttinyLEDHeart2:1: error: redefinition of 'int dataPin'<br> AttinyLEDHeart2:1: error: 'int dataPin' previously defined here<br> AttinyLEDHeart2:2: error: redefinition of 'int clockPin'<br> AttinyLEDHeart2:2: error: 'int clockPin' previously defined here<br> AttinyLEDHeart2:3: error: redefinition of 'int registerPin'<br> AttinyLEDHeart2:3: error: 'int registerPin' previously defined here<br> AttinyLEDHeart2:4: error: redefinition of 'int buttonPin'<br> AttinyLEDHeart2:4: error: 'int buttonPin' previously defined here<br> AttinyLEDHeart2:5: error: redefinition of 'int debouncer'<br> AttinyLEDHeart2:5: error: 'int debouncer' previously defined here<br> AttinyLEDHeart2:6: error: redefinition of 'boolean buttonState'<br> AttinyLEDHeart2:6: error: 'boolean buttonState' previously defined here<br> AttinyLEDHeart2:7: error: redefinition of 'boolean oldButtonState'<br> AttinyLEDHeart2:7: error: 'boolean oldButtonState' previously defined here<br> AttinyLEDHeart2:8: error: redefinition of 'long unsigned int buttonHeld'<br> AttinyLEDHeart2:8: error: 'long unsigned int buttonHeld' previously defined here<br> AttinyLEDHeart2:9: error: redefinition of 'long unsigned int timer'<br> AttinyLEDHeart2:9: error: 'long unsigned int timer' previously defined here<br> AttinyLEDHeart2:10: error: redefinition of 'int sequenceDelay'<br> AttinyLEDHeart2:10: error: 'int sequenceDelay' previously defined here<br> AttinyLEDHeart2:11: error: redefinition of 'int sequenceNumber'<br> AttinyLEDHeart2:11: error: 'int sequenceNumber' previously defined here<br> AttinyLEDHeart2:12: error: redefinition of 'int sequenceProgress'<br> AttinyLEDHeart2:12: error: 'int sequenceProgress' previously defined here<br> AttinyLEDHeart2:13: error: redefinition of 'int sequenceTotal'<br> AttinyLEDHeart2:13: error: 'int sequenceTotal' previously defined here<br> AttinyLEDHeart2:14: error: redefinition of 'int sequenceLengths [6]'<br> AttinyLEDHeart2:14: error: 'int sequenceLengths [6]' previously defined here<br> AttinyLEDHeart2:15: error: redefinition of 'unsigned int sequenceZero [1]'<br> AttinyLEDHeart2:15: error: 'unsigned int sequenceZero [1]' previously defined here<br> AttinyLEDHeart2:16: error: redefinition of 'unsigned int sequenceOne [2]'<br> AttinyLEDHeart2:16: error: 'unsigned int sequenceOne [2]' previously defined here<br> AttinyLEDHeart2:17: error: redefinition of 'unsigned int sequenceTwo [14]'<br> AttinyLEDHeart2:17: error: 'unsigned int sequenceTwo [14]' previously defined here<br> AttinyLEDHeart2:19: error: redefinition of 'unsigned int sequenceThree [28]'<br> AttinyLEDHeart2:19: error: 'unsigned int sequenceThree [28]' previously defined here<br> AttinyLEDHeart2:23: error: redefinition of 'unsigned int sequenceFour [16]'<br> AttinyLEDHeart2:23: error: 'unsigned int sequenceFour [16]' previously defined here<br> AttinyLEDHeart2.pde: In function 'void writeStep(int)':<br> AttinyLEDHeart2:28: error: redefinition of 'void writeStep(int)'<br> AttinyLEDHeart2:28: error: 'void writeStep(int)' previously defined here<br> AttinyLEDHeart2.pde: In function 'void findAndWriteStep(int, int)':<br> AttinyLEDHeart2:36: error: redefinition of 'void findAndWriteStep(int, int)'<br> AttinyLEDHeart2:36: error: 'void findAndWriteStep(int, int)' previously defined here<br> AttinyLEDHeart2.pde: In function 'void setup()':<br> AttinyLEDHeart2:63: error: redefinition of 'void setup()'<br> AttinyLEDHeart2:63: error: 'void setup()' previously defined here<br> AttinyLEDHeart2.pde: In function 'void loop()':<br> AttinyLEDHeart2:76: error: redefinition of 'void loop()'<br> AttinyLEDHeart2:76: error: 'void loop()' previously defined here
The default Arduino ISP sketch has an error in it which results in an error every time when trying to program a Attiny. Below I have posted the corrected sketch which you should use to program the chip with. If you still having trouble, PM me your email address and I will send it to you as an attachment so you can open it directly. Best of luck. <br> <br> <br>// ArduinoISP version 04m2 <br> <br>/* <br> Copyright (c) 2008-2011 Randall Bohn <br> Copyright (c) 2009 David A. Mellis <br> Copyright (c) 2011-2012 Rowdy Dog Software <br> All rights reserved. <br> <br> Redistribution and use in source and binary forms, with or without <br> modification, are permitted provided that the following conditions are met: <br> <br> * Redistributions of source code must retain the above copyright notice, <br> this list of conditions and the following disclaimer. <br> <br> * Redistributions in binary form must reproduce the above copyright notice, <br> this list of conditions and the following disclaimer in the documentation <br> and/or other materials provided with the distribution. <br> <br> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; <br> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE <br> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE <br> ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE <br> LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR <br> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF <br> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS <br> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN <br> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) <br> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE <br> POSSIBILITY OF SUCH DAMAGE. <br> <br> http://www.opensource.org/licenses/bsd-license.php <br>*/ <br> <br>// this sketch turns the Arduino into a AVRISP <br>// using the following pins: <br>// 10: slave reset <br>// 11: MOSI <br>// 12: MISO <br>// 13: SCK <br> <br>// Put an LED (with resistor) on the following pins: <br>// 9: Heartbeat - shows the programmer is running <br>// 8: Error - Lights up if something goes wrong (use red if that makes sense) <br>// 7: Programming - In communication with the slave <br>// <br>// October 2010 by Randall Bohn <br>// - Write to EEPROM &gt; 256 bytes <br>// - Better use of LEDs: <br>// -- Flash LED_PMODE on each flash commit <br>// -- Flash LED_PMODE while writing EEPROM (both give visual feedback of writing progress) <br>// - Light LED_ERR whenever we hit a STK_NOSYNC. Turn it off when back in sync. <br>// <br>// October 2009 by David A. Mellis <br>// - Added support for the read signature command <br>// <br>// February 2009 by Randall Bohn <br>// - Added support for writing to EEPROM (what took so long?) <br>// Windows users should consider WinAVR's avrdude instead of the <br>// avrdude included with Arduino software. <br>// <br>// January 2008 by Randall Bohn <br>// - Thanks to Amplificar for helping me with the STK500 protocol <br>// - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader <br>// - The SPI functions herein were developed for the AVR910_ARD programmer <br>// - More information at http://code.google.com/p/mega-isp <br> <br>#include <br> <br>#if ARDUINO &gt;= 100 <br> #include <br>#else <br> #include <br>#endif <br> <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>//#define PROGRAMMER_BAUD_RATE 250000 <br>#define PROGRAMMER_BAUD_RATE 19200 <br> <br>#define PROGRAMMER_USE_ONE_LED 0 <br>#define PROGRAMMER_USE_OLD_LED_LAYOUT 1 <br> <br>#define PROGRAMMER_USE_FAST_SPI_CLOCK 0 <br>#define PROGRAMMER_USE_NORMAL_SPI_CLOCK 1 <br>#define PROGRAMMER_USE_SLOW_SPI_CLOCK 0 <br> <br>#define RELAY_ENABLED 0 <br>#define RELAY_SAY_HELLO 1 <br>//#define RELAY_BAUD_RATE 38400 <br>#define RELAY_BAUD_RATE 9600 <br>#define RELAY_TICK_PIN 8 <br> <br>#define EXTRA_OUTPUT_TUNING_CLOCK 0 <br> <br>#define EXTRA_OUTPUT_RECOVERY_CLOCK 0 <br> <br>#define EXTRA_OUTPUT_TUNING_PULSE 0 <br>#define EXTRA_USE_LONG_TUNING_PULSE 0 <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if EXTRA_OUTPUT_TUNING_CLOCK + EXTRA_OUTPUT_TUNING_PULSE &gt; 1 <br>#error EXTRA_OUTPUT_TUNING_CLOCK and EXTRA_OUTPUT_TUNING_PULSE are mutually exclusive. Enable only one. <br>#endif <br> <br>#if PROGRAMMER_USE_FAST_SPI_CLOCK + PROGRAMMER_USE_NORMAL_SPI_CLOCK + PROGRAMMER_USE_SLOW_SPI_CLOCK != 1 <br>#error PROGRAMMER_USE_FAST_SPI_CLOCK, PROGRAMMER_USE_NORMAL_SPI_CLOCK, and PROGRAMMER_USE_SLOW_SPI_CLOCK are mutually exclusive. Enable only one. <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if PROGRAMMER_USE_ONE_LED <br> <br>class AispLED <br>{ <br>public: <br> <br> void begin( uint8_t pin ) <br> { <br> _pin = pin; <br> pinMode( _pin, OUTPUT ); <br> _state = sLampTest; <br> _next = sHeartbeat; <br> _mode = sHeartbeat; <br> _previousTick = millis(); <br> _heartbeat = +1; <br> } <br> <br> void error( void ) <br> { <br> if ( ! ( (_state &gt;= sError0) &amp;&amp; (_state &lt;= sErrorN) ) ) <br> { <br> _state = sError; <br> update(); <br> } <br> } <br> <br> void flash( void ) <br> { <br>//rmv if ( ! ( (_state &gt;= sError0) &amp;&amp; (_state &lt;= sErrorN) ) ) <br> { <br> if ( (_state &gt;= sFlash0) &amp;&amp; (_state &lt;= sFlashN) ) <br> { <br> _next = sFlash2; <br> } <br> else <br> { <br> _state = sFlash; <br> update(); <br> } <br> } <br> } <br> <br>/* rmv <br> void heartbeat( void ) <br> { <br> _state = sHeartbeat; <br> update(); <br> } <br>*/ <br> <br> typedef enum <br> { <br> mProgrammer, mRelay <br> } <br> mode_t; <br> <br> void setMode( mode_t mode ) <br> { <br> if ( mode == mRelay ) <br> { <br> _mode = sSilent; <br> } <br> else <br> { <br> _mode = sHeartbeat; <br> } <br> } <br> <br> void update( void ) <br> { <br> state_t CurrentState; <br> tick_t currentTick; <br> tick_t delta; <br> <br> currentTick = millis(); <br> <br> do <br> { <br> CurrentState = _state; <br> <br> switch ( _state ) <br> { <br> case sFlash: <br> analogWrite( _pin, 255 ); <br> _previousTick = currentTick; <br> _state = sFlash1; <br> break; <br> <br> case sFlash1: <br> if ( currentTick - _previousTick &gt;= 50 ) <br> { <br> if ( _next != sFlash2 ) <br> { <br> _fade = 128; <br> _heartbeat = -1; <br> analogWrite( _pin, _fade ); <br> } <br> else <br> { <br> analogWrite( _pin, 0 ); <br> } <br> _previousTick = currentTick; <br> _state = _next; <br> _next = _mode; <br> } <br> break; <br> <br> case sFlash2: <br> if ( currentTick - _previousTick &gt;= 50 ) <br> { <br> analogWrite( _pin, 255 ); <br> _previousTick = currentTick; <br> _state = sFlash1; <br> } <br> break; <br> <br> /* rmv <br> case sFlash: <br> _fade = 255; <br> analogWrite( _pin, _fade ); <br> _previousTick = currentTick; <br> _state = sFlash1; <br> break; <br> <br> case sFlash1: <br> if ( currentTick - _previousTick &gt;= 8 ) <br> { <br> _fade = (31 * _fade) / 32; <br> // _fade = (63 * _fade) / 64; <br> analogWrite( _pin, _fade ); <br> if ( _fade &lt;= 192 ) <br> { <br> _state = sHeartbeat; <br> _heartbeat = -1; <br> } <br> _previousTick = currentTick; <br> } <br> break; <br> */ <br> <br> case sError: <br> analogWrite( _pin, 255 ); <br> _previousTick = currentTick; <br> _state = sError1; <br> break; <br> <br> case sError1: <br> if ( currentTick - _previousTick &gt;= 900 ) <br> { <br> analogWrite( _pin, 0 ); <br> _previousTick = currentTick; <br> _state = sError2; <br> } <br> break; <br> <br> case sError2: <br> if ( currentTick - _previousTick &gt;= 100 ) <br> { <br> analogWrite( _pin, 255 ); <br> _previousTick = currentTick; <br> _state = sError1; <br> } <br> break; <br> <br> case sHeartbeat: <br> _previousTick = currentTick; <br> _state = sHeartbeat1; <br> break; <br> <br> case sHeartbeat1: <br> if ( currentTick - _previousTick &gt;= 48 /*16*/ ) <br> { <br> if ( _fade &gt;= 48 /*64*/ ) <br> { <br> _heartbeat = -1; <br> } <br> else if ( _fade &lt;= 8 ) <br> { <br> _heartbeat = +1; <br> <br> if ( _mode == sSilent ) <br> { <br> _state = sSilent; <br> } <br> } <br> _fade = _fade + _heartbeat; <br> analogWrite( _pin, _fade ); <br> _previousTick = currentTick; <br> } <br> break; <br> <br> case sSilent: <br> analogWrite( _pin, 0 ); <br> _state = sSilent1; <br> break; <br> <br> case sSilent1: <br> if ( _mode == sHeartbeat ) <br> { <br> _state = sHeartbeat; <br> } <br> break; <br> <br> case sLampTest: <br> _fade = 0; <br> analogWrite( _pin, 255 ); <br> _previousTick = currentTick; <br> _state = sLampTest1; <br> break; <br> <br> case sLampTest1: <br> delta = currentTick - _previousTick; <br> if ( delta &gt;= 50 ) <br> { <br> ++_fade; <br> if ( _fade &lt;= 4 ) <br> { <br> analogWrite( _pin, 255 ); <br> _previousTick = currentTick; <br> } <br> else <br> { <br> _state = _mode; <br> } <br> } <br> else <br> analogWrite( _pin, 255 - (5*delta) ); <br> break; <br> } <br> } <br> while ( CurrentState != _state ); <br> } <br> <br>private: <br> <br> typedef enum <br> { <br> sFlash0, sFlash, sFlash1, sFlash2, sFlashN, <br> sError0, sError, sError1, sError2, sErrorN, <br> sHeartbeat0, sHeartbeat, sHeartbeat1, sHeartbeatN, <br> sSilent0, sSilent, sSilent1, sSilentN, <br> sLampTest, sLampTest1, <br> sFini <br> } <br> state_t; <br> <br> typedef unsigned short tick_t; <br> <br> uint8_t _pin; <br> tick_t _previousTick; <br> state_t _state; <br> state_t _next; <br> state_t _mode; <br> int16_t _fade; <br> int16_t _heartbeat; <br>}; <br> <br>AispLED TheLED; <br> <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if RELAY_ENABLED <br> <br> #if ARDUINO &gt;= 100 <br> #include <br> SoftwareSerial Relay( 12, 14 ); <br> #else <br>// #include <br>// NewSoftSerial Relay( 12, 14 ); <br> #endif <br> <br> bool HoldInResetAfterProgramming; <br> bool HeldInReset; <br> bool PreviousTick; <br> <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#define RESET SS <br> <br>#if PROGRAMMER_USE_ONE_LED <br> #define LED_PIN 5 <br>#else <br> #if PROGRAMMER_USE_OLD_LED_LAYOUT <br> #define LED_HB 9 <br> #define LED_ERR 8 <br> #define LED_PMODE 7 <br> #define PROG_FLICKER true <br> #else <br> #define LED_HB 5 <br> #define LED_ERR 6 <br> #define LED_PMODE 7 <br> #define PROG_FLICKER true <br> #endif <br>#endif <br> <br>#define HWVER 2 <br>#define SWMAJ 1 <br>#define SWMIN 18 <br> <br>// STK Definitions <br>#define STK_OK 0x10 <br>#define STK_FAILED 0x11 <br>#define STK_UNKNOWN 0x12 <br>#define STK_INSYNC 0x14 <br>#define STK_NOSYNC 0x15 <br>#define CRC_EOP 0x20 //ok it is a space... <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if ! PROGRAMMER_USE_ONE_LED <br>void pulse(int pin, int times); <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void setup() <br>{ <br> Serial.begin( PROGRAMMER_BAUD_RATE ); <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.begin( LED_PIN ); <br> #else <br> pinMode( LED_PMODE, OUTPUT ); <br> pulse( LED_PMODE, 2 ); <br> pinMode( LED_ERR, OUTPUT ); <br> pulse( LED_ERR, 2 ); <br> pinMode( LED_HB, OUTPUT ); <br> pulse( LED_HB, 2 ); <br> #endif <br> <br> #if EXTRA_OUTPUT_TUNING_CLOCK <br> start_tuning_clock(); <br> #endif <br> <br> #if EXTRA_OUTPUT_TUNING_PULSE <br> start_tuning_pulse(); <br> #endif <br> <br> #if EXTRA_OUTPUT_RECOVERY_CLOCK <br> start_recovery_clock(); <br> #endif <br> <br> #if RELAY_ENABLED <br> pinMode( RELAY_TICK_PIN, INPUT ); <br> digitalWrite( RELAY_TICK_PIN, HIGH ); <br> #endif <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>int pmode=0; <br>// address for reading and writing, set by 'U' command <br>int here; <br>uint8_t buff[256]; // global block storage <br> <br>#define beget16(addr) (*addr * 256 + *(addr+1) ) <br> <br>typedef struct param <br>{ <br> uint8_t devicecode; <br> uint8_t revision; <br> uint8_t progtype; <br> uint8_t parmode; <br> uint8_t polling; <br> uint8_t selftimed; <br> uint8_t lockbytes; <br> uint8_t fusebytes; <br> uint8_t flashpoll; <br> uint16_t eeprompoll; <br> uint16_t pagesize; <br> uint16_t eepromsize; <br> uint32_t flashsize; <br>} <br>parameter; <br> <br>parameter param; <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>static unsigned error_count; <br>static uint8_t first_mark; <br>static unsigned command_count; <br> <br>static void set_error( uint8_t _mark, uint8_t _extra ) <br>{ <br> ++error_count; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if PROGRAMMER_USE_ONE_LED <br>#else <br>// this provides a heartbeat on pin 9, so you can tell the software is running. <br>uint8_t hbval=128; <br>int8_t hbdelta=8; <br>unsigned long hbprev; <br> <br>void heartbeat() <br>{ <br> unsigned long current; <br> current = millis(); <br> if ( current - hbprev &gt;= 40 ) <br> { <br> if (hbval &gt; 192) hbdelta = -hbdelta; <br> if (hbval &lt; 32) hbdelta = -hbdelta; <br> hbval += hbdelta; <br> analogWrite(LED_HB, hbval); <br> hbprev = current; <br> } <br>//rmv delay(40); <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if RELAY_ENABLED <br>static void serial_relay_output_stuff( void ) <br>{ <br> Serial.println(); <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if RELAY_ENABLED <br>void do_serial_relay( void ) <br>{ <br> bool RelayActive; <br> bool SomethingRelayed; <br> bool ThisTick; <br> <br> Relay.begin( RELAY_BAUD_RATE ); <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.setMode( AispLED::mRelay ); <br> #endif <br> <br> #if RELAY_SAY_HELLO <br> Serial.println( &quot;Serial Relay starting...&quot; ); <br> #endif <br> <br> if ( HeldInReset ) <br> { <br> pinMode( SCK, INPUT ); <br> pinMode( RESET, INPUT ); <br> #if RELAY_SAY_HELLO <br> Serial.println( &quot;Processor released from reset.&quot; ); <br> #endif <br> HeldInReset = false; <br> } <br> <br> RelayActive = true; <br> SomethingRelayed = false; <br> <br>//rmv while( ! Serial.available() ) <br> while ( RelayActive ) <br> { <br> while ( Relay.available() ) <br> { <br> Serial.write( Relay.read() ); <br> SomethingRelayed = true; <br> } <br> <br> #if PROGRAMMER_USE_ONE_LED <br> if ( SomethingRelayed ) <br> { <br> TheLED.flash(); <br> SomethingRelayed = false; <br> } <br> #endif <br> <br> ThisTick = digitalRead( RELAY_TICK_PIN ); <br> if ( ThisTick != PreviousTick ) <br> { <br> PreviousTick = ThisTick; <br> <br> Serial.write( '\t' ); <br> Serial.print( ThisTick, DEC ); <br> Serial.write( '\t' ); <br> Serial.print( millis(), DEC ); <br> Serial.println(); <br> } <br> <br> if ( Serial.available() ) <br> { <br> unsigned long Start; <br> <br> char ch = Serial.read(); <br> <br> switch ( ch ) <br> { <br> case '@': <br> HoldInResetAfterProgramming = ! HoldInResetAfterProgramming; <br> #if RELAY_SAY_HELLO <br> Serial.print( &quot;Processor &quot; ); <br> if ( HoldInResetAfterProgramming ) <br> { <br> Serial.print( &quot;WILL&quot; ); <br> } <br> else <br> { <br> Serial.print( &quot;will NOT&quot; ); <br> } <br> Serial.println( &quot; be held in reset after programming&quot; ); <br> #endif <br> break; <br> <br> case '#': <br> pinMode( RESET, OUTPUT ); <br>/*rmv <br> // The following should not be necessary. It is kept because that's how it is done in start_pmode. <br> digitalWrite( RESET, LOW ); <br>*/ <br> Start = millis(); <br> #if RELAY_SAY_HELLO <br> Serial.println( &quot;Resetting target...&quot; ); <br> #endif <br> while ( millis() - Start &lt; 50 ); <br> pinMode( RESET, INPUT ); <br> break; <br> <br> case '?': <br> serial_relay_output_stuff(); <br> break; <br> <br> default: <br> RelayActive = false; <br> break; <br> } <br> } <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.update(); <br> #else <br> heartbeat(); <br> #endif <br> } <br> <br> while( Serial.available() ) <br> Serial.read(); <br> <br> Relay.end(); <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.setMode( AispLED::mProgrammer ); <br> #endif <br> <br> #if RELAY_SAY_HELLO <br> Serial.println( &quot;Serial Relay stopped&quot; ); <br> #endif <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if EXTRA_OUTPUT_TUNING_CLOCK <br> <br>static void start_tuning_clock( void ) <br>{ <br> // Generate a 1.0 MHz clock on OC1A (PC6, digital pin 9) <br> // Using a 1.0 MHz clock requires that the target run faster than 2.5 MHz so that the clock can reliably drive timer 0. (F_CPU / 2.5) <br> // The target decides what to do with the clock. <br> <br> // Turn the timer off while changes are made <br> TCCR1B = (0 &lt;&lt; ICNC1) | (0 &lt;&lt; ICES1) | (0 &lt;&lt; WGM13) | (0 &lt;&lt; WGM12) | (0 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (0 &lt;&lt; CS10); <br> <br> // Configure the Compare Match Output Mode and the Waveform Generation Mode <br> // COM1A1 COM1A0 = 0 1 = Toggle OC1A/OC1B on Compare Match. <br> // COM1B1 COM1B0 = 0 0 = Normal port operation, OC1B disconnected. <br> // WGM13 WGM12 WGM11 WGM10 = 0 1 0 0 = CTC OCR1A Immediate MAX <br> TCCR1A = <br> (0 &lt;&lt; COM1A1) | (1 &lt;&lt; COM1A0) <br> | <br> (0 &lt;&lt; COM1B1) | (0 &lt;&lt; COM1B0) <br> | <br> (0 &lt;&lt; WGM11) | (0 &lt;&lt; WGM10); <br> <br> TCCR1B = <br> TCCR1B <br> | <br> (0 &lt;&lt; WGM13) | (1 &lt;&lt; WGM12); <br> <br> // No interrupts <br> TIMSK1 = (0 &lt;&lt; ICIE1) | (0 &lt;&lt; OCIE1B) | (0 &lt;&lt; OCIE1A) | (0 &lt;&lt; TOIE1); <br> TIFR1 = (1 &lt;&lt; ICF1) | (1 &lt;&lt; OCF1B) | (1 &lt;&lt; OCF1A) | (1 &lt;&lt; TOV1); <br> <br> // Ensure the first pulse is correct (fix? Should this be set to TOP on the Teensy?) <br> TCNT1 = 0; <br> <br> // Frequency = F_CPU / (2 * Prescaler * (OCR + 1)) <br> // Frequency = 16000000 / (2 * 1 * (7 + 1)) <br> // Frequency = 1.0 MHz <br> OCR1A = 7; <br> <br> // Enable the output driver <br> DDRB |= (1 &lt;&lt; DDB1); <br> <br> // Start the timer <br> // CS12 CS11 CS10 = 0 0 1 = clkI/O/1 (No prescaling) <br> TCCR1B = <br> TCCR1B <br> | <br> ((0 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (1 &lt;&lt; CS10)); <br>} <br> <br>static void stop_tuning_clock( void ) <br>{ <br> // Stop the timer <br> // CS12 CS11 CS10 = 0 0 0 = No clock source (Timer/Counter stopped). <br> TCCR1B = <br> TCCR1B <br> &amp; <br> ~ ((0 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (1 &lt;&lt; CS10)); <br> <br> // Disable the output driver <br> DDRB &amp;= ~ (1 &lt;&lt; DDB1); <br>} <br> <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if EXTRA_OUTPUT_TUNING_PULSE <br>static void start_tuning_pulse( void ) <br>{ <br> // Generate a 2.000 millisecond pulse on OC1A (PC6, digital pin 9) <br> // If the target processor running at 8 MHz is perfectly tuned, TimeOnePulse returns 3200 counts (*5 = 16000 clocks) from a 2.000 millsecond pulse <br> <br> // Or <br> // Generate a 16.000 millisecond pulse on OC1A (PC6, digital pin 9) <br> // If the target processor running at 1 MHz is perfectly tuned, TimeOnePulse returns 3200 counts (*5 = 16000 clocks) from a 16.000 millsecond pulse <br> <br> // Turn the timer off while changes are made <br> TCCR1B = (0 &lt;&lt; ICNC1) | (0 &lt;&lt; ICES1) | (0 &lt;&lt; WGM13) | (0 &lt;&lt; WGM12) | (0 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (0 &lt;&lt; CS10); <br> <br> // Configure the Compare Match Output Mode and the Waveform Generation Mode <br> // COM1A1 COM1A0 = 1 0 = Clear OC1A on Compare Match, set OC1A at BOTTOM (non-inverting mode) <br> // COM1B1 COM1B0 = 0 0 = Normal port operation, OC1B disconnected. <br> // WGM13 WGM12 WGM11 WGM10 = 0 1 0 1 = Fast PWM, 8-bit 0x00FF BOTTOM TOP <br> TCCR1A = <br> (1 &lt;&lt; COM1A1) | (0 &lt;&lt; COM1A0) <br> | <br> (0 &lt;&lt; COM1B1) | (0 &lt;&lt; COM1B0) <br> | <br> (0 &lt;&lt; WGM11) | (1 &lt;&lt; WGM10); <br> <br> TCCR1B = <br> TCCR1B <br> | <br> (0 &lt;&lt; WGM13) | (1 &lt;&lt; WGM12); <br> <br> // No interrupts <br> TIMSK1 = (0 &lt;&lt; ICIE1) | (0 &lt;&lt; OCIE1B) | (0 &lt;&lt; OCIE1A) | (0 &lt;&lt; TOIE1); <br> TIFR1 = (0 &lt;&lt; ICF1) | (0 &lt;&lt; OCF1B) | (0 &lt;&lt; OCF1A) | (0 &lt;&lt; TOV1); <br> <br> // Ensure the first pulse is the correct width (fix? Should this be set to TOP on the Teensy?) <br> TCNT1 = 0; <br> <br> #if EXTRA_USE_LONG_TUNING_PULSE <br> // (Prescaler / F_CPU) * (OCR + 1) <br> // (1024 / 16000000) * (249 + 1) <br> // 16 milliseconds <br> OCR1A = 249; <br> #else <br> // (Prescaler / F_CPU) * (OCR + 1) <br> // (256 / 16000000) * (124 + 1) <br> // 2 milliseconds <br> OCR1A = 124; <br> #endif <br> <br> // Enable the output driver <br>//rmv DDRB |= (1 &lt;&lt; PB1); <br> DDRB |= (1 &lt;&lt; DDB1); <br> <br> // Start the timer <br> #if EXTRA_USE_LONG_TUNING_PULSE <br> // CS12 CS11 CS10 = 1 0 1 = clkI/O/1024 (From prescaler) <br> TCCR1B = <br> TCCR1B <br> | <br> ((1 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (1 &lt;&lt; CS10)); <br> #else <br> // CS12 CS11 CS10 = 1 0 0 = clkI/O/256 (From prescaler) <br> TCCR1B = <br> TCCR1B <br> | <br> ((1 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (0 &lt;&lt; CS10)); <br> #endif <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if EXTRA_OUTPUT_RECOVERY_CLOCK <br>void start_recovery_clock( void ) <br>{ <br> // Generate a 1 MHz clock on OC2B (PD3, digital pin 3) <br> // The clock can be used to recover a processor that does not have an external crystal with the fuses set to use an external crystal <br> <br> // Turn the timer off while changes are made <br> TCCR2B = <br> (0 &lt;&lt; FOC2A) | (0 &lt;&lt; FOC2B) | (0 &lt;&lt; WGM22) | (0 &lt;&lt; CS22) | (0 &lt;&lt; CS21) | (0 &lt;&lt; CS20); <br> <br> // Configure the Compare Match Output Mode and the Waveform Generation Mode <br> // COM2A1 COM2A0 = 0 0 = Normal port operation, OC0A disconnected. <br> // COM2B1 COM2B0 = 0 1 = Toggle OC2B on Compare Match <br> // WGM22 WGM21 WGM20 = 0 1 0 = CTC OCRA Immediate MAX <br> TCCR2A = <br> (0 &lt;&lt; COM2A1) | (0 &lt;&lt; COM2A0) <br> | <br> (0 &lt;&lt; COM2B1) | (1 &lt;&lt; COM2B0) <br> | <br> (1 &lt;&lt; WGM21) | (0 &lt;&lt; WGM20); <br> <br> TCCR2B = <br> TCCR2B <br> | <br> (0 &lt;&lt; WGM22); <br> <br> // No interrupts <br> TIMSK2 = <br> (0 &lt;&lt; OCIE2B) | (0 &lt;&lt; OCIE2A) | (0 &lt;&lt; TOIE2); <br> TIFR2 = <br> (0 &lt;&lt; OCF2B) | (0 &lt;&lt; OCF2A) | (0 &lt;&lt; TOV2); <br> <br> // Ensure the first pulse is correct (fix? Should this be set to TOP on the Teensy?) <br> TCNT2 = 0; <br> <br> // F_CPU / (2 * Prescaler * (1 + OCR)) <br> // 16000000 / (2 * 1 * (1 + 7)) <br> // 1 MHz <br> OCR2A = 7; <br> <br> // Enable the output driver <br>//rmv DDRD |= (1 &lt;&lt; PD3); <br> DDRD |= (1 &lt;&lt; DDD3); <br> <br> // Start the timer <br> // CS22 CS21 CS20 = 0 0 1 = clkT2S/(No prescaling) <br> TCCR2B = <br> TCCR2B <br> | <br> ((0 &lt;&lt; CS12) | (0 &lt;&lt; CS11) | (1 &lt;&lt; CS10)); <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>uint8_t getch() <br>{ <br> while(!Serial.available()); <br> return Serial.read(); <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void fill(int n) <br>{ <br> for (int x = 0; x &lt; n; x++) <br> { <br> buff[x] = getch(); <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if ! PROGRAMMER_USE_ONE_LED <br>#define PTIME 30 <br>void pulse(int pin, int times) <br>{ <br> do <br> { <br> digitalWrite(pin, HIGH); <br> delay(PTIME); <br> digitalWrite(pin, LOW); <br> delay(PTIME); <br> } <br> while (times--); <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if ! PROGRAMMER_USE_ONE_LED <br>void prog_lamp(int state) <br>{ <br> if (PROG_FLICKER) <br> digitalWrite(LED_PMODE, state); <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if ! PROGRAMMER_USE_SLOW_SPI_CLOCK <br> <br>void spi_init() <br>{ <br> uint8_t x; <br> <br>//SPCR = 0x53; <br> <br>#if PROGRAMMER_USE_NORMAL_SPI_CLOCK <br> // SPE: SPI Enable <br> // MSTR: Master/Slave Select <br> // SPI2X SPR1 SPR0 = 0 1 0 = SCK Frequency is fosc/64 = 250 K <br> // 250 K * 2 * 2 = 1 M <br> SPCR = (0 &lt;&lt; SPIE) | (1 &lt;&lt; SPE) | (0 &lt;&lt; DORD) | (1 &lt;&lt; MSTR) | (0 &lt;&lt; CPOL) | (0 &lt;&lt; CPHA) | (1 &lt;&lt; SPR1) | (0 &lt;&lt; SPR0); <br>#endif <br> <br>#if PROGRAMMER_USE_FAST_SPI_CLOCK <br> // SPE: SPI Enable <br> // MSTR: Master/Slave Select <br> // SPI2X SPR1 SPR0 = 1 0 1 = SCK Frequency is fosc/8 = 2 M <br> // 2 M * 2 * 2 = 8 M <br> SPCR = (0 &lt;&lt; SPIE) | (1 &lt;&lt; SPE) | (0 &lt;&lt; DORD) | (1 &lt;&lt; MSTR) | (0 &lt;&lt; CPOL) | (0 &lt;&lt; CPHA) | (0 &lt;&lt; SPR1) | (1 &lt;&lt; SPR0); <br> SPSR = SPSR | (1 &lt;&lt; SPI2X); <br>#endif <br> <br> x=SPSR; <br> x=SPDR; <br>} <br> <br>#else <br>void spi_init() <br>{ <br>} <br>#endif <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#if ! PROGRAMMER_USE_SLOW_SPI_CLOCK <br> <br>void spi_wait() <br>{ <br> do { <br> } <br> while (!(SPSR &amp; (1 &lt;&lt; SPIF))); <br>} <br> <br>uint8_t spi_send(uint8_t b) <br>{ <br> uint8_t reply; <br> SPDR=b; <br> spi_wait(); <br> reply = SPDR; <br> return reply; <br>} <br> <br>#else <br> <br>uint8_t spi_send(uint8_t b) <br>{ <br> uint8_t rv; <br> <br> rv = 0; <br> <br> for ( char i=7; i &gt;= 0; --i ) <br> { <br> rv = rv &lt;&lt; 1; <br> <br> if ( b &amp; 0x80 ) <br> { <br> digitalWrite( MOSI, HIGH ); <br> } <br> else <br> { <br> digitalWrite( MOSI, LOW ); <br> } <br> <br> // (1 / ((128000 / 2) / 2)) * 1000 * 1000 = 31.25 <br> digitalWrite( SCK, HIGH ); <br> delayMicroseconds( 32 ); <br> <br> if ( digitalRead( MISO ) ) <br> { <br> rv = rv | 0x01; <br> } <br> <br> digitalWrite( SCK, LOW ); <br> delayMicroseconds( 32 ); <br> <br> b = b &lt;&lt; 1; <br> } <br> <br> return( rv ); <br>} <br> <br>#endif <br> <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) <br>{ <br> uint8_t n; <br> spi_send(a); <br> n=spi_send(b); <br> //if (n != a) error_count = -1; <br> n=spi_send(c); <br> return spi_send(d); <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void empty_reply() <br>{ <br> if (CRC_EOP == getch()) <br> { <br> Serial.print((char)STK_INSYNC); <br> Serial.print((char)STK_OK); <br> } <br> else <br> { <br> set_error( 1, 0 ); <br> Serial.print((char)STK_NOSYNC); <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void breply(uint8_t b) <br>{ <br> if (CRC_EOP == getch()) <br> { <br> Serial.print((char)STK_INSYNC); <br> Serial.print((char)b); <br> Serial.print((char)STK_OK); <br> } <br> else <br> { <br> set_error( 2, 0 ); <br> Serial.print((char)STK_NOSYNC); <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void get_version(uint8_t c) <br>{ <br> switch(c) <br> { <br> case 0x80: <br> breply(HWVER); <br> break; <br> case 0x81: <br> breply(SWMAJ); <br> break; <br> case 0x82: <br> breply(SWMIN); <br> break; <br> case 0x93: <br> breply('S'); // serial programmer <br> break; <br> default: <br> breply(0); <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void set_parameters() <br>{ <br> // call this after reading paramter packet into buff[] <br> param.devicecode = buff[0]; <br> param.revision = buff[1]; <br> param.progtype = buff[2]; <br> param.parmode = buff[3]; <br> param.polling = buff[4]; <br> param.selftimed = buff[5]; <br> param.lockbytes = buff[6]; <br> param.fusebytes = buff[7]; <br> param.flashpoll = buff[8]; <br> // ignore buff[9] (= buff[8]) <br> // following are 16 bits (big endian) <br> param.eeprompoll = beget16(&amp;buff[10]); <br> param.pagesize = beget16(&amp;buff[12]); <br> param.eepromsize = beget16(&amp;buff[14]); <br> <br> // 32 bits flashsize (big endian) <br> param.flashsize = <br> buff[16] * 0x01000000 <br> + buff[17] * 0x00010000 <br> + buff[18] * 0x00000100 <br> + buff[19]; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void start_pmode() <br>{ <br> // Tuning clock *must* be turned off before SCK is turned into an output because T0 on the 8-pin processors is also SCK <br> #if EXTRA_OUTPUT_TUNING_CLOCK <br> stop_tuning_clock(); <br> #endif <br> <br> spi_init(); <br> <br>/* rmv <br> // fix: Drive RESET LOW before mucking with SCK? <br> // http://code.google.com/p/mega-isp/issues/detail?id=22 <br> <br> // following delays may not work on all targets... <br> pinMode( RESET, OUTPUT ); <br> digitalWrite( RESET, HIGH ); <br> pinMode( SCK, OUTPUT ); <br> digitalWrite( SCK, LOW ); <br> delay( 50 ); <br> digitalWrite( RESET, LOW ); <br> delay( 50 ); <br>*/ <br> pinMode( RESET, OUTPUT ); <br> digitalWrite( RESET, LOW ); <br> <br> pinMode( SCK, OUTPUT ); <br> digitalWrite( SCK, LOW ); <br> <br> delay( 50 ); <br> <br> pinMode( MISO, INPUT ); <br> pinMode( MOSI, OUTPUT ); <br> <br> // fix: Check the value returned from the processor. Ensure it entered programming mode. <br> spi_transaction( 0xAC, 0x53, 0x00, 0x00 ); <br> <br> pmode = 1; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void end_pmode() <br>{ <br> pinMode( MISO, INPUT ); <br> pinMode( MOSI, INPUT ); <br> <br> #if ! PROGRAMMER_USE_SLOW_SPI_CLOCK <br> SPCR &amp;= ~ (1 &lt;&lt; SPE); <br> #endif <br> <br> #if RELAY_ENABLED <br> if ( HoldInResetAfterProgramming ) <br> { <br> HeldInReset = true; <br> } <br> else <br> { <br> pinMode( SCK, INPUT ); <br> pinMode( RESET, INPUT ); <br> HeldInReset = false; <br> } <br> #else <br> pinMode( SCK, INPUT ); <br> pinMode( RESET, INPUT ); <br> #endif <br> <br> pmode = 0; <br> <br> // Don't turn the tuning clock on until after SCK is turned into an input because T0 on the 8-pin processors is also SCK <br> #if EXTRA_OUTPUT_TUNING_CLOCK <br> start_tuning_clock(); <br> #endif <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void universal() <br>{ <br>//rmv int w; <br> uint8_t ch; <br> <br> fill(4); <br> ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]); <br> breply(ch); <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void flash(uint8_t hilo, int addr, uint8_t data) <br>{ <br> spi_transaction(0x40+8*hilo, <br> addr&gt;&gt;8 &amp; 0xFF, <br> addr &amp; 0xFF, <br> data); <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void commit(int addr) <br>{ <br>/* rmv <br> static bool JustOnce = true; <br>*/ <br> #if PROGRAMMER_USE_ONE_LED <br> uint8_t RdyBsy; <br> #endif <br> <br>/* rmv <br> if ( JustOnce ) <br> { <br> JustOnce = false; <br> pinMode( 3, OUTPUT ); <br> digitalWrite( 3, HIGH ); <br> } <br>*/ <br> <br> #if PROGRAMMER_USE_ONE_LED <br> #else <br> if (PROG_FLICKER) prog_lamp(LOW); <br> #endif <br> <br> spi_transaction( 0x4C, (addr &gt;&gt; 8) &amp; 0xFF, addr &amp; 0xFF, 0 ); <br> <br>/* rmv <br> RdyBsy = spi_transaction( 0xF0, 0x00, 0x00, 0x00 ); <br> <br> if ( (RdyBsy &amp; 0x01) != 0x01 ) <br> { <br> digitalWrite( 3, LOW ); <br> } <br>*/ <br> <br> #if PROGRAMMER_USE_ONE_LED <br>/* <br> delay( 30 ); <br>*/ <br> { <br> TheLED.flash(); <br> unsigned long Start; <br> Start = millis(); <br> while ( millis() - Start &lt; 30 ) <br> { <br> TheLED.update(); <br> if ( param.polling ) <br> { <br> RdyBsy = spi_transaction( 0xF0, 0x00, 0x00, 0x00 ); <br> if ( (RdyBsy &amp; 0x01) == 0x00 ) <br> break; <br> } <br> } <br> } <br> #else <br> if (PROG_FLICKER) <br> { <br> delay(PTIME); <br> prog_lamp(HIGH); <br> } <br> #endif <br> <br>/* rmv <br> RdyBsy = spi_transaction( 0xF0, 0x00, 0x00, 0x00 ); <br> <br> if ( (RdyBsy &amp; 0x01) == 0x01 ) <br> { <br> digitalWrite( 3, LOW ); <br> } <br>*/ <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>//#define _current_page(x) (here &amp; 0xFFFFE0) <br>int current_page(int addr) <br>{ <br> if (param.pagesize == 32) return here &amp; 0xFFFFFFF0; <br> if (param.pagesize == 64) return here &amp; 0xFFFFFFE0; <br> if (param.pagesize == 128) return here &amp; 0xFFFFFFC0; <br> if (param.pagesize == 256) return here &amp; 0xFFFFFF80; <br> return here; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>uint8_t write_flash_pages(int length) <br>{ <br> int x = 0; <br> int page = current_page(here); <br> while (x &lt; length) <br> { <br> if (page != current_page(here)) <br> { <br> commit(page); <br> page = current_page(here); <br> } <br> flash(LOW, here, buff[x++]); <br> flash(HIGH, here, buff[x++]); <br> here++; <br> } <br> <br> commit(page); <br> <br> return STK_OK; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void write_flash(int length) <br>{ <br> fill(length); <br> if (CRC_EOP == getch()) <br> { <br> Serial.print((char) STK_INSYNC); <br> Serial.print((char) write_flash_pages(length)); <br> } <br> else <br> { <br> set_error( 3, 0 ); <br> Serial.print((char) STK_NOSYNC); <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>// write (length) bytes, (start) is a byte address <br>uint8_t write_eeprom_chunk(int start, int length) <br>{ <br> // this writes byte-by-byte, <br> // page writing may be faster (4 bytes at a time) <br> fill(length); <br> <br> #if PROGRAMMER_USE_ONE_LED <br> #else <br> prog_lamp(LOW); <br> #endif <br> <br> for (int x = 0; x &lt; length; x++) <br> { <br> int addr = start+x; <br> spi_transaction(0xC0, (addr&gt;&gt;8) &amp; 0xFF, addr &amp; 0xFF, buff[x]); <br> delay(45); <br> } <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.flash(); <br> #else <br> prog_lamp(HIGH); <br> #endif <br> <br> return STK_OK; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>#define EECHUNK (32) <br> <br>uint8_t write_eeprom(int length) <br>{ <br> // here is a word address, get the byte address <br> int start = here * 2; <br> int remaining = length; <br> if (length &gt; param.eepromsize) <br> { <br> set_error( 4, 0 ); <br> return STK_FAILED; <br> } <br> while (remaining &gt; EECHUNK) <br> { <br> write_eeprom_chunk(start, EECHUNK); <br> start += EECHUNK; <br> remaining -= EECHUNK; <br> } <br> write_eeprom_chunk(start, remaining); <br> <br> return STK_OK; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void program_page() <br>{ <br> char result = (char) STK_FAILED; <br> int length; <br> char memtype; <br> <br> length = 256 * getch(); <br> length = length | getch(); <br> memtype = getch(); <br> <br> // flash memory @here, (length) bytes <br> if (memtype == 'F') <br> { <br> write_flash(length); <br> return; <br> } <br> if (memtype == 'E') <br> { <br> result = (char)write_eeprom(length); <br> if (CRC_EOP == getch()) <br> { <br> Serial.print((char) STK_INSYNC); <br> Serial.print(result); <br> } <br> else <br> { <br> set_error( 5, 0 ); <br> Serial.print((char) STK_NOSYNC); <br> } <br> return; <br> } <br> Serial.print((char)STK_FAILED); <br> return; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>uint8_t flash_read(uint8_t hilo, int addr) <br>{ <br> return spi_transaction(0x20 + hilo * 8, <br> (addr &gt;&gt; 8) &amp; 0xFF, <br> addr &amp; 0xFF, <br> 0); <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>char flash_read_page(int length) <br>{ <br> for (int x = 0; x &lt; length; x+=2) <br> { <br> uint8_t low = flash_read(LOW, here); <br> Serial.print((char) low); <br> uint8_t high = flash_read(HIGH, here); <br> Serial.print((char) high); <br> here++; <br> } <br> return STK_OK; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>char eeprom_read_page(int length) <br>{ <br> // here again we have a word address <br> int start = here * 2; <br> for (int x = 0; x &lt; length; x++) <br> { <br> int addr = start + x; <br> uint8_t ee = spi_transaction(0xA0, (addr &gt;&gt; 8) &amp; 0xFF, addr &amp; 0xFF, 0xFF); <br> Serial.print((char) ee); <br> } <br> return STK_OK; <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void read_page() <br>{ <br> char result = (char)STK_FAILED; <br> int length; <br> char memtype; <br> <br> length = 256 * getch(); <br> length = length | getch(); <br> memtype = getch(); <br> <br> if (CRC_EOP != getch()) <br> { <br> set_error( 6, 0 ); <br> Serial.print((char) STK_NOSYNC); <br> return; <br> } <br> Serial.print((char) STK_INSYNC); <br> if (memtype == 'F') result = flash_read_page(length); <br> if (memtype == 'E') result = eeprom_read_page(length); <br> Serial.print(result); <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.flash(); <br> #endif <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void read_signature() <br>{ <br> if (CRC_EOP != getch()) <br> { <br> set_error( 7, 0 ); <br> Serial.print((char) STK_NOSYNC); <br> return; <br> } <br> Serial.print((char) STK_INSYNC); <br> uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00); <br> Serial.print((char) high); <br> uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00); <br> Serial.print((char) middle); <br> uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00); <br> Serial.print((char) low); <br> Serial.print((char) STK_OK); <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void avrisp( void ) <br>{ <br> uint8_t data, low, high; <br> uint8_t ch = getch(); <br> <br>#if RELAY_ENABLED <br> if ( (ch == '!') &amp;&amp; ! pmode ) <br> { <br> do_serial_relay(); <br> } <br> else <br>#endif <br> { <br> switch ( ch ) <br> { <br> case '0': // signon <br> ++command_count; <br> error_count = 0; <br> first_mark = 0; <br> empty_reply(); <br> break; <br> <br> case '1': <br> ++command_count; <br> if ( getch() == CRC_EOP ) <br> { <br> Serial.print( (char) STK_INSYNC ); <br> Serial.print( &quot;AVR ISP&quot; ); <br> Serial.print( (char) STK_OK ); <br> } <br> break; <br> <br> case 'A': <br> ++command_count; <br> get_version( getch() ); <br> break; <br> <br> case 'B': <br> ++command_count; <br> fill(20); <br> set_parameters(); <br> empty_reply(); <br> break; <br> <br> case 'E': // extended parameters - ignore for now <br> ++command_count; <br> fill(5); <br> empty_reply(); <br> break; <br> <br> case 'P': <br> ++command_count; <br> start_pmode(); <br> empty_reply(); <br> break; <br> <br> case 'U': // set address (word) <br> ++command_count; <br> here = getch(); <br> here = here | (256 * getch()); <br> empty_reply(); <br> break; <br> <br> case 0x60: //STK_PROG_FLASH <br> ++command_count; <br> low = getch(); <br> high = getch(); <br> empty_reply(); <br> break; <br> <br> case 0x61: //STK_PROG_DATA <br> ++command_count; <br> data = getch(); <br> empty_reply(); <br> break; <br> <br> case 0x64: //STK_PROG_PAGE 'd' <br> ++command_count; <br> program_page(); <br> break; <br> <br> case 0x74: //STK_READ_PAGE 't' <br> ++command_count; <br> read_page(); <br> break; <br> <br> case 'V': //0x56 <br> ++command_count; <br> universal(); <br> break; <br> <br> case 'Q': //0x51 <br> ++command_count; <br> error_count = 0; <br> first_mark = 0; <br> end_pmode(); <br> empty_reply(); <br> break; <br> <br> case 0x75: //STK_READ_SIGN 'u' <br> ++command_count; <br> read_signature(); <br> break; <br> <br> // expecting a command, not CRC_EOP <br> // this is how we can get back in sync <br> case CRC_EOP: <br> set_error( 8, 0 ); <br> Serial.print( (char)STK_NOSYNC ); <br> break; <br> <br> // anything else we will return STK_UNKNOWN <br> default: <br> set_error( 9, ch ); <br> if ( CRC_EOP == getch() ) <br> Serial.print( (char)STK_UNKNOWN ); <br> else <br> Serial.print( (char)STK_NOSYNC ); <br> } <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br>void loop( void ) <br>{ <br> #if PROGRAMMER_USE_ONE_LED <br> #else <br> if ( pmode ) digitalWrite( LED_PMODE, HIGH ); <br> else digitalWrite( LED_PMODE, LOW ); <br> #endif <br> <br> #if PROGRAMMER_USE_ONE_LED <br> if ( error_count ) TheLED.error(); <br> #else <br> // is there an error? <br> if (error_count) digitalWrite( LED_ERR, HIGH ); <br> else digitalWrite( LED_ERR, LOW ); <br> #endif <br> <br> #if PROGRAMMER_USE_ONE_LED <br> TheLED.update(); <br> #else <br> heartbeat(); <br> #endif <br> <br> if ( Serial.available() ) <br> { <br> avrisp(); <br> } <br>} <br> <br>/*----------------------------------------------------------------------------*/ <br> <br> <br>
It's amazing to see what you've done with it! Coin cell batteries are a nice adaptation, and that enclosure looks very nice. <br> <br>What did you end up doing to get the programming to work?
well it turns out with Arduino 0.22 I couldn't get the boot loader to upload correctly to 8 MHz which is what caused the program to act funny. Then with Arduino 1.0 the default ISP sketch is not compatible with the ATiny series so after lots of searching on the internet, I found a guy on a forum that had made an updated version which corrected the problem and then after downloading and using that new sketch. I finally had a working ATiny.
<p>Love this instructables! When i saw it, I immediately started to gather up the components to do it! I've changed a few things, because i wanted it to fit into a box that i had, taking just 100x100mm. </p><p>I added 2 switches: the main switch and one that will be on when the lid of the case is opened. To make it fit i made 2 separeted board: one with the led and the other one with the &quot;brain&quot; components, and connected them via ribbon cable and connectors. So there are three levels in the box, from the bottom: battery pack, &quot;brain&quot; board, led board!</p><p>Initally i thought of making a PCB for the &quot;brain&quot; components (if anyones wants the eagle file, i can give it), but i screwed up the etching part so i went back to the prefbord. I added a lot more transitions too!</p><p>I know, the wiring is very messy, but this is my first project, i'm kinda new to electronics so...be gentle ahah</p><p>I even thought of using 16bit shift registers and two color leds to make it more intresting, but that's for another project ahah</p><p>Anyway, keep up the good work, and thanks for this amazing instructables!</p>
I'm sorry, but how can i program the shifter?<p>I really need arduino? :S i can't find anything on google to help me...<br>Waiting reply, thanks</p>
<p>I'm sorry, but how can i program the shifter?</p><p>I really need arduino? :S i can't find anything on google to help me...<br>Waiting reply, thanks</p>
It looks like you know a lot bout the Shift registers so I have a question can one send to a 3rd register by putting <<16 at the end instead of the <<8?
They sure can! You can daisy chain quite a number of these together the same way as the first two, just make sure to shift enough data through to fill all the registers. :)
Very well organized...great work!
Read about charlieplexing ( https://www.instructables.com/id/Creating-a-charlieplexed-LED-grid-to-run-on-ATTiny/?ALLSTEPS ) <br>and you might save a lot of hardware ;-)
Hello, me again, looks like I have everything working :) except the ATiny :( do you have any ideas as to why I might get this erorr when other sketches upload and run just fine on the ATiny except the animatedheart file. I have tried both the original and v2, both have the same result.<br><br>Binary sketch size: 2318 bytes (of a 8192 byte maximum)<br>avrdude: please define PAGEL and BS2 signals in the configuration file for part ATtiny85<br>avrdude: please define PAGEL and BS2 signals in the configuration file for part ATtiny85<br><br>Thanks for all the help
Hm... Have you tried popping the ATtiny into the circuit and trying it even after the errors? I recall seeing that from time to time and just ignoring it.<br> <br> I assume you're using the Arduino ISP. I followed <a href="http://hlt.media.mit.edu/?p=1229" rel="nofollow">this guide</a>(specifically the .zip file linked to on that site) to set that up, and it's been working well for me.&nbsp;
ops I should included this earlier but yes, I did try that and this is how the circuit behaves.<br><br>Connect power supply, nothing happens.<br>press button and all led's light up,<br>let go of button, all led's go out,<br><br>It won't cycle through any of the programmed functions with the button and the led's only light up while the button is pressed. I also noticed that the ATiny heats up quite a bit while the power is connected. I'm not sure if this is normal for it but I checked the circuit about 5 times for shorts and incorrect wiring but couldn't find anything.
The ATtiny shouldn't be much hotter than room temperature. Can you confirm that the button isn't connected to the LEDs or shift registers in any way, and that the LEDs aren't connected to the ATtiny?<br> <br> What values of resistors are you using on the button and on the LEDs?<br> <br> I'm not sure what's causing the behavior, but I did encounter something similar while I was designing mine. I'll try to remember what I did.
I followed your instructible to the letter, except I did swap out the leds, resistors, and applied voltage. I instead used blue led's from which I calculated the resistors that I would need to properly power the led's with a 4.5v power supply so I bought 226 OHM 1/4W 1% METAL FILM . <br><br>The configuration of the button as it sits now is, one lead goes to ground, the other to pin3 of the ATiny, also connected to pin3 is the 47k ohm resistor from which the other lead goes to V+.
how can i use the z 80
I've never used a Z80 processor, so you'll have to program and alter the schematic/layout yourself. If you're new to Z80 programming, <a href="http://z80.info/" rel="nofollow">this website</a> may be able to help. Good luck!
This is Amazing, Think I'm going to adapt this to make a nerdy christmas card for my girlfriend!..
Awesome, let me know how it turns out! (:
This is a great instructable. It's well documented. Thanks and keep up the good work.
Thank you; I tried hard! I'll be sure to write-up other things I make.

About This Instructable




More by LexanPanda:Animated LED Heart 
Add instructable to: