AVR Port Simulator

Microcontrollers are extrememly popular in circuits nowadays, and that is for good reason. They can be programmed to do just about anything and replace otherwise very complicated hardware. Take, for instance, the Arduino and, by extension, the atmega series of microcontrollers. These devices allow us to manipute hardware by writing software. The only problem is that writing code for and understanding these microcontrollers isn’t exactly as straightforward as making a circuit out of transistors. So, in this video, I will provide the very basics to writing code for a microcontroller, specifically the atmega series of microcontrollers, so that you can start making programmable circuits of your own and move beyond the confines of Arduino boards.
Today’s video will cover basic software controlled I/O. Every microcontroller has something similar to what I will describe, so don’t worry if you are trying to understand another microcontroller, the general ideas are similar. This code should also generally work in the Arduino IDE as well. Take a look at your datasheet if you are unsure. I will give you some example code and run it on an actual AVR and then explain how it works. This is the code that we will be using. I will explain it all in a second, but I will show you what it does first. As we can see it blinks each LED in an alternating pattern. To explain how the AVR can do this, I have created this PCB to demonstrate how the AVR handles I/O on its digital pins, and you, the user, are the CPU. I know it looks complicated but if we break it down you will understand how it works completely. Let’s start in the bottom of the PCB. This is where I introduce the concept of registers. Basically, a register is a piece of hardware that stores binary data, in this case 8 bits of data. The CPU can read and write to it. It’s almost like RAM except its faster and has a purpose in controlling hardware directly. You, as the CPU, can read from it by looking at the LEDs. An LED that is on is a ‘1’, and an LED that is OFF is a ‘0’. You can write to it by selecting ones and zeros on the switches and then pressing the write button. We can see in our code that the first two lines of the main function are the DDRB and the PORTB registers. The silkscreen on the PCB represents these registers. Let’s write these values into the registers. 0xff represents all ones, so we can write that in. 0xaa is simply alternating 1’s and 0’s. While its great that we can save this data, how do these registers directly affect the output? Well, we can take a look in the datasheet to find out. We can see that the PORT register is connected to the output through this component, which is a buffer. A buffer simply outputs the same logic level as its input, so a 1 on the input leads to a 1 on the output. We can already see that the output, which is the green LEDs at the top by the way, matches the PORT register. But what about the line connecting to the buffer from the side? Well that is the enable pin. The enable pin does exactly what it says, and when it is a 0, the output of the buffer is high impedance. The buffer is implemented on the board as U2 and U3, and they are the SN74HCT125 buffer ics.
Why would we want a high impedance output? Well, sometimes, we want to use the pin as an input and don’t want some output messing with it. That is why the register is called the Data-Direction-Register. A one makes the pin an output and a zero makes it an input. So, in the arduino programming method, you can sort of think of the PORT register as digitalWrite and the DDR register as pinMode, the difference is that you are changing 8 pins at once. When we set the pin as an input, we can see that it is driven by external connections. However, the PORT register still has one more trick up its sleeve. When the pin is set as an input, the PORT register can be driven high to set the pull-up resistor. This basically just connects the pin to VCC through a 10k resistor. This allows the external world to drive the pin, but it will be high by default if the external interference is high impedance. This just keeps the pin from floating. Remember, the pull-up resistor is only active when DDR is 0 and PORT is 1. That finally brings us to the PIN register. This register is read-only, and it doesn’t matter if the pin is an input or output. This is how you read input, you can also read output if you find the need to do that. Now let’s continue on with the code. Once we enter the loop, the first instruction deals with the PORT register. This line of code basically reads PORTB equals PORTB xor’ed to 0xff. First, remember that 0xff is 8 bits of 1’s. If you are unaware of bitwise operators, the arrow is the xor operator. An xor is basically when one input is a one the output is a one, however if both are ones or both are zeros, the output is zero. This operator is useful for alternating bits, and you can select which one by setting the appropriate bit. Anyways, since we are the CPU, we need to look at each bit and xor it with a one. That means that each one will become a zero and each zero will become a one, alternating the output. And obviously delay just means that we have to wait. We can now repeat that process forever because we are in an infinite loop. Now that you understand how to write code this way without the arduino libraries, why would you want to do this. Isn’t it easier to refer to each pin individually instead of having to deal with entire registers with 8 pins at once. Well in some ways it is better and in others it isn’t. So, yes while it is true that it is easier to understand initially and can lead to easier code in certain circumstances it does have its drawbacks compared to the method that we used here today. First, the arduino functions such as pinMode or digitalWrite are a whole lot slower than writing to the DDR and PORT registers because the arduino has to lookup where each pin is located. For example, pin 13 on the arduino correlates to pin 5 on PORTB. Arduino has to find out where pin 13 is whereas our code already knows where PORTB and DDRB are. Second, writing to the registers like this can lead to situations where we can take advantage of controlling 8 bits at once. We can read the register and write an 8 bit number to it, making it especially convenient in this example to alternate all 8 bits at once. This video serves as my introduction to microcontrollers that go beyond arduino. This red board here simply provides an interface where you can directly interact with the ideas I talked about in this video so that you can learn more about it and experiment. If you want one for yourself, I’ve left the schematic in the description. If you enjoyed this video and found it helpful, please consider subscribing so that you can see my other videos. Have a good one.