Direct port manipulation, using the digital ports

Fonte: direct-port-manipulation-using-the-digital-ports

Direct port manipulation, using the digital ports [tutorial part 3]

And how about a pattern of on,off,on,..?

DDRD = 0b11111111;    //All pins in PORTD are outputs
PORTD = 0b10101010;    //The small on,off,on,.. pattern

Now, the only thing left is how to read on pin so we can read data from sensors or even the mighty push-button, to read the state of a digital pin configured as input, we will used a third register called PINx, where again x is the port name of where the pin is located, so first using DDRx we say to the micro-controller that we want some pins as digital inputs, then using PINx we read their values, seems easy right, so lets dig into the code:

DDRD = 0b00000000;//All pins in PORTD are inputs
charmy_var = 0;   //Create a variable to store the data read from PORTD
my_var = PIND;    //Read the PORTD and put the values in the variable

Its as easy as it can be, and when compared with the Arduino digitalWrite and  Read functions, using direct port access you save space in flash and also win a lot of speed, because the Arduino functions can take more than 40 clock cycles to read or write a single bit in a port and the same time to read another single bit, and the code is pretty complex with a load of lines that occupy at least some 40 bytes, it might be a small save in flash but its a huge steep to speed up any program, but they are easy to use by the people that don’t understand a lot about programming/micro-controllers, so every implementation as its advantages and drawbacks, but lets continue.

Its a bit uncommon that you need to read or write a full port at each time, for example if you want to light a led, or to read a button we only need to use one pin, and writing all those bits one by one every time that we want to change a value in a PORT is a boring task, but the AVR lib-c as some little nice defined Px0..7 “words” where x is again the port that we want to use and 0..7 is the value of the individual pin of the said port, so to light a led we would do something like this:

DDRD = (1<<PD2);    //Pin 2 of portd is an output
PORTD = (1<<PD2);    //Pin 2 of portd as now the logic value 1

Or reading a button value:

DDRD = 0b11111101; //Pin 1 of PORTD is an input, all others are outputs
charmy_var = 0;   //Create a variable to store the data read from PORTD
//Read the PORTD pin 1 value and put it in the variable
my_var = (PIND & (1<<PD1));
We can also use this Px0..7 thing multiple times in a statement, for example in this piece of code, there will be some code executed only if two buttons are pressed at the same time:
 
DDRD = 0b11111100;        //Portd pins 0 and 1 are inputs, all the others are outputs
if(PIND & ((1<<PD0) | (1<<PD1))){
 //Code inside the if() statement will be executed when both buttons are high
}
I think that you are getting the point, but the bit manipulation tutorial will help a bit about this subjects

There is yet some more things that we can do with our input and output pins/ports that is very useful for i2c interfaces, and for example to use buttons, I’m talking about the pull-ups that our micro-controller and inside it and I will show you how you can enable them and why should you use them when using push-buttons.

When you have a push-button it can have two states, one is disconnected, and when you push it it will make the connection between the micro-controller pin and lets say, ground, but when it is disconnected there is nothing forcing a stable value in the input pin, to the untrained eye we could assume that the pin will be reading 1, because when we press the button it read 0, but the fact is that the pin can read either 1’s or 0’s because the pin is very sensitive to electro-magnetic noise, much like a little antenna, so we can solve this problem in two similar ways, one is to attach a resistor of 10Kohms or more between the Vcc(+5v) and the input pin, or just save some pennies and use the integrated pull-ups that our micro-controller as to offer, it also makes our circuits a bit simpler and that’s also a good thing.

To enable the pull-ups we need to do something that may seem a bit strange at the first look,because there is no dedicated register to enable or disable the pull-ups, their are enabled or disabled writing respectively 1 or 0 to the PORTx register when the DDRx register is configured as inputs, lets see some code to clarify this:

DDRD=0b00000000;  //All pins in PORTD are inputs
PORTD=0b00001111; //Pull-ups enabled in the pins 0,1,2 and 3 and pull-ups disabled in pins 4,5,6 and 7
char my_var=0;  //Create a variable to store the data read from PORTD
my_var=PIND;  //Read the PORTD and put the values in the variable

