Continue to Site

Welcome to

Welcome to our site! is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Question on learning ATmega328 using Elegoo kit.


Full Member level 4
Sep 21, 2016
Reaction score
Trophy points
Activity points
Hi, I bought the Elegoo kid from Amazon:

I want to learn programming and design hardware using ATmega328P. I know I will be using C++ to program, but at the mean time, I want to know how much I have to study ATmega328.

I designed MPU stuff long time ago, I am reading the data sheet of ATmega328, it's LOONNGG!! I also reading the assembly language. That's total of over 300 pages. My question is how far I need to study this before I start working on the kit.

I want to be a little better than kids that just follow the instruction and make some of the experiment work, I do want to eventually design using the ATmega328. So how much I need to study the ATmega328.


I recommend to read fly over the whole datasheet. Just to get a clue about it's features.
Especially here in the forum I see many "solutions" that could way improved ...
* easier coding
* much faster (using way less processing power)
* more reliable / stable / predictable

They often use one blocking task using 100% processing power
While one could easily perform 10 tasks quasi parallel ... while only using 5% of processing power in total.


I recommend to read fly over the whole datasheet. Just to get a clue about it's features.
Especially here in the forum I see many "solutions" that could way improved ...
* easier coding
* much faster (using way less processing power)
* more reliable / stable / predictable

They often use one blocking task using 100% processing power
While one could easily perform 10 tasks quasi parallel ... while only using 5% of processing power in total.


That's kind of what I think. I spend time looking at register, I/O, SRAM, EEPROM and Flash address mapping so far. I am also looking at the general direct register, I/O, indrect addressing of memory, and some pre, post increment stuff, just to get the feel of what is available.

I have no interest in programming in assembly for sure. Please let me know what else I need to scan through.

just to get the feel of what is available.
Yes, this is what I mean.
No need to spend the time to fully understand every detail...but spend enough time to get familiar with the features ... at least that you know they exist.

But for every periferal, like ADC, SPI, I2C, UART, reset sources, timer..counter..capture..PWM...
One very important feature are the interrupts.
Usually it's just a couple of line to set them up .... but then you may forget about them.
They save so much processing time

Example: in most if my applications I have a counter to generate an interrupt ... let's say every 10ms.
Wihin the ISR
* update the software RTC
* scan for key press
* set flags and increment counters for main loop processing
* control LEDs, buzzers, motors (timing)

Often I have a buzzer that I want to sound for let's say 1 second without blocking my whole code.
Then I just use a simple variable Buzz.
When I want the buzzer to work ... I set Buzz to 100 (100 x 10ms) then I forget about the buzzer in main loop
In the 10ms_ISR I just check Buzz for 0: if not 0 I switch ON the buzzer and decrement Buzz. Else I switch OFF the buzzer. Maybe takes a microsecond every 10ms. (0.01% of processing power)

By writing these 3 lines of ISR code ... the main loop becomes fast and simple ... and plenty of time for other jobs....while one does not need to care about switching OFF the buzzer after the desired delay. The ISR will care for it, with almost perfect timing.
This is so convenient.
And declaring the "Buzz" variable as volatile you may even check it's state in main loop. If Buzz > 0 you know the buzzer is currently ON

Or UART receive. Lets say a command via UART is max 8 bytes long, like "BUZ100[Cr]".
Then define a ring buffer for 8 bytes.
On UART_receive_ISR, just push thevreceived byte into the buffer and check for [Cr]. If Cr then set a flag "Parse".

In main loop just check whether "Parse" is active .... then run the parsing subroutine to process the data in the ring buffer

Hi KlausST

I find the data sheet and even assembly code from Microchip is NOT that good, it's like the terms are not well defined. I am not sure Rd and Rr whether it's the content of the register or the address of the register, like "r" and "d". It never really gave the clear definition.

Do you have suggestion of a book or some youtube video that is good. It's hard to read if I cannot even sure what they mean.

As a personal experience I found that by picking a specific task and
tackling that, it would draw me into the part, pieces at a time, to work
with and learn. Example I remember is I wanted the equivalent of
todays RTC functionality in a 4 bit micro I was working on. So breaking
it down :

It had to count, days, weeks, secs, months.......
It had to be initialized.....
It had to have human interface....buttons, digits, muxing, scan

Etc and so forth. So each sub task drew me into finding a solution, one piece at
a time. Not overwhelming trying to solve everything at once. All done in ASM, no
compiler at the time. And each new task fertilized the ones I already did and ones
to come.

Once complete, then transformed into a micro junkie, I became fascinated
with addressing methods and benefits, so upgraded the code, increasing
performance, minimizing code density. And this launched the thousand plus
possible branches on learning and investigation, all incredibly satisfying.

That builds a base of knowledge that allows you to look at new tasks and new
architectures w/o climbing mount Everest. Nowadays most processors come
with a rich set of APIs you use to manipulate the HW, much less activity writing
the ASM drivers by typical designers now, just copy and paste the API f() calls into your
code and suppling the parameters for the call.

And if you are a visual learner, there are a number of block coding languages now
where you can turn out basic functionality in minutes versus coding with a C manual
open as well as compiler manual all wrapped around your head. I still recommend you
do the C C++ path, but you can crank out a basic networked solution in 1/2 an hour
with the block languages, an example :

Here is a simple but quite capable timer solution :

And then you graduate to a SOC (System on Chip) where you drag and drop functional
blocks out of a chips catalog, drop them onto design canvas, config them, route them to each
other and then out to pins, and do some code with the 100's+ APIs in their code library
to manipulate them. Single chip !

Example design :

Whats on a typical chip, multiple copies of the blocks in many instances, ability to create
your own out of gates and schematic capture and/or Verilog....


A lifetime of creativity and fun await.....:)

Regards, Dana.
Last edited:

I've used the AVRs a lot. In early days even programmed them in assembly. Really a lot and very deeply.
I surely used every single instruction ... and almost every single periferal register.

I found them very convenient .. especially the instruction set and the rich periferals and speed.
Basically rr is the source register, rd is the destination register.

I don't understand your worries.


I've used the AVRs a lot. In early days even programmed them in assembly. Really a lot and very deeply.
I surely used every single instruction ... and almost every single periferal register.

I found them very convenient .. especially the instruction set and the rich periferals and speed.
Basically rr is the source register, rd is the destination register.

I don't understand your worries.

I just bought 2 books to help, but at the mean time, this is my confusion
1)From below, Rr and Rd is 5bits, this means Rr and Rd is an ADDRESS pointing to register "r" and register "d".

2)Here, it's comparing value of Rd and Rr. This means Rd and Rr is the CONTENT inside the register. You cannot compare ADDRESS.

3)This is the most confusing. I assume Rd, and Rr are the content in "d" and "r" resp. What is in the 16bit Opcode "11rd", "dddd" and "rrrr"?
It said Operands 0<=d<=31, 0<=r<=31. BUT in the Opcode description "r" and "d" is a binary bit only?

I am very exact as in all programming. To me, this is very confusing particular the "11rd" and "dddd". What are that?

I know I supposed to "fly through", but I think I at least have to understand the terminologies a little better. I just cannot move on.

--- Updated ---

I know I am nitpick, but from my pass programming, the code is VERY EXACT. Like in 8080, HL is 16bit register. (HL) is the CONTENT the byte POINTED by HL.

It is very clear reading the instruction.
Last edited:

1) yes. This is the general description of the instruction .
Rd as well as Rr is the address to the according register.
The AVRs have 32 working registers. (Good thing compared to an "accumulator machine" like the 6502).
And the accessing method is called direct addressing.
So address "16" refers to the register#16. Better say it reads/writes the contents of the register 16.
It's always about the content (value) of the register, and not the address of the register. And this usually is what the progamming guy wants.
(Detail#1 below)


2) Now this is not the general description of an instruction, it is the detailed description of the COMPARE instruction.
Yes, as said it always uses the content of the registers.
(Detail#2 below)
Registers are like boxes. 32 equal boxes. Equal, but the content of the box is unknown during coding time.
The content depends on port readings, math results, ADC readings, counter values...

Let´s imagine .. your code makes that an actual temperature value is stored in register#12.
And the user input for a setup temperature is in register#15.
so the instruction "Compare register#12 with register#15" basically compares the actuall temperature with the setup temperature and can decide whether a heater needs to be turned ON or OFF.
(detail#2 below)


3) Again a detailed description of an ADDing instruction.
Yes. Same as always it uses the contents of the according registers.

Now you refer to the (binaray) Opcode.
When programming in machine code you need to understand this.
When programming in Assembler you don´t necessarily need to understand it. (That´s why we have an assembler) But I personally see "your curiosity" in this regard a good charactereistic.
So the complete OPcode is:
So basically you have
* a number of fixed bits "000111" .. this tells the instruction decoder that it is the "Add with carry" instruction
* 5 bits "r" to identify the source register 0..31
* 5 bits "d" to identify the destination register 0..31
So the instruction has all information it needs: both registers and what to do with the contents.
(deatil#3 below)


Your reference to 8080:
Indeed the 8080 was a 8 bit machine and had 7 8bit registers: A, B, C, D, E, H, L. While registers H and L may be combined to a 16 bit register (maybe for indirect addressing).
and as you already wrote:
* HL refers the the content of the H and L registers
* and (HL) refers to the content of the RAM address referenced by HL. This is called indirect addressing.

Same is with the AVR:
there are 32 8bit registers: Register 0..31.
and 3 pairs of them can be combined to 16 bit registers: (analog to 8080 HL)
* register 26 and 27 to the so called 16 bit "X" register
* register 28 and 29 to the so called 16 bit "Y" register
* register 30 and 31 to the so called 16 bit "Z" register
the (now) 16 bit registers X, Y, and Z can be used like with the 8080 as indirect 16 bit address pointer to the SRAM.

So it´s the same .. just different names.
The AVR equivalent instruction to read data with indirect addressing is: (copied from the AVR instruction set)
"LD Rd, X": Load indirect, Rd <- (X)
Note: even in the AVR instruction set they use the X in brackets to show the "indirect addressing"


It is already a rather lengthy post.
To - hopefully - reduce confusion I still tried to keep it short.
Thus I tried to write only the essentials.

You may stop reading here.
Or you read some more details on the topics above.

For sure there is a way to "manipulate the address" .. and not the content of the register addressed.
But with AVRs this is done with the indirect addressing registers, X, Y, Z.
You may add/subtract using the ADIW / SBIW instruction
or it can be used with the post-increment like "Z+" or pre-decrement like "-Z".
Very useful and making the AVR really fast compared to an 8080.
Let´s imagine you want to read 8 consequent bytes of data from an FPGA (parallel access) to the SRAM.
with AVR this is just 8 time (loop or non loop)
LD Rd, X+
ST Y+, Rr
(taking 4 clock cycles per byte to move, so you transfer 4MBytes/s on a 16MHz AVR)
How would you do the same with an 8080 .. and what data rate can you achieve?

Imagine it compared the register address:
While one theoretically could compare the address of the registers .. it would make no sense at all.
Example: compare adddress #12 with address #15 ... you already know that 15 is bigger than 12. So at coding time you already know there is only one result: 15 is bigger than 12. There is no alternative condition. Indeed a useless instruction. It is no "branch" instruction at all, because there is only one way, the other (12 to be bigger than 15) never happens.

You may be worried why there is one "r", then 5 "d" and then the missing 4"r".
First: don´t worry about this. ;-)
This is probaly an chip developing artefact.
The AVRs have 16 registers + 16 registers. The one (R16 ... R31) are more flexible to use than R0..R15.
So I guess at first they defined the 16 registers. using 4 bits per register addressing.
And in the OP 16 bit code they used bits0..3 for the source register addressing and bits4..7 for the destination register addressing. (looks nice and straight forward)
But when they used full 32 register instruction they had a problem .. they now needed 5 instead of 4 bits to access each register. How to handle it?
Indeed there is no clean solution. There always is a caveat.
They decided to put the bissing address bits at OPCODE bits 8 and 9.
Not nice to read for humans. No problem for a hardware instruction decoder.
Rarely a human goes that deep in every bit of the opcode.

Hope this clarified a bit of your worries.

Hi KlausST
Thanks so much for the detail answer. I marked up the page as shown
Question on ADC.jpg

1) Can you take a look the my notes in RED, the in the Operands 0<=d<=31 really mean the 5bit of d4..d0 value is from 0 to 31.

2) For Opcode, 11rd is really 1 1 r4 d4 as shown in RED. dddd is really d3 d2 d1 d0.

3) I have more question in 5.2: Rd3 and Rr3 is the content of register of Rd3 and Rr3. What is R3?

4) What are the sign "<=>" mean? Also what is "-" mean. I don't want to guess?

Thanks for all the help. I know there's easier way to learn this by playing with it. BUT I am actually curious in learning more on assembly programming of this. I always feel assembly is faster, program is much much smaller in space. You can put a lot in 4K of memory.

I started my career in 1979 doing test programs in assembly and machine language using Z80(8080). I always like assemble language, it gives me the feel of the hardware. I since got into analog and RF. when I had to design embedded processor, I just designed the hardware and had my engineer wrote the program for me and always worked. I really never get to write programs myself since the 80s. So I am way behind time on this.

Sadly, now that I retired, I don't have anyone to kick around to do my dirty work. So it's all on me now. Electronics is still my passion. I am designing extreme high end hifi power amps. I have people did double blind tests and my amps are at least as good as those that are over $4,000. Now, I want to get fancier, I bought remote control on ebay in the past, but I want to venture to do my remote control using this. Not only switching channels, volume control. I want to change parameters of the amp with remote. So I am forced( well twist my arm!!!) to learn this. And here we are.

When I get into something, I like to go deeper, not just get it done. I have time, I can do it slowly. So I just slowly learning this. I bought 2 books last night, I want to learn using C++ to call sub-routine in assembly. That would be fun. here is the picture of one of my amp:
12 Pairs amp.jpg

Last edited:

1) yes

2) yes. To be complete you missed "0001" and "rrrr" ...

3) yes. Rd3 is bit3 of the content of the destination register. (Register, Destination, content, bit3)
Tbh: I don't know what "R3" means here. For me the important information is:
"H : Half Carry Flag: The Half Carry Flag, H, indicates a half carry in some arithmetic operations. It is useful in Binary Code Decimal (BCD) arithmetic."

4) Not every flag is updated on every instruction.
[ - ] means the flag is not updated. Not modified, stays as it was before
[ <=> ] means this flag becomes updated. .. on given condition
To complete:
[ 0 ] means flag becomes cleared, unconditionally
[ 1 ] means flag becomes set, uncontitionally

I've really programmed a lot in assembly in the past. You are right, assembly programs are more focussed, usually faster, usually smaller. They are more optimized on what you need.
On the other hand it takes much longer to write the code (especially when more complex), it is more likely for coding errors, much harder to read (especially for another programmer), harder to maintain, libraries are less re-usable...

Currently I don't write much code (I have my professional programmers) but then ... it usually is C or C++, it often uses some some inline assembly.
I still "think in assembly".

I guess I also started around 1980. First with machine coding on a 6502. (It was sooooo slow compared to an AVR)
Then did some Z80 programming, designed microcintroller PCBs, did smaller projects with 68000 and DSP56 (it was incredibly fast in "computation" compared to the - these days - standard 386 machines). Then PIC, AVR, STM32, ESP32 ...

Still I'm rather disappointed how slow computers with modern OS are. Take long to boot, waste a lot of ressources..
On the other hand they have to be very flexible with connected hardware, need a lot of back compatibility, need more programmers to be involved...

What analogy: I also designed high end analog audio - more for my own use. Recently I've got some job for a high end audio company.
I really enjoy this.

But most if the time I do industrial measurement and control designs. Analog and digital combined, high quality, high reliability.
No "works by accident", always well designed, engineered, calculated. When I start a design I do the math first ... soon have a good idea of the performance, have my specs in head or on paper ... then I start with schematics ....
I don't build the hardware first, then find out how good/bad it performes .... I know the performance before hardware design.

Very nice amplifier. Well done.

If you are going to do remote quite a few paths you can take :

1) Use a universal IRDA remote as basis of handheld control element. Possibly
get custom membrane for application / product specific use. Code, bulk your
coding, small amount open source for link layer.

2) Use a radio chip / module for link. They can supply layouts to manage the RF
considerations. Like Nordic Semis solutions, Bluetooth or WiFi or NR+..... Driver
libraries supported by them.

3) ESP8266 or ESP32 WiFi, open source very large following. Libraries a bit of
a minefield being open source. One way around this is align with significant
vendor/user of this architecture, like expressif at chip level and seedstudio, dfrobot,
sparkfun.... at module level. You typically would use HTML for user interface.

Bluetooth seems a little more dominant in todays audio control. But its user interface
slightly more involved, user involvement to pair devices. They may not be a consideration
for your customer target base, eg. they are already somewhat hi tech as users.....

Not to confuse but there are service providers to manage, as an intermediary, messaging
to a phone from networks, like IFTTT. Example doing a local network where you want to
send to a phone a message / data and answer back.

Obviously the control element of choice these days a phone, and there are tons of tools
and apps wifi and bluetooth centric, for development.

Seems like a mount Everest to climb, but basic link can be done in block language quite
rapidly. Although I find this is OK for simple stuff but can "see" it will migrate to regular
C, C++ type environment. Note the block languages generate C, C++ code, so you can get
up a link rapidly and do some basic stuff then move to the more traditional environment.
Tuniot, NodeRed, FlowCode would be the block stuff.

Here is an ap that basically looked for a network using a hotspot controller and if hotspot
hung on startup activated a servo to move it past the screen waiting for a button push. A
remote site issue controlling hardware. Just to show simple network investigation operating
remote HW to fix a problem remote hotspot would not reboot completely without intervention.
Just to show how simple this turned out to be using block language.

Here is another ap done in block language, sophisticated timer with vairied triggers and sequencing.

Regards, Dana.
Thanks KlausST

The few things you explained really help, I have no problem reading quite a few instructions like branching on condition. Now I need to look deeper into SREG.

What do you design in high end audios? To me, the basics are very easy, that’s the reason I chose hifi as hobby after I retired. Power amp is just a power Op-Amp. I design IC before, so it’s common to design op-amps. The best book I found is the book by Bob Cordell. I actually talked to him on forum before, he was an IC designer also, I can really talk to him.

I am really surprised from studying a lot of schematics of higher end amps like Krell, Mark Levinson etc. They really take shortcuts. Like they lower the LOOP GAIN by not use active loads. My speculation is they don’t know how to make the amp stable when the loop gain is too high. They must not know closed loop feedback theory. From reading hundreds of schematics, I suspect most of the designers don’t have formal education on analog electronics and they likely copying each other. There’s really not much creativity.

Before I started designing power amps, I bought a Nakamichi PA-7 designed by famous Nelson Pass. It was an improved version of his famous Threshold S300 with faster power transistors and one more pair(7pairs instead of 6). I bought it because of his name and “Threshold”. His brand now is PASS LAB. I thought that would serve as REFERENCE to design against. Hell, my first design beat the XZY of that from double blind testing with people. That amp is NOT stable. It will oscillate with only 1500pF cap across the output terminal of the amp. It started to sound strange using multi wire speaker cable like Kimber Kable type because capacitance of the cable is too high. Does he even know simple basic close loop feedback theory?

I should have bought the Krell KSA-250, there was one on ebay for $1500. Problem is it sit there and burn like 1KW as it’s a 200W/ch class A amp. Not just the electrical bill, I have to have AC on to listen to music!!!

Still Krell and Mark Levinson are taking short cuts not using active load to lower the loop gain. I used active load of the IPS and darlington VAS and darlington driver for OPS to maximize the loop gain. I designed my amps that they are stable with 5 of the 3300pF small cap in parallel(with short lead to minimize lead inductance) right at the output connector of the amp( not through speaker cable). I do not use output inductor like a lot of them cheat.

One version of my amp is using Complementary LTP(like Krell) as IPS, I got THD reading of 0.002% from 50Hz to 10KHz. 0.006% at 20KHz at 2/3 power into 4ohm. But from listening I don’t like it, it’s too analytical. There is something analytical spec cannot tell. Also, I make my amp as fast as possible. -3db@500KHz 2/3 power driving 4ohm. Slew rate of over 30V/uS with full swing.

To me, when one design to the perfection analytically, then the “ART” comes in. Also a lot of knowledge in RF and other things come into play. I don’t like the sound of Complementary LTP and the simple single LTP design. I have my own design the I am not sharing that I like best.

Too bad, there is NO MONEY in this high end stuff. Companies like Adcom, Nakamichi, Caver, PS Audio etal can earn a lot of money with their middle of the road products. But the very high end ones, how many can they sell. Most people don’t even know their names. So I just do it for the fun of it. Even I hand build my amps, they are NOT CHEAP. Just the chassis and parts is over $1000 each(of cause buy in low quantity, but not that low, like I buy power transistor 100 at a time). One thing I found, there are good reason why they are expensive, huge heatsink, multiple power supplies, many transistors. All .
Last edited:
Hi Danadakk
Thanks for the suggestion. I am still swimming in the beginner's water. I have time to get into the really basic stuffs. I am in no hurry to get anything done. So I am just learning more on ATmega328 rather than trying to get things done.

I'll keep your suggestion in mind when the time is right later.


Hi KlausST

I think I forgot to say, there are so so much SNAKE OIL in audiophile world it's not funny, all the specific resistors, capacitors, wires and all that. They really gives a bad name to those that work hard in audio world. I make it a point to use common components bought from Digikey or Mouser. Wires all from ebay(cheapest). It's all about the design, no snake oil. Hell, I made my speaker cable(very critical component) with cheap copper clad wires from ebay to show off my speaker cables. No fancy connectors. I am born cheap!!

Regarding High End Audio:
This is off topic here, thus I keep it short. I totally agree that there is too much "philosohpic" stuff, that has nothing to do with physics, electronics, mathematics.
In the discussion with my client I had a rule for his design/job: It needs to makes sense physically and it needs to prove that it works as claimed. No fake. My client agreed.
Currently the task is not to design something for the signal path, but for - let´s say - the power supply. (Signed an NDA).
But we talked about signal path, too. It will come later :)


Regarding High End Audio:
This is off topic here, thus I keep it short. I totally agree that there is too much "philosohpic" stuff, that has nothing to do with physics, electronics, mathematics.
In the discussion with my client I had a rule for his design/job: It needs to makes sense physically and it needs to prove that it works as claimed. No fake. My client agreed.
Currently the task is not to design something for the signal path, but for - let´s say - the power supply. (Signed an NDA).
But we talked about signal path, too. It will come later :)

Power supply is VERY IMPORTANT, that much I can say. Too bad I don't have experience in SMPS, again, I had my engineer designed those so I could concentrate in "more challenging" designs. I wish I had involved in it a little more. It's a flip of a coin whether I want to spend the time on MPU design like here, or SMPS design. I decided ATmega328 is more interesting.

Whole programming thing started because of my grandson. He's a CS major just graduated. 3yrs ago, he told me he didn't have motivation. So I said to him how about grandpa nipping on your heal?!!! I actually studied C++ with a book from cover to cover in 1/2yr. The whole thing lead to today with ATmega328. I ultimately want to program with C++, but I am interested in assembly programming also. I don't have a dead line, so I just go wherever I feel like.

I do enjoy talking about experience on hifi design, not necessary in detail circuits, but experience and impression. I know it's hard to talk, you have your NDA, I have ideas that I am not willing to share as I might apply patent on.
Last edited:
I am still studying slowly. I have one major question on SBI and a few side questions.
Question on SBI.jpg

I copied these from the data sheet, My question is in RED.
1) If you look at the description of the instruction SBI, it said the SREG is not affected, but in the lower example, it definitely said SBI affect the SREG. Which one is true or I reading it wrong?

2) From SBI r16,2 instruction, it means set bit 2 of r16. If r16 has original value of 0x01, setting bit 2 gives you 0x05 only. Bit 7 is NOT set. Why N is set?

3) I just want to confirm the bits on SREG is set LITTERALLY by the content regardless of what the value represented.



The other two questions is not important, it's pretty clear. It's the SBI r16, 2 that I cannot get pass. That's setting bit 2 of r16, that will not set bit 7 as the original value is 0x01 only, you only get 0x05 after SBI setting bit 2.


LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to