I'm always amazed at the new technology that is constantly coming out that allows hobbyists like myself access to powerful and cheap microcontrollers like the Arduino or chipKIT development boards. They are easy to program and easy to use, but sometimes the code can get a little bit long and we look at it and think "There has to be a better/faster/easier/shorter way to write this." There are a few ways to simplify sketches, like using arrays and for() loops to iterate through assigning pin numbers to variables, but one of my favorites is to assign the 1's and 0's directly to the registers on the chip. This happens in the background when you compile and upload your sketch to your microcontroller. Each instruction and it's associated parameters are broken down into a simpler language called Assembly (AVR instruction set for ATMEL chips, MIPS instruction set for PIC chips), and Assembly instructions are designed to directly manipulate the bits in registers. Now, you can take the time to learn Assembly and a new IDE to implement it, or, if your instructions are simple and clear, you can avoid the extra cost of space and time by skipping over the instruction conversion process and read/write data directly to/from the registers using standard IDE instructions that you are familiar with.

Step 1: So What Is a Register?

Wait, what's a register you ask? In short, it's a chunk of memory usually consisting of anywhere from 8 to 64 bits of data. Each bit is assigned a value of 1 or 0, and the value of each bit in the MANY different registers in a microcontroller tell the rest of the system what to do and when to do it. Most of the registers in the ATMEGA328P chip on the Arduino are 8-16 bits. The chipKIT boards use PIC processors, and they are usually 16-32 bit registers.There is a LOT more I could go into regarding registers, but it's better left to another day. Wikipedia has a good explanation as well.