If you execute this code with nothing attached to PORTD, the four high bits of the my_var variable may have 1’s or 0’s or any possible combination of them because they are floating(acting like little antennas), but the four lower bits will read all 1’s because the pull-ups impose a weak 5v signal that is read as a 1 logic value.

In a basic sense this is all you need to know to master the direct port manipulation but the bit manipulation tutorial will teach you more things about nifty things like bitmask’s, AND,OR, NOT and XOR operations and how to set and clearer bits in a register and some nice tricks about the shift left and shift right operations, all good things to know as they can speed up your program and are handy when using the digital ports.

Lets now make a small test program that will take use of the digital inputs and outputs and also the pull-ups, because this as been a very theoretical tutorial its nice to come to the end and blink some leds!

This is the pseudo-code for our program, its intent is to read a switch and every-time that the switch is read it will toggle a led, so you press ounce and the led lights up, press again and the led goes off, and again from the start, this could be done using some if’s conditions but can be done in a single line using the powerful XOR(^) operator.

Main{
 Configure the pins, in thisexample code, I will use PORTD
 Infinite loop{
 Read button value
 If led is on and button==1 turn led off
 If led is off and button==1 turn led on
 }
}

Just one more thing(I know I’m always going a bit off-topic, but this one is important) when we use a button wired to a digital input we must be aware that a push-button doesn’t give a nice and clean transition from 0 to 1 of from 1 to 0, but instead the signal as some ringing and bouncing, this is due to the mechanical proprieties of the button and not a design flaw, the button as small metallic reed inside, and when we press it the reed closes and close the circuit between its input and output but this reed will oscillate a bit until it rests firmly in its stop, so we must take care of this, and as usual there are two ways, using a small capacitor near the button to debounce the value, or make this very same debouncing in code, which is easier to do when we have a lot of buttons and again is cheaper than adding a lot of caps to our circuit.

If you google the terms button debouncing you will find a great variety of ways to debounce buttons in code, the way that I will use here is the simplest of all, its just a small delay inserted between consecutive reads of the button, this is of course a blocking method because our micro-controller will just stop and sit there delaying for some miliseconds, there are smarter ways that use timers and other smart tricks but for 2-3 buttons and projects that don’t need super precise timing this is a commonly used method.

To do this delay I will use the built-in delay routines provided by the AVR lib-c.

So lets start coding, all the code is straight forward if you understood everything that was written above.

#include <avr/io.h> //This is our usual include
#define F_CPU 16000000UL //This says to the compiler at what frequency our Atmega is running, in this case its 16Mhz
#include <util/delay.h> //The delay functions/routines
uint8_t readButton(void); //Declaration of the readButton function

intmain(void) {
 DDRD &= ~(1<<PD2); //Configure PORTD pin 2 as an input
 PORTD |= (1<<PD2);//Activate pull-ups in PORTD pin 2
 DDRB |= (1<<PB5);//Configure PORTB pin 5 an output, this is the 
 digital 13 in the Arduino that as the built-in led
 while(1) { //Infinite loop
 if(readButton()==1) { //Verify the button state
 PORTB ^=(1<<PB5);//This is the above mentioned XOR that toggles the led
 }
 _delay_ms(250); //Delay between consecutive button presses
 }
}

uint8_t readButton(void) {
 if ((PIND & (1 << PD2)) == 0) { //If the button was pressed
 _delay_ms(25);
 } //Debounce the read value
 if ((PIND & (1 << PD2)) == 0) { //Verify that the value is the same 
 that what
 was read
 return1;
 } //If it is still 0 its because we had a button press
 else { //If the value is different the press is invalid
 return0;
 }
}

I think that there is no need to show how to create the project in AvrStudio at this point, but if you have any doubts consult the other tutorials or leave a comment, and don’t forget to press the reset button when you want to upload your code.

I also don’t have a circuit schematic but I can get one if someone requests it, or when I have the time to make one, the led used is the built-in led that Arduino as in Digital pin 13, and the button is also easy, you connect one of the legs of the button to the PORTD2 pin, that is digital pin 2 and the other leg of the button you connect to the ground.

I have done some corrections to the text, and here is the code in an Avr Studio project ready to compile and upload:

http://code.google.com/p/avr-tutorials/downloads/detail?name=port.zip

Thanks for reading and don’t forget to comment anything that you want, and good programming!