Applications => Circular led
Diese Seite in Deutsch:
Circular LED with ATmega324PA
32 red LEDs mounted in a circle with a diameter of 75 mm. Each diode
has a resistor and is connected to one of the 32 port pins of an
ATmega324PA. Each single LED can be switched on and off.
This small device can be used for two different applications:
Many different variations are possible:
- as programmable light band in a circle: starting from the left side,
one, two, three or four LEDs move either clock-wise or counter-clock,
steps, speed and direction can be programmed into a more or less large
table and repeat endless,
- as clock: starting with the upper LED and then clock-wise seconds,
minutes and hours are displayed and advanced. The minutes blink in
slow motion, the hours even slower. The seconds start with LED 1 and
advance very fast until their current value is reached.
- Low-current LEDs reduce the supply current substantially, so the
device can be supplied from a battery,
- with a small power supply device up to 10 or, with low-current LEDs,
even more LEDs can be switched on simultanously,
- the assembler source code is freely available and can be modified.
All drawings of this project can be downloaded as LibreOffice draw file
here (including the PCB layout and
the component placement drawing), all flow diagrams are as LibreOffice
draw file here, all calculation
tables are as LibreOffice Calc file
The hardware for both applications is nearly identical. When applied
as clock, an additional crystal and two ceramic capacitors are
This here is the boring schematic of the circular LED. The connections
of the LEDs with the controller pins requires some attention in the
software section, but eases the PCB design: the bits of the three
ports C, D and B are in a different direction than that of port A.
The 6-pin IDC plug is necessary only if you either want to program
the controller on the board or if you want to supply the device via
the standard connector.
If you want more than ten of the 32 LEDs on simultanously, you can use
low-current LEDs, e.g. for 2 mA, and increases the resistors (by default
82Ω), e.g. to 560Ω. You can then switch as many LEDs on as
you want, without risking exceeding the current limits of 200 mA
of the controller.
The same can be done when supplying the device from a battery.
The clock uses the same hardware, but the crystal and the two
ceramic capacitors of 22 pF hav to be added like shown in grey
in the schematic. The clock uses the crystal to be more exact than
with the internal RC oscillator.
By default I used a crystal with 2.097152 MHz, to which the
software is also adapted. This crystal is suitable for a 16-bit TC
as well as for an 8-Bit-TC. The software uses a 16-bit TC.
The picture shows for all crystals on the market, if those are
suitable for this application. As can be seen, the 16-bit TC version
works with more crystals than the 8-bit version. Please note that
crystals above 10 MHz work only with 5 V operating
voltage. But such high frequencies are not necessary for this
application. The device and the software even work at frequensies
such as 32.768 kHz. But, in that case, make sure that your
programming adapter allows clock frequencies below 8 kHz,
if you use such a low-frequency-crystal.
For the 8-bit-TC, higher frequency crystals use additional
clocking with CLKPR. As can be seen, no crystals, that require
additional CLKPR-dividing are suitable with an 8-bit-TC.
If you want to use a different crystal: the calculation sheet
"clockxtals" in the LibreOffice-Calc-file
here provides the
opportunity to check its suitability. Those who really
want to use a crystal above 4.5 MHz, can check if
additionally using CLKPR as clock prescaler can probably offer
an additional suitability case.
With the drop-down-field in cell B3 you can select one of the
listed crystals. If that crystal fits the 8-bit- or the 16-bit-TC,
prescaler and CTC-divider are provided as constants for export
to the source code. Simply select the constants lines, press
Ctrl-C to copy these lines to the clip board, then mark the
respective source code lines and press Ctrl-V to overwrite
those lines in the source code. If you assemble that, you can
program the controller with that changed clock frequency.
This table shows the LED currents for 5-mm-LEDs under different
operating voltages and with different resistors. Listed are
operating voltages between 3.0 V (two AA- or AAA-battery
types), 3.3 V (from a power supply over ISP6 or a wall
plug supply), 3.6 V (from two AA- or AAA-types rechargeable
batteries), 4.5 V (three AA- or AAA-type batteries) and
4.8 V (four AA- or AAA-type rechargeable batteries).
Additionally the upper tolerance voltage of a 5 V
power supply is listed.
Calculation of the currents is not that simple because
so, cannot be calculated with a simple linear function. Therefore
the calculation in the spreadsheet "LED-Currents" uses
10 approximations per voltage/resistor. As can be seen from the
sheet that the approximations for the 47Ω, and in part also
for 82Ω, are not approaching a useful final value. Those
values are not exact, but the others are.
- both, the LED voltage (with an exponential function), and
- the port-pin's VOL voltage are current-dependant
(with a linear function),
With resistors from 82Ω and higher the complete range of
operating voltages produces acceptable currents. But e aware that
currents above 20 mA through the SCK/MOSI/MISO pins can
conflict with the ISP interface, if your programmer is not fit
for such currents. And be aware that for all LEDs that are switched
on simultanously a limit of 200 mA can be driven by the
Background in read signals currents below 5 mA, for which
only low-current-high-efficiency LEDs are suitable.
On my real object, equipped with 82Ω and at 3.125 V,
I measured a current of 10,6 mA, so the currents in the
table are a little bit too low.
Here the same has been calculated for 3-mm-LEDs and for 2 mA
nominal current: as the forward voltages of such LEDs are smaller,
the currents are higher than for the standard-5-mm-LEDs. So the
resistors can be larger.
The wall plug power supply is provided in two flavours: to the left
a schematic for a maximum of four LEDs on simultanously, below
for 200 mA as maximum permissible current from the ATmega324PA
and for more than four LEDs on.
The smaller one can drive up to 80 mA LED current. The controller's
current contribution is only 0.5 mA, so forget this.
This is the larger version. The 200 mA are sufficient for
more than ten LEDs at 20 mA each or for all 32 LEDs when
low-current-LED-types and larger resistors are used (max.
6.25 mA per LED).
This is the 200-mA-power-supply on a small raster board.
For three applications (light band and clock in a circle, rectangular and
a mimimal space version) PCB's has been designed, because mounting that
all on a raster board is not exact enough in respect to mechanical aestetics.
3.1.1 Circle-type PCB
This is the design for the PCB in a 80-by-80 mm format in .gif
format. The PCB is single-sided.
Those who need it with enhanced resolution, can right-click on the
drawing, select "Save target as" and save the file in enhanced
resolution. Or you can use the LibreOffice-Draw file and produce a
higher-resolution copy as gif- or png-file. Print this enlarged
drawing to scale (e.g. with IrfanView).
3.1.2 Component placement circle type on the PCB
That are the components and how to place them on the PCB. All
drillings are 0.8 mm, excluding the four holes for the
screws (2.5 or 3 mm) as well as the six holes for the IDC
plug and the two holes for the power input (1.0 mm).
Those who want to program the controller via the ISP6-plug
have to add three enameled copper wires for SCK, MISO
and MOSI manually from the IDC socket to the controller.
Who does not need the ISP plug, neither for programming nor
as power supply plug, can leave it aside.
If you do not need the clock feature, you can leave the
crystal and the two 22-pF-capacitors out. In this case the
controller runs with its internal RC oscillator and at
1 MHz clock. This is also the basis for the software.
3.1.3 Rectangular PCB
This is a rectangular version with the same PCB size.
Those who want it more squared than cuircular use this layout.
No component placement drawing here, it is nearly the same.
Right-click and use "Save target as" to have the drawing
in a higher-resolution version.
The software works fine, the LED numbering starts in the middle
of the left edge.
3.1.4 Minmal size PCB version
This version reduces the PCB size to a minimum.
3.1.5 Minimum size PCB
That PCB places the 32 LEDs as near as possible to the controller.
It has a size of 65x50 mm. If you right-click on the PCB picture
and "Save target as", you'll get the enlarged drawing.
Components such as the ISP6 plug, the operating voltage plug and the
crystal are placed to different locations.
3.1.6 Component placement on the mimimum size PCB
The most relevant change compared to the circled version is that
the resistors are mounted vertically. That reduces the size of the
PCB substantially. No crystal is foreseen here. One bridge has to
be soldered. And, if you plan to program the controller via ISP6,
the MOSI pin has to be connected manually.
This is a minimum size version with 32 pieces of 2mA-3mm-LEDs and
470Ω, preferably for battery operation. The 4-Led-power-supply
version is sufficient, if your software does not switch on more
than ten LEDs at a time.
This is the complete parts list for both applcations as well as
for the two power supplies. The order numbers and prices, as of
12.10.2021, are for Reichelt.
The controller and the 32 LEDs determine the total price. Note
that low-current-LEDs instead of standard LEDs increase the price a
Two cases have been analyzed:
As can be seen from the table, a maximum of 22 LEDs can be on
simultanously without reaching the maximum load of the power
supply and without reaching the maximum current of the
ATmega324PA. The last line with the 23 LEDs in the first case
exceeds this limit by 10%, but the ATmega324PA worked fine
even under these circumstances.
- the light-band with 5mm-LEDs, designed for 20mA current,
supplied by the 200mA-power-supply,
- the minimum size light-band with 3mm-LEDs, designed for
2mA current, supplied by the 4LED-power-supply.
First of all: regulators for 3.3 V do not work as exact
as 5V-regulators. They only work fine at very low currents,
where no LEDs have to be driven. Especially in the mid-range
of current loads both regulators are on their knees, with a
maximum of 0.6 Volts missing. In the higher current areas
they again go up with their voltage but they never reach
their nominal voltage again.
Astounting is the current if no LED is on. With 0.51 and
0.88 mA both currents are quite different, even though
both ATmega were measured at the same clock frequency and
without interrupt servicing.
The average currents are fine, but the voltage drops of the
regulators cause very different currents.
Conclusion: a battery is a much better regulator. And: do
not trust semiconductor producers, they sell machines with
very different properties than what is printed on the
The software is written completely in assembler and is well
documented, so that own adaptions and changes are possible.
The flow diagrams are available
The assembler source code for the light band can be downloaded
from here and can be
viewed in the browser
No further include files are necessary. Please change the fuses
To the left are the original fuses when the ATmega324PA is shipped,
to the right are those fuses that are to be set to have a correct
functioning of the circular LED.
Only the JTAGEN fuse has to be switched off. Otherwise the LEDs
L13 to L16 would not work correct. All other fuses remain the same.
The light band's software works as follows:
The LEDs of the Ports C, D and B are reversed, which means that
L9 is PC7, L10 is PC6, etc. When constructing the table those
bits are to be defined different: 0x7F to C turns L9 on, 0xFE
turns L16 on.
- The timer TC1 runs with a prescaler of 64 in CTC mode with
the compare value in Compare-A.
- After the timer reached the compare value, a
compare-match-interrupt is executed. The
Interrupt-Service-Routine shifts the complete 32 bit wide
output value either to the right (if the direction bit is
zero) or to the left (if it is one). The shifted registers
are written to the ports A, C, D and B.
- If all (32 or whatever) shifts are executed and rRnd
is zero, the number of repeats in (rRpt is decreased.
If this is also zero, the next combination of values is read
from the control table (Load next table values). The control
table consists of eight 16-bit-words: the first two words
hold the start values of the LEDs (1 is LED off, 0 is LED on,
byte 0: Port A with LEDs L1 to L8, byte 1: Port C with L9 to
L16 reversed, byte 2: Port D with L17 to L24 reversed, byte
3: Port B with L25 to L32 reversed), the third word holds the
Compare-Match-Value (the lower the faster), the fourth word
consists of the LSB, which is the number of repeats, and the
MSB, which is the number of rounds between 1 and 128 as well
as the direction bit in bit 7.
- If the table end is reached, the next table address is set
to the beginning of the table. The table can use the complete
rest of the flash memory, sufficient for roughly 4,000 table
The table entries again:
Die voreingestellte Tabelle hat folgenden Inhalt:
- First word: LSB = Port A (bits normal), MSB = Port C
- Second word: LSB = Port D (bits reversed), MSB = Port B
- Third word: CTC compare value, 1 MHz / 64 =
15.625 kHz, per round these are 488.28 Hz or
- Fourth word: LSB = Number of repeats 1..256, MSB = Number
of shifts 1 .. 128, Bit 7 = 1 is backward shifting.
The constant cSecondMult allows to define the duration of
a 32-shift round in milliseconds. In lines 3 and 6 of the table
you can see how the shift direction can be reversed. The lines
5 and 7 demonstrate a "quiet" round, with none of the
.dw 0xFFFE,0xFFFF, (10000*cSecondMult+500)/1000-1, 1+32*256 ; One LED, 1 time right, round time 10 seconds
.dw 0xFFFE,0xFFFF, (2000*cSecondMult+500)/1000-1, 20+32*256 ; One LED, 20 times right, round time two seconds
.dw 0xFFFF,0xFF7F, (2000*cSecondMult+500)/1000-1, 10+256*(32+cLeft) ; One LED, 10 times left, round time two seconds
.dw 0xFFFE,0xFF7F, (1000*cSecondMult+500)/1000-1, 10+32*256 ; Two LEDs, 10 times right, round time one seconds
.dw 0xFFFF,0xFFFF, (500*cSecondMult+500)/1000-1, 1+32*256 ; All off for half a second
.dw 0xFFF0,0xFFFF, (100*cSecondMult+500)/1000-1, 100+(32+cLeft)*256 ; Four LEDs in a row, 100 times left, round time 0.1 seconds
.dw 0xFFFF,0xFFFF, (2000*cSecondMult+500)/1000-1, 1+32*256 ; All off for two seconds
You can see from the flow diagram, that all runs though the ISR
require between 26 and 43 clock cycles (the red numbers in the
diagram are clock cycles). This is the reason for selecting
a prescaler value of 64: even when the CTC compare value is
zero, one complete execution cycle fits within and no timer
interrupt is missed.
... are available
here as 1280-by-720
and here as 640-by-360.
The software of the clock application is also written in assembly
The assembler source code for the clock can be downloaded
here and viewed in the
No additional include files are necessary.
In the section "Adjustable const" of the source code all
parameters controlling the clock can be adjusted. Many of those
adjustments can use the spreadsheets in the the LibreOffice Calc
file here, can be copied
from the spreadsheet and can replace the corresponding lines in the
source code file.
After assembling and burning the hex code to the flash memory the
Fuses of the ATmega324PA need adjustment,
otherwise the clock runs too slow (or much too fast if you plan to
use a 32.768 kHz crystal).
Prior to or after programming the controller the fuses of the
ATmega324PA have to be adjusted to use the external crystal.
To the left the original fuses can be seen, to the right the
adjusted fuses are marked in red sqares.
The JTAGEN-fuse (otherwise the LEDs L13 to L16 remain dark), the
CLKDIV8-fuse (otherwise the clock runs too slow by a factor of
eight) and the SUT_SCKSEL-fuses have to be changed (otherwise
the clock runs too slow by a factor of roughly two).
The SUT_SCKSEL-fuses are displayed here for a crystal of
2.097152 MHz. If you want to use a 32.768-kHz crystal
and if you imported the respective lines from the spreadsheet
in the LibreOffice file you'll have to change this setting
to a Low-Speed-Crystal entry.
The dewsign of the software is not as trivial as the hardware, because
The complete timing therefore is not simple and straight-forward:
- 60 ceconds are distributed over 32 LEDs only, which makes
1.875 seconds per LED, and
- 60 minutes distribute over 32 LEDs only, which yields
1.875 minutes or 112.5 seconds per LED, and
- 12 hours distribute over 32 LEDs, yielding 0.75 hours
or 45 minutes or 2,700 seconds per LED.
The flow diagram of the TC1-Compare-A-Interrupt-Service-Routine shows all
this. The ISR is called every 58.59375 ms. On its end (lower part
of the diagram) this routine outputs the current states of the four
rLedN registers. The minute's (rMinN) and the hour's
(rHrN) LEDs are ANDed with these registers, depending from two
bits of the sub-counter, so those blink with a different rhythm.
- The second's pulses have to make 32 steps in a minute or in
60 seconds. That is 32 / 60 steps per second or
0.5333333 steps/s or 1.875 seconds per step. To enable a
dynamic second movement, these 1.875 seconds are subdivided
by 32. Each of these steps lasts 1.875 s / 32 =
58.59375 milli-seconds. Each of these sub-steps shifts the
second's LED one step further if it is smaller or equal the
current second position, otherwise it remains there for the
rest of the 32-step-cycle.
- The minute pulses divide one hour by 32, so that 32 steps
are to be absolved in 60 minutes. The step speed is 32 / 60
steps per minute or 32 / 60 / 60 per second = 0.0088888 steps/s or
112.5 seconds per step. Related to a sceond's step duration
of 1.875 seconds these are 60 "seconds",
compared with a sub-duration of 58.59375 milli-seconds these
are 1,920 single steps.
- The hour pulses divide a half day by 32, so that 32 steps
are absolved in 12 hours. Here we have 32 steps in
12 * 60 * 60 seconds or 1.350 seconds per step. Compared
with a sub-duration step of 58.59375 milli-seconds these are
23,040 single steps.
The minute registers rMinN are rotated every 1,920th step
(counter in XH:XL), the hour registers rHrN every 23,040th step
(counter in YH:YL). If after rotating all four bytes a zero rotates out,
this zero is copied with AND to the beginning of the four registers, so
that minutes and hours re-start again.
The flow diagram starts with shifting the seconds LEDs. This shifting
of the rLedN is stepped over, if the round down-counter in
rCntRnd is larger or equal to the seconds down-counter in
If the round counter in rCntRnd reaches zero, the LED registers
re-start with the first LED and the round counter re-starts with 32.
The end of a 60-second-period cannot be used to advance the minutes,
because the minute's LED only increases after 1.875 minutes.
Therefore the minutes and the hours are derived from the 16-bit
counters in XH:XL and YH:YL and have nothing to do with the second's
The shifting of the seconds in rSec, which occurs every
1.875 seconds, is clocked separately with the 8-bit-counter TC0.
This counter runs with a prescaler of 1,024. The overflow interrupt
of this counter, which occurs after 256 prescaled clock cycles,
decreases a software counter in rSecDiv by one (down from 15),
which then decreases rSec if it is zero. If rSec
reaches zero, it is re-started with 32.
In red letters all clock cycles within the ISR are documented. As can
seen, a maximum of 76 clock cycles is required. Even at a crystal
frequency of 32.768 kHz only these are 4.0% of the time when the
next TC1 interrupt occurs. The software therefore is suitable even for
this very low clock frequency.
The number of consumed clock cycles plays an additional role: the
operating current of the controller depends from that. As outside
the ISR the controller is send to sleep, it doesn't consume relevant
current. At 2 MHz clock the sleep share is 99.3%, at
32.768 kHz this share is 96.1%. The current consumption of the
controller therefore is irrelevantly small, as compared to the LEDs.
If you want to start the clock not at 00:00:00 but, e.g., at
20:20:00 (or 08:20:00), you'll have to do that in the source code.
As the uneven times of minutes and hours in this clock require
some calculation, the spreadsheet in the LibreOffice Calc file
"clockstart" provides some assistance for this. That
spreadsheet took me several hours of hard work until it functioned
correct, so use it properly.
The times at which the next minute or hour LED is to be rotated,
can be seen from this table. n is the round number from 0 to 32.
The columns Minute and Hour show the times. The column Bit show
the portbits to be activated (different rowing for port A and
C/D/B). The LED numbers in white on red background refer to the
numbering in the schematic.
As nearly all minute and hour times are fractional, the start at
a certain time requires to set the minute counter in XH:XL and
the hour counter in YH:YL to certain values. If the start time
would be 20:20:00, the hour LED would have to be LED22 (bit 1
in port B). The next shifting would have to be at 20:25:00. The
20 minutes will have to switch portpin PD45 active, the next
minute LED would be activated at 20.625 minutes.
In the spreadsheet "clockstart" just input the hour and
the minute of the starting time into the two cells with green
background. This calculates the LED number and the port bits
and displays this as hex number (and below in 32-bit binary).
As the next shift of the hour and minute registers is only
parts of a whole division, the sheet also calculates the rest
of the counter time (as part of the 1,920 resp. 23,040 full
counter stages). These rests can be used to start the XH:XL
and YH:YL counters.
Those four constants in the source code can be copied from the
spreadsheet by highlighting those cells, Ctrl-C to copy those
to the clipboard and Ctrl-V to replace those line in the source
code file. After assembling and burning the clock starts at this
... are available at
here in 1280-by-720 resolution
and here in 640-by-360 resolution.
©2021 by http://www.avr-asm-tutorial.net