Have you tried to go beyond Arduino but got stopped by the dense datasheets?
This is the instructable for you!
I was working on an instructable for the epilog contest which would wirelessly link two smoke alarms.
I wrote all the code and prototyped on a breadboard.
As the deadline drew near I built the hardware but no matter what I tried I couldn't make it squeeze into the tiny space available.
As I wallowed in self pity, I thought of what a waste it would be for all that I learnt to be left in my head, so here it is!
This instructable will take you from the basics of bitwise manipulation to making good use of standard AVR peripherals such as timers, interrupts & serial communications.
It will also cover common extras such as Infrared remote controls, radio communications and more.
So jump in, skip what you know and brush up on what you need to.
Create the breadboard projects presented and learn new things!
Remove these ads by
Signing UpStep 1Binary and bitwise operations
Lets start at the most basic, the bit.
A bit is the smallest unit of data to a computer, it is either a '1' or a '0'.
In other words it is either on, or off.
To do anything useful in a computer though, a single bit is not enough, so they are combined into bytes.
A byte is 8 bits together, and using binary counting a byte can either store 0-255 (256 numbers) or -128 to 128.
For example:
00000000 = 0
00000001 = 1
00000010 = 2
00000011 = 3
00000100 = 4
Just like when you are counting in decimal (base 10, as in 10 fingers!), when you go past 9, you put a 1 in front and put the second digit as 0.
It is the same with binary, except as there is only 0 or 1, when you go past '1' you put a 1 in front and a '0' as the second digit.
The features of a microcontroller are controlled by registers. In the case of an 8-bit AVR they are either 8 or 16 bits long.
Instead of the whole thing representing a number however, each bit determines if a certain feature is on or off.
We will look at a lot of different registers later, but for now let's make up an imaginary one so we can see how to manipulate them.
Imagine we find a register in the datasheet that connects to 8 LEDs called LEDREG.
Each bit in the register is either a 1 or a 0, the LED is either on, or it is off.
We could turn on the first LED like so:
LEDREG = 1; // 00000001
2nd LED
LEDREG = 2; //00000010
But what about the 3rd LED?
If we did this:
LEDREG = 3; //00000011
We wouldn't get the 3rd LED, we would get LED 1 & 2 lit up instead!
With registers it isn't the number that matters, but what the underlying bits look like.
The 3rd LED would look be like this:
LEDREG = 4; //00000100
If you wanted to turn on different patterns of LEDs you could work out all 256 combinations, but that would be tedious.
There is a better way!
Boolean logic
Computers at the lowest level work with something called boolean logic.
They use logic gates to combine binary numbers.
For example an AND gate will only output a 1 if both inputs are 1.
An OR gate will output a 1 if either of it's inputs are 1.
Have a look here:
http://www.electronics-tutorials.ws/boolean/bool_6.html
It shows the 'truth tables' for common logic gates.
So, what use is all this to us?
We can make use of these logic gates directly using bitwise operators
Bitwise operations
Lets say we already have the 3rd LED on:
LEDREG = 4; //00000100
How can we turn on the first LED?
We could put in the value of 5 (00000101) but we don't want to have to figure out which combination each time.
Instead we can use an OR operator like so:
LEDREG = LEDREG | 1;
What this means is this
00000100 OR
00000001
--------------
00000101
The OR operator lines up each bit and if it is on in either byte, it will be on in the output.
A quicker way to write "LEDREG = LEDREG | 1;" is:
LEDREG |= 1;
You can also chain your operators like so:
LEDREG |= 1 | 2;
This will come in handy when we learn shift operators.
What if you wanted to toggle all of the LEDs?
You could use a NOT operator:
LEDREG = ~LEDREG;
A NOT operator flips all the bits, so you get:
00000101 NOT
--------------
11111010
Next lets look at an AND operator.
AND is used to mask a value.
That is, it is used to blank out sections of a byte but keep the value of the unmasked section, like so:
11111010 AND
00001111
-------------
00001010
You can use an AND to turn off a whole group of LEDs without changing the state of the rest.
In the above example it would be used like:
LEDREG &= 15; //00001111
One more useful operator before we move on is the XOR.
XOR stands for eXclusive OR.
It is similar to an OR gate, however if both bits are on, then they are turned off.
For example:
LEDREG ^= 15;
00001010 XOR
00001111
-------------
00000101
Now, by themselves the operators are limited, you still need to convert from binary to the equivalent decimal number.
This is where shift operators come in
Shift operators
A shift operator simply shifts all the digits left or right.
For example a left shift of 1:
x = 5 << 1;
gives you x == 10
in binary that is:
00000101 <<
-------------
00001010
A right shift simply moves the bits to the right:
00001010 >>
--------------
00000101
Any bits at the ends are simply lost (or stored in a carry register, but lets ignore that for now!)
A shift operator can be used as a very fast multiplication & division, as long as you are happy with only multiplying / dividing by powers of 2, eg:
x << 1 == x*2
x << 2 == x*4
x << 3 == x*8
Shifts are used a lot in setting registers.
Lets return to our LED example.
If we want to set the 6th bit, instead of working out what number that would be and then ORing it with the register, we can use a left shift like so:
LEDREG |= (1<<5);
NB: It is '5', not '6' as we only need to move the '1' 5 times.
In binary it would look like so:
00000001 <<
-------------
00100000
Which is then ORed with the register like so:
00000101 OR
00100000
-------------
00100101
In datasheets, the position of a certain bit is usally given a name such as "RXEN" which is used to turn on receive mode in the serial peripheral and "TXEN" for transmit.
Together they would look something like this:
UCSRB |= (1<<RXEN) | (1<<TXEN);
This should be enough to get you started, lets move onto some real examples!
| « Previous Step | Download PDFView All Steps | Next Step » |















