You can think of a register like you do an array when you write a piece of code in your favorite coding language, except that each element is a single bit, not a collection of bits that make up the int or char you defined. Also, just like arrays, the count starts at 0, not 1. So an 8-bit register (let's call it myRegister for kicks) has 8 bits total, numbered from 0 to 7. So if we see a pin on our microcontroller assigned to bit myRegister[6], we know that the 7th (second to last) bit is the one we need to manipulate. It can be tough to keep straight, but it's important. I'll try and clarify it more later, probably to the point of overkill.

Some things to keep in mind - While register manipulation is a perfectly viable programming option, I don't really recommend it unless you are extremely confident in your abilities and you are totally out of memory on your chip or need to free up some extra clock cycles. Oftentimes there are a lot of checks that happen in the background when you use the standard functions and libraries to assign I/O direction and values to the pins. It can get tricky keeping all of that stuff straight, and may not be worth the time and effort it takes to re-write your code using registers. That being said, the examples I will show you are simple and basic in the extreme so anybody can use them, regardless of experience. They will definitely take less memory and process faster than if you were to use the standard functions. But you need to be extremely careful when you manipulate the registers directly, and quadruple check your statements. It would be tough to damage the chips manipulating the registers incorrectly, but it can be much harder to debug when it doesn't work right, most often because you wrote the wrong value to the wrong register and/or bit. The standard functions and libraries are there for a reason. They take more memory and processing time, but are usually more user friendly. Last thing, don't forget that the performance parameters for each pin don't change (e.g. current sourced/sunk, voltages, etc.) when you use the registers. Don't blame me when you try and drive a 2A motor directly from pin 10 and it smokes your chip. That's on you because you should know better anyway.

Maybe the cause of the random noise using the Arduino sketch is due to the use of delayMicroseconds () function.<br> <br> The function itself has a certain execution time which cannot be neglected. When working with such short pulses (0.5 milliseconds) execution time for other functions must be kept to a minimum amount.
<p>am new to this.... </p><p>But according to me this was nice and so useful to me.</p><p>thanks lot</p>
<p>I don't know if this is only on my computer, but the example code was apparently so long that Instructables has cut the length of the code boxes, causing the text to continue out the bottom, obscuring other text below it. I fixed it by typing the following into the browser console. (In Chrome, this is activated by CMD+ALT+J)</p><p><strong>a=document.getElementsByTagName(&quot;pre&quot;);for(i=0,l=a.length;i&lt;l;i++){a[i].style.height=&quot;auto&quot;}</strong></p><p>This simply sets the height to 'auto' on all elements in the document with tag type 'pre'. Anyway, great Instructable!</p>
<p>&quot;(easy but confusing math stuff here)&quot;. That's a great way to avoid talking about some slightly irrelevant details. XD But, great Instructable, I really enjoyed reading it! It was well structured and easy to follow (relative to difficulty of the topic)! =D</p>
<p>Thanks nodcah</p>
<p>My first &quot;computer&quot; was a 6502A at 1MHz and used the exact same tricks in binary (and machine code, I didn't have an assembler). Now I'm playing with an ATMega328P at 20MHz (&quot;homebrew&quot;, that's new too), I can say nothing has changed since the late 70s - except the speed, the Open Source and... the price.</p><p>Thank you for this refreshing article.</p><p>BTW, MPLAB IDE lets you program directly in ASM, do you know if there is such thing with the Arduino?</p>
<p>I'm unfamiliar with coding directly in AVR assembly. I'bler dampingFactor mentioned in a previous comment down below that he uses codevisionavr.</p>
<p>Cool Ible</p><p>Arduino always was a simplified view on the underlying hardware. (started with Atmels)</p><p>When i started using uP's, it was the Z80. It didn't have any peripherals as PWM's Counters, DA's built in. I used to &quot;hand assemble&quot; the code in the beginning. (I had to manually calculate jump addresses to &quot;labels&quot;, because that's what the &quot;Assembler&quot; normally does.)</p><p>Arduino is a extreme abstraction, to how the processor works. Bringing it closer to our human language and making it easier to use. If you don't need optimized code, it just works. But if you have some time critical applications, you're lost. (have you ever tried to diassemble Arduino code?)</p><p>This instructable can be a introduction to &quot;real&quot; u'controller programming...</p><p>(never trust a high level language, unless it's Forth)</p>
<p style="margin-left: 20.0px;">+1 Cool ible....</p><p style="margin-left: 20.0px;">I started with the Signetics_2650<em> early dev PCB only 256 words 8 bit wide</em>, then the 8008 and finally the Z80 ==&gt; Double the registers, I/O mapped into memory and bank switching...</p><p>And I'm not sure about Forth. </p><p>Only wrote two Forth stacks before moving_on to Stamps and compiled basic... A basic that can be converted to machine code and burned into $6 pic with the ability to insert your own fast routines.</p>
<p>Thanks for a well-written instructable. Though the &quot;Arduino way&quot; works well in most cases, it's sometimes fun to see what's really going on.</p>
<p>Good explanation about the things many of us take for granted that somebody has diligently done in our various libraries</p>
<p>great article.<br>One thing you might have forgotten to mention (unless I skipped over that) is that even between various Atmega's the code becomes less portable from one atmega to another. If you did mention that.. I apologize </p>
<p>No I didn't and you're very right. Each chip has it's own characteristics that users need to keep in mind. That's why I listed the pin-mapping for several boards. Each of the chipKIT boards uses a different PIC32.</p><p>Thanks for mentioning that.</p>
<p>If you are really interested in how the underlying microcontroller works (Arduino is a development board, not a microcontroller) you should start playing with just the MCU. I'd recommend a simple ATmega328 or ATtiny24 chip. It only takes a few external components. You can use the Arduino board, but you might be tempted to you Arduino &quot;sketches&quot; instead of actual code. It's all in the datasheet!</p>
<p>It's interesting how the Arduino IDE and MPIDE don't require the normal main() statements and such that are needed when writing code. main() is implied in the IDE, and everything you sketch is put inside it in the compiler. Thanks for making that distinction. And thanks for the info.</p>
<p>Yes, They are great learning tools, but the hide a lot of what is going on (for simplicity) which is good if you don't care to explore further, but bad if you want to see what the chips are really capable of.</p>
I've always used codevisionavr. This is a c compiler offered by HP InfoTech, free evaluation version available. It is now available as an add on for avr studio 6.1 and higher available on the Atmel website, also free. As for a good all around microcontroller from Atmel I recommend ATmega16. It has pretty much one of everything available on the chip.
<p>Thank you for the info!!</p>
<p>This is very useful when interfacing with parallel devices. That way you can do something like PORTL=123; instead of having to write the pins individually and figure out which ones to set. </p>
<p>As always, such great content explained clearly. All this talk about registers reminds me of my PLC classes a few years ago. Good Job!</p>
<p>Thanks for the feedback. It can be such a complex idea the first time you see it, so I'm glad at least somebody got it! LOL</p>

About This Instructable




Bio: I've always loved to figure out how things work, so hacking and making just fits for me. I'm an intern at Digilent Inc ... More »
More by brmarcum:Monitoring Digital Circuits With the Digital Discovery Using the Voltmeter With the Analog Discovery 2 Semiconductor Curve Tracer with the Analog Discovery 2 
Add instructable to: