I/O Port Operations in AVR
Hello friends! In this post, we will discuss about the port operations in AVR. Before going further, I suggest that you read my previous post regarding AVR Basics. The examples discussed here are in accordance with ATMEGA16/32 MCU. However, the concepts are equally good for any AVR MCU.
Register
Okay, now I hope you are familiar with the term register. If not, then you must have heard of it. Basically, a processor register is a memory space within the CPU itself so that they can be accessed very frequently and fast. These registers are linked with the operation of the MCU. Let’s consider the following memory space.
Here, you can see that I have represented 8 bits together to form a memory of 1 byte. Note the sequence in which the bits are numbered. They are numbered as 7, 6, 5, … , 1, 0. This is because the bits are numbered from the Least Significant Bit (LSB) to the Most Significant Bit (MSB). From the knowledge of digital logic, we know that the last bit is the LSB whereas the first bit is the MSB. Hence, Bit 0 = LSB and Bit 7 = MSB.
Register Concept Explained
Let me explain you why LSB is the last bit. Let’s take an example. Please note that 0b stands for binary and 0x stands for hexadecimal. If nothing is prefixed, it means that it is in decimal number system.
A = 0b 0110 0111 = 103
Now here, let’s change the value of the last bit (orange colour bit) from 1 to 0. This makes
B = 0b 0110 0110 = 102
Now, once again in A, let’s change the first bit (magenta colour bit) from 0 to 1. This makes
C = 0b 1110 0111 = 231
We see that by changing the last bit, the result (B) is very close to the original data (A), whereas by changing the first bit, the result (C) varies quite significantly from the original data (A). Hence, the last bit is the LSB (as the data doesn’t change significantly) whereas the first bit is the MSB (as the data changes significantly).
Now, we also know that 1 nibble = 4 bits. Hence, bits 0,1,2,3 are called lower nibble whereas bits 4,5,6,7 are called upper nibble. So basically, a register is a memory allocated in the CPU, usually having a size of 1 byte (8 bits).
Next, every register has a name, and every bit of it also has a name. Take the following example.
Here, the name of the register is ADMUX (don’t worry about the name, we will discuss it later). Also, note that each bit also has a name and an initial value. Each bit of the register can have a value of either 0 or 1 (initially it is 0). Now suppose, I write
ADMUX = 0b01000111;
This means that the ADMUX register has been updated as follows:
This can also be achieved by the following codes:
ADMUX = (1<<REFS0)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0); ADMUX = 0x47; //Hex form
So, got an idea of what registers are and how are they defined/initialized? We will discuss about various registers one by one as required. Right now, we are concerned with only three registers, DDR, PIN and PORT.
Port Operation Registers
The following registers are related to the various port operations that we can perform with the GPIO pins.
- DDRx – Data Direction Register
- PORTx – Pin Output Register
- PINx – Pin Input Register
where x = GPIO port name (A, B, C or D)
DDRx Register
As I mentioned earlier, the GPIO pins are the digital I/O pins i.e. they can act as both input and output. Now, how do we know that the pin is an output pin or input? The DDRx (Data Direction Register) helps in it.
DDRx initializes the port. Have a look at it’s bit structure.
The ‘x’ in DDRx is just for representation. It is replaced by the corresponding port i.e. x = A, B, C, D. Say for the example shown in the diagram above
DDRC = (1<<DDC0)|(1<<DDC4)|(1<<DDC5)|(1<<DDC7);
This is equivalent to
DDRC = 0b10110001;
and as well as
DDRC = 0xB1;
and even
DDRC = (1<<0)|(1<<4)|(1<<5)|(1<<7);
So, did you get how to declare it? Suppose I would like to initialize my port B, then I would have written
DDRB = (1<<DDB0)|(1<<DDB4)|(1<<DDB5)|(1<<DDB7);
All right, now that we are done with the declaration, let me explain you what it does. Always remember, in the case of DDRx, 1 stands for output and 0 stands for input. In the following statement (given below), port C is initialized such that the pins PC0, PC4, PC5 and PC7 are output pins whereas pins PC1, PC2, PC3 and PC6 are input pins.
This is represented in the adjoining figure. The pins marked as input now has the capability to read the voltage level at that pin and then treat it as HIGH if it is above the threshold level, or else it will treat it as LOW. Generally, the threshold level is half the VCC.
Similarily, the pins marked as output have the capability to either become HIGH (voltage = VCC) or LOW (voltage = zero) as directed/written in the code.
DDRC = (1<<DDC0)|(1<<DDC4)|(1<<DDC5)|(1<<DDC7);
PORTx Register
The PORTx register determines whether the output should be HIGH or LOW of the output pins. In simplified terms, once the DDRx register has defined the output pins, we need to set them to give an output of HIGH or LOW. The PORTx register goes as follows.
The register declaration is similar to the DDRx register, except that we change the names, that’s all! One such example is given above in the diagram. The following declarations are one and the same.
PORTD = (1 << PD0)|(1 << PD3)|(1 << PD6); PORTD = (1 << 0)|(1 << 3)|(1 << 6); PORTD = 0b01001001; PORTD = 0x49;
Now, let’s consider the following statements:
DDRC = 0b10110001; PORTC = 0b10010001; OUTPUT = 0b10010001; /*This is not a C executable line, this line is just for explanation*/
The port C is initialized using the DDRx register. The highlighted bits correspond to the output pins. Now, just concentrate on the highlighted bits only. Since they are output pins, wherever I state ‘1’ in PORTC, that pin goes HIGH (1), giving an output voltage of VCC at that pin.
Now consider the following set of statements:
DDRC = 0b10110001; PORTC = 0b10010101; OUTPUT = 0b10010001; /*This is not a C executable line, this line is just for explanation*/
Once again, the bits highlighted in orange correspond to the output pins. So, whatever value (0 or 1) desired in the orange region is reflected in the output. Now, look at the magenta highlighted bit. Inspite of being set as HIGH in the PORTx register, the output is LOW. This is because that pin is initialized as an input pin by DDRx. Hence, PORTx cannot change the properties of that pin. Hence, in general, PORTx cannot modify the properties of a pin which is initialized as input by DDRx.
PINx Register
The PINx register gets the reading from the input pins of the MCU. The register goes as follows:
The register declaration procedure stands the same. Also note that the names of the bits of PORTx and PINx registers are same.
Now, let’s consider the following statements:
DDRC = 0b10110001; PINC = 0b01001011; INPUT = 0b01001011; /*This is not a C executable line, this line is just for explanation*/
Here, the highlighted bits correspond to the pins that are initialized as input by the DDRx. In the second line, the PINx register is defined. Well, this line is just to explain the concept, practically, we always use PINx as a condition (like in IF or in WHILE loop). As per the second statement, the PINx command reads the values only at the input pins.
Now, consider the following set of statements:
DDRC = 0b10110001; PINC = 0b01011010; INPUT = 0b01001010; /*This is not a C executable line, this line is just for explanation*/
Here, you can compare it with the example I gave for PORTx. Since the magenta-highlighted bit is an output pin, PINx cannot change it’s properties. Hence, in general, PINx cannot modify the properties of a pin which is initialized as output by DDRx and vice versa.
Example Code Snippet
Let’s demonstrate the use of the DDRx, PORTx and PINx registers from the following code snippet:
DDRC = 0x0F; PORTC = 0x0C; // lets assume a 4V supply comes to PORTC.6 and Vcc = 5V if (PINC == 0b01000000) PORTC = 0x0B; else PORTC = 0x00;
Code Explained:
- DDRC = 0x0F; is equivalent to DDRC = 0b00001111; This means that the pins PC0…PC3 are output pins (can be manipulated using PORTC) and pins PC4…PC7 are input pins (whose levels determine the value of PINC).
- PORTC = 0x0C; is equivalent to PORTC = 0b00001100; This means that the pins PC2 and PC3 have a HIGH voltage (Vcc = 5V) and pins PC0 and PC1 have LOW voltage (0V). The other pins have low voltage by default.
- if (PINC = 0b01000000) checks the input voltage at pin PC6. Since it is mentioned in the comment that a 4V is supplied to PORTC.6 (same as pin PC6), this condition is true (as 4 > 2.5, where 2.5V is the threshold, 5/2 = 2.5).
- Since the if condition is true, PORTC = 0x0B; is executed.
- If the if condition is not satisfied, PORTC = 0x00; will be executed.
We can also put it inside a while loop to run it continuously i.e. it always checks for the voltage at pin PC6, and the outputs at PC0, PC1 and PC3 go high only if the voltage at PC6 is greater than 4V.
DDRC = 0x0F; while(1) { // a condition of 4V supply to PORTC.6 and Vcc = 5V if (PINC == 0b01000000) PORTC = 0x0B; else PORTC = 0x00; }
To learn how to code and simulate using AVR Studio 5, visit this page.
So, here we end up with the port operations that can be performed with an AVR MCU. Though the concept has been explained using ATMEGA16/32, the concepts are equally good for any AVR MCU! Just go through the datasheet in order to get an idea of the registers.
Thank you for reading this! The comments’ box is down below! ;)
Hi,
I need your suggestion in avr coding.
I have 3 different frequency values that I have as input. A corresponding conversion factor for calculation of intensity is :
Light intensity (i)=frequncy (i)/100
for i=1,2,3Now I perform my calculation using 3 inputs LI(1), LI (2) and LI(3).
Ad(1) = Log10(2.383/LI(1))
Ad(2) = Log10(2.383/LI(2))
Ad(3) = Log10(2.383/LI(3))
net absorbance= avg. of all 3
How do I implement these calculation in atmega32. What should be the avrcode corresponding to identifying the inputs and doing this calculation to display the output?
You can include the
math.h
header file where you can have functions forlog
operations. DefineLI
andAd
asfloat
. Rest should be fine. Btw, where are you taking the input for the frequency – from ADC?heyy Mayank…i really appreciate the way u explain…i am making a breathlyzer using the butterfly board and want to get the input from the breathlyzer into that. how do i do that…a simple explaination would help
Hello Jagroop
Which breathlyzer are you using? If possible please send me the link of the datasheet of the breathlyzer you are using.
Hi Mayank,
Can you please help me out with this easy but very commonly used coding style ? Below you will find the code.
I already have read out “simulator using topic” written by you. After that I am trying to debug my code using the simulator but it is not working properly. Will you please help me out? I think this will be also very helpful to other newbies like me.
Problem: On the simulator when I am selecting bits on the PINB in the following way,
PINB=00000011 or PINB = 0xFF
I cannt see my output on PORTD in the following way,
PORTD = 0xFB;
rather I am having different output.
Thanks in advance. I will be waiting for your reply.
Code: http://pastebin.com/BpeKa57x
Hi Tonoy
I have simulated the same code and it was working fine. There are small things that need to be taken care off.
1. Please check that you have selected the proper simulation device, it should not be Atmega8 in the simulator, in the code it is mentioned clearly Atmega48PA, for ease you can use Atmega16 or 32.
2. Once the while loop starts executing, the very first if statement, which ever is true is considered and the output is of that case.
3. In this code, the if statement outcome is TRUE for any non zero value, it results FALSE only if there is zero.
4. While performing bitwise AND operation, if the resultant is non zero, it is executed else it goes to next condition
I would suggest you to do a manual calculation for the given input and you will find that for input 0b00000011 both the Case 2 and 3 are true but because of the else if structure only Case 2 will be executed.
If you delete the Case 2 and again execute then for the input 0b00000011 you will get the previously Case 3 i.e. 0xFC as output.
Now for the input 0xFF, the very first case if true, so it will not check any other case because of else if structure and the output will be 0xFE.
Now if you replace all the “else if ” with ” if ” statement then, the last True condition will fetch you the corresponding output.
You can easily watch this (in Atmel Studio) by enabling the Debugging mode and then Right click on driveBuffer variable and select “Add Watch”.
Hope this will solve your doubts. :-D
If you still find any difficulty, feel free to contact us….
hi…what can i use only one bit in a register in my codes,for example whats the true form for this cod : while (!(ADCSRA.4)) {…}
Hi Mr Gi!
You need to use bitwise operators. If you want to access 5th bit of ADCSRA register, then you can write:
(ADCSRA & 0b00010000)
I would suggest you to read the Programming 101 tutorial to know more about bitwise operators.
I’m having an issue where I have LEDs for output on port d, and also inputs – one of which operates on a threshold type level.
The problem is that as I monitor pin 7 to see if it has turned to a 1 (threshold reached/exceeded) I want to flip an LED on to show that this has happened – the detection works fine unless I alter the port d state to turn on this LED, and then suddenly the threshold changes.
I know it’s a bit hard to explain, but I am unsure how to put it better.
I am only changing the one bit on the port d to flip the LED on or off. If I leave the LED alone, the threshold detection works fine. Once the LED is on, POOF, the detector pin no longer detects the input threshold correctly. Turn off the LED, and POOF, all is OK again. I’m wondering if turning on the LED is switching on an internal pull-up resistor or something…
Hi Norman,
How do you know that without the LED your threshold detection works fine? I mean, how are you checking (without the LED) that your threshold detection works?
To add to it, I would ask you how have you powered up your microcontroller – i.e. the source of power – is it a battery, or through your computer, or using a power adapter? Because sometimes it might happen that if the power supply isn’t good or is inconsistent, then connecting the LED might draw a little more current, which would eventually reduce your effective Vcc, thus reducing your threshold level.
-Max
I know the detection works because there is a cube of 512 LEDs that respond to it. I simply want one single LED on the control board itself as well, but this seems to throw off the detection. I don’t think that there is some magil load difference between 512 and 513 LEDs.
Sorry, that should have said “magical” but I can’t find and “edit” function here.
Also, where’s the profile editor in this thing?
HI Norman,
May I know how the 512 LEDs are connected to your microcontroller? And how do they actually respond?
Video 1: https://www.youtube.com/watch?v=BZtdUuBj5Y8
Video 2: https://www.youtube.com/watch?v=YnDuVS66CZg
First video is how the LEDs respond, second one is how it’s hooked up
Okay, now that’s a pretty cool application! I am impressed, congrats!! I am sharing it on my Facebook page! :)
I got an overall idea how you have connected the 8x8x8 LEDs. And its responding pretty good to the analog input of the music. Now what I am wondering is how have you provided the audio/analog input to your microcontroller? Recommended method is to use the inbuilt ADC. As you mentioned earlier that you wanted to test whether the LED is responding to the threshold level or not. Why don’t you connect your input to the ADC pin, and then choose your desired threshold? Here is the ADC tutorial you might wanna refer to.
Because initially it wasn’t designed for Audio responsiveness.
It was meant to be pretty.
As such, ports that had a full 8 bits not being used for things like the ICSP or serial were all utilized for outputs.
The only I/O left on the chip are digital. D6 and D7 specifically.
So basically I want to mirror the input of D7 onto an LED on D6 – but whenever I try that, D7 changes it’s characteristics.
Here’s a video of it just “looking pretty” so you can see it’s original intention.
Video: https://www.youtube.com/watch?v=4SYGDunYwEw
Also, if you are going to put any of my videos on your facebook page, please reference my Instructables page on the construction of the cube. Thanks.
http://www.instructables.com/id/CHRs-8X8X8-LED-Cube-Revisited-with-improvements/
Sure. I will add that as well.
I gave up on this.
It works, and looks pretty.
Considering I am using a single digital bit input from the music source, I think it’s fantastic! LOL!
hey mayank very basic doubt i have…..can u explain me following statement…
TCCR0 |= (1<<CS00)
Hi Anup,
It simply means that we are OR-ing the CS00 bit of TCCR0 register with 1. Usually this results in setting of the CS00 bit to 1 (because of the OR operation) without affecting other bits of the register. Does that make sense?
thanks a lot….
THANK U SOO MUCH.. UR NOTES HELPED ME ALOT
Thanks Anchal, Keep Reading :D
DDR and PORT registers may be both written to, and read.
so i have question-
What is the use of reading these two registers؟
Masam,
You read from these two registers if you wanna know the previous value written to it. This condition usually doesn’t arise however. Makes sense?
hi , What is the initial value registers(ddr-port-pin) after reset
Initial value of DDR is zero.
Initial value of PORT is also zero.
But initial value of PIN is not defined. Whenever you try to read in using PIN, it takes in the real-world values at that instant.
while(1)
{
// a condition of 4V supply to PORTC.6 and Vcc = 5V
if (PINC == 0b01000000)
PORTC = 0x0B;
else
PORTC = 0x00;
}
i don’t understand-“a condition of 4v supply to PORTC and Vcc=5v”
when this code will work…. and what is threashold voltage?
Alamin,
Threshold voltage is the voltage above which a HIGH signal is considered HIGH.
For example, I am giving a chain of input pulses to the microcontroller with HIGH = 2.8v and LOW = 0.1v. Assuming that threshold voltage (Vth) = 2.5v, the HIGH input will be considered 1 whereas LOW input will be considered 0. If instead of that, I give input with HIGH = 2.2v and LOW = 0.1v, keeping the Vth same, both HIGH and LOW will be considered as 0 by the microcontroller. Makes sense?
Hi,
for my final year project i’m using Atmega 16 interfacing lcd. My purpose here is to display an analog input coming in to any one of the atmega adc inputs which is then to be displayed on the lcd. As i’m weak in coding can you please help me code this. I’m trying really hard since a week but to no success. your help will really be appreciated..
my email id is sidmody92@gmail.com
Hey Siddharth,
Sorry, but we can’t. We don’t solve people’s homework here. If you are weak in coding, I don’t understand why did you choose this project in the first place! My suggestion would be to go and learn C, and then visit my site again. Things will make more sense to you then. Thanks for stopping by! Good luck!
Your best bet is maybe to switch to the Arduino (ATmega328P) as it has an LCD communication library already which makes projects like yours extremely simple.
I’m sorry to disturb again. I have a few questions
1- what is difference between tri-state and pull up?
2- if the initial value of these registers(port and ddr) is not zero, what problems occur ?
3-Why do we sometimes pull up input pins?
4-Why dont we pull up output pins?
5-If we define a input pin to output pin,what problems occur?
I’d like to know this, too. I’m an experienced C programmer, and have done some assembly language, but microcontrollers are new to me. Scouring the product sheets is a little less than entirely enlightening.
Sorry guys, seems like I somehow missed to notice this comment.
1 – Tri-state includes three states – 0, 1, and z(high impedance). When you don’t connect a pin of a microcontroller to anything, and neither do you drive it high or low, it goes into high impedance state. Typically voltage in this state is not zero, but a little higher than zero. Pull-up on the other hand are used to compliment active low inputs (which I hope you know what they are).
2 – It will behave exactly the way you think! Try it out.
3 – See point 1. Whenever you have active low inputs, you’ll need to pull-up the input pins, otherwise they would go to high impedance state, which is not good.
4 – Can you? Try it and let me know. Surprise me! :)
5 – What do you mean by “define input pin to output pin”? This statement logically and literally doesn’t make any sense. Please clarify.
Thanks!
we have some Question , please help me !!!
1. Why do we sometimes pull up input pins?
2.what is internal pull up and what is external pull up pin,
3. which time we use internal or external pull up ?,
/* which is best please give me a brief explain */
Hi there – just thought I would drop an update as to what has happened with the project since I last came here looking for advice.
Yes, I am actually still using D6 for my audio trigger input.
If you want to skip the blah-de-blah-blah and go right to the audio input part of the demo, go to about 4:30 in the video.
Thanks for the update! :)
Hai, for the past ten years I was using only PIC Microcontrollers. Now I have started learning AVR. I use Atmel Visulal studio 6. In PIC I find very to ease to toggle a pin. like
while(1){
RC0=1;
delay1s()l
RC0=0;
delay1s();
}
Is there any easy method to toggle a pin in ATmega 16
I think you missed to notice this post.