I bought a USBTinyISP to program my chips, and built it - that was good fun. Then, I learned a bit more about AVR, and built the VUSBTinyISP, which is an instructable. I highly recommend both of these, since they'll teach you all about burning chips.
I just reread what I wrote and I wish I had done better, but I had rushed it in for a deadline.
I like the Arduino and started there, but after playing with a few low level operations I quickly took to AVR GCC directly.
It was a lot more fun to code against such restrictions, when at work I am usually on a machine with between 8 & 32 GB of RAM, there is no pressure to try to do anything interesting.
The smallest I have done now though was an ATTiny13, and that was a fun set of restrictions, not even having hardware serial and having to do it directly in assembly was fun!
But to be far to Arduino users, that isn't everyone's definition of fun, and solving the problem by using it as a tool is all they need.
Maybe there is room for some instructables that takes a stock arduino and a USBTinyISP and ease the user into working without the Arduino libraries and boot loader.
That seems to me to be the easiest path if you want to convert them, they already have a stable hardware platform (power, USB->Serial etc) so all of their focus can be on the software differences.
I was really turned off by the latest issue of MAKE. They had a 12-year-old kid write in about how he was doing really cool stuff with raw AVR in the Q&A section. Reading this, I was extremely happy, since obviously this is superior to arduino development. Their response? "Go find some arduino resources here and read our biased article about how arduino is better than everything else." That was the entire response. No commendation, just a quick "if you're thinking about doing any sort of microcontroller development, you better do it with arduino." That's anti-intellectual.
So, thanks again. Hopefully people will see the light once they've spent hundreds of dollars on about $10 worth of AVR chips.
Thanks again for reminding me about the missing appendix.
I just added it then if you want to look it over, but in the end I couldn't add much to the already excellent tutorial from ladyada.
I had this feeling in the back of my head that I had missed something.
I will do a proper write up this weekend (tomorrow), but until then you will do well to read ladyada's tutorial on the topic:
http://www.ladyada.net/learn/avr/
Thanks for pointing this out, I wrote this instructable in a rush and I just forgot.