The best example I can think of is the "Peggy," A Light Emitting Pegboard Display. It is a 25x25 LED matrix display driven by an ATmega168 (which is pin compatible with the ATmega328)
The wiki page has a lot of good information. Including a detailed schematic.
There are few things to notice in their layout.
For one, they use a row common anode setup. That is the current source is on the row, and sink on the column. You have yours in row common cathode. There is nothing inherently right or wrong with either layout. Just something to keep in mind when designing your circuit. If using discrete leds, it just means flipping the led connections. If using a prebuilt LED matrix, it is something important to know. (I'll assume you can easily swap the order to match the peggy schematic. If not, just swap column for row in your head)
They use 74HC154 4-16 decoder/demux chips for row select. Since you only need 10 rows (or cols) you can get away with just one. Of course, there is the issue of current. In your case, at 10 x 30mA = 300mA minimum. To solve that problem they used 2STX2220 PNP transistors which will be able to source up to 1.5A per row. A bit over kill in your case. Since you will just use these as row select switches, just about any other pnp transistor that can source your max current should work just as well. Take a look at Transistor Circuits to figure out what resistor values you'll need for full on/off operations.
On the Peggy board, for the column sink driver they use an STP16DP05. But I have found these difficult to find and expensive. There are many other alternatives like the TLC5916 These use a serial input, and can be easily cascaded. If not, a digikey of mouser search for led sink driver will yield many results.
Alternatively, since you already have ULN2803 arrays, you could use two of these with a single current limit resistor per column. That's a lot of pins, so you'll have to get creative, but it could work for the column sink as well.
Avago published a nice application note titled "Introduction to Driving LED Matrices". It covers this and a few other things.
int
can only be 0-255
That's not correct. In the C
programming language, an int
is always at least 16 bits wide, even on 8-bit micros. A char
is 8 bits wide.
But when using inttypes.h
, I strongly recommend using the explicit types like uint8_t
,int16_t
or uint32_t
.
Your real error is using _delay_ms()
with a variable parameter. This is not allowed, as it is a macro involving floating point calculations - at least in avr gcc. You are supposed to use something like this:
void DelayMs(int delay) {
while(delay--) _delay_ms(1);
}
Best Answer
The "Alternate Port Functions" subsection of the "I/O-Ports" section of the datasheet describes exactly how each pin will behave given the peripherals enabled. In the case of SPI, only either MISO (master) or the other three pins (slave) are forced to a specific direction (input in both cases); the other pins can have their direction configured to either conform to SPI or not as required/desired.
Note that
DDRx
,PORTx
, andPINx
can always be read from and written to regardless of the current functions of the corresponding pins, even if such an action does not make sense given their configuration.