Monday 9 July 2012

Introduction to C language bitwise operators and relevant truth tables. in AVR uC's (...cont)

So from the last time we got to know that:


-The OR operation is used between the variable that we want to change and a constant which is called a BIT MASK or simply the MASK. The mask is used to identify the bit that we want changed. #This time we will use hexadecimal for completion of the examples, instead of binary.
Imagine we have a variable by the name of state:

    
    state = state | 0x01;  */ we set bit 0  to 1 ( HIGH ) and store it back into state*/


PS- this can be made shorter in real programming practice 
    
    state |= 0x01;


-To clear a bit ( in this case bit 0), we have to use the AND operator and the NOT operator. 


    state = state & ~0x01;


PS-Again, this can be made shorter with

    state &= ~0x01;

So with this in mind, lets translate it into some code, that we can use in Arduino board for example, and flash the led on pin 13 ( bit 5 on Port B)



#include <avr/io.h>
#include <util/delay.h>

int main(void){
  DDRB = 0b00100000;    /* set bit 5 of data direction register to output */
  while (1) {
    PORTB |= (0x01 << 5);    */ we set bit 5  to 1 ( HIGH ) and store it back into PORT register */
    _delay_ms(100);    */ delay 100 ms, acording to <util/delay.h> header file */
    PORTB &= ~(0x01 << 5);    */ we clear bit 5 and store it back into PORT register */
    _delay_ms(100);
  }
}


PORTB |= (0x01 << 5);
So this sets bit 5 (and only bit 5) to 1. This is because it translates into:

PORTB PORTB | 0b00100000;

PORTB &= ~(0x01 << 5);
Translates into

PORTB &= ~ 0b00100000;

A mistake here would be

PORTB &= (0x01 << 5);

as this would set all bits to 0 ( therefore, all pins), and not just bit 5.
Translated would be

PORTB &= 0b00000000;
To add to this we still have the toggle a bit option, which can be useful if, in this case, the delay were to be the same for on and off states...
#include <avr/io.h> 
#include <util/delay.h> 

int main(void) { 
  DDRB = 0xFF; 

  while(1) { 
    PORTB ^= (1 << 7); 
    _delay_ms(250); 
  } 
} 

We can also change more than one of the bits, using the AND operator (" | "):

#include <avr/io.h>
#include <util/delay.h>

int main(void){
  DDRB = 0b00100000; /* set bit 5 of data direction register to output */

  while (1) {
    PORTB |= (0x01 << 5);
    PORTB &= ~( ( 1 << DDB3 ) | ( 1 << DDB4 ) ) ; /*this will only be used on the second loop, as at this time the register hasnt been set for these bits*/
    _delay_ms(100);
    DDRB|=  ( ( 1 << DDB3 ) | ( 1 << DDB4 ) ) ; /* pin 3 and 4 as outputs rest left in their original state */
    PORTB |= ( ( 1 << DDB3 ) | ( 1 << DDB4 ) ) ; /* we set bit 3 and 4 to 1 ( HIGH ) and store it back into PORT register */
    PORTB &= ~(0x01 << 5); /*clear the bit 5*/
    _delay_ms(100);
  }
}


I would advise, as a next step, to research about the _BV() Macro, in the  , from the avr-libc .BV stands for Bit Value). 
PS:New intro-tutorial about the _BV() http://dubworks.blogspot.co.uk/2012/07/introduction-to-c-language-bitwise_21.html

The _BV() macro is defined as:
 
#define _BV(x)   (1 << x) 

this allows: 

PORTC |= _BV(0);  // Set bit 0 only. 
PORTC &= ~(_BV(1));  // Clear bit 1 only. 
PORTC ^= _BV(7);  // Toggle bit 7 only.

No comments:

Post a Comment

Feel free to contact me with any suggestions, doubts or requests.

Bless