Tuesday, 31 July 2012

Useful Info about the AT Mega 48/88/168/328

Some useful charts with info i found on the net (courtesy of web.alfredstate.edu )


ASCII Conversion Chart - 

//web.alfredstate.edu/weimandn/miscellaneous/ascii/ascii_index.html


A handy Decimal - Binary - Octal - Hex - ASCII Conversion Chart - http://web.alfredstate.edu/weimandn/miscellaneous/ascii/ascii_index.html


















Sunday, 22 July 2012

Introduction to C language bitwise operators: " _BV " Macro (...cont)



/* The  _BV() is a compiler macro defined as #define _BV( bit ) ( 1<<(bit) ) in 
 <avr/sfr_defs.h> which was included already indirectly through <avr/io.h>. 
 It stands for Bit Value where you pass it a bit and it gives you the byte value 
 with that bit set. 
 As we seen already, in the C language one assigns and tests bits using bit 
 operators, the assign operator, and the concept of bit masks: */
PORTC |= 0x01;  // Set bit 0 only. 
PORTC &= ~0x01; // Clear bit 0 only. 
PORTC ^= 0x01;  // Toggle bit 0 only. 
PORTC & 0x01;  // Test bit 0 only. 
PORTC |= 0x80; // Set bit 7 only. 

/*Using macros make this easier to read. The _BV() macro in avr-libc takes a number as   the argument and converts it to the appropriate bit mask. (The BV stands for Bit Value).   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. /*Using bit operators, one can do multiple, non-contiguous bits at a time: */ PORTC |= (_BV(0) | _BV(2) | _BV(7));  // Set bits 0,2,7 PORTC &= ~(_BV(1) | _BV(2) | _BV(6));  // Clear bits 1,2,6 PORTC ^= (_BV(5) | _BV(3));   // Toggle bits 3,5 /*The | symbol between each _BV macro statement means logically OR. */ /*(_BV(0) | _BV(2) | _BV(7));  logically OR’s the bits together   e.g*/ /* Name        bit7  bit6  bit5  bit4  bit3  bit2  bit1   bit0   _BV(0)  =    0      0    0     0      0     0    0      1   _BV(2)  =    0      0    0     0      0     1    0      0   _BV(7)  =    1      0    0     0      0     0    0      0   or’ed   =    1      0     0     0     0     1     0      1   */ /*   A further example is */
UCSRB = _BV(TXEN)|_BV(RXEN)|_BV(RXCIE); /* tx/rx enable, rx complete*/


/*  In each iteration of the infinate loop (while (1)) we are using   standard C methods for setting and clearing the PC0 bit followed by   1000 mS delay between each set and each clear. Let's take a closer   look at each of those.   The first, is to clear the bit using PORTC &= ~_BV(PB0);   which turns off the PIN (remember that the PIN is connected to   VCC, so a logical 1 output results in little to no   voltage across the PIN).   Remember that our _BV macro returns the bit set in byte form,   in this case, 0x01 or 00000001b. So, the statement PORTB &= ~_BV(PB0);  is actually PORTB &= ~0x01;.   The bitwise operator ~ will "not" the value first, which results   in 11111110b. So now we basically have PORTB &= 0xFE;. With this,   the bit in position 0, PB0, will ALWAYS be cleared after this   statement without effecting the other bits in the byte. So   regardless of the value currently in PORTB, only the bit we're   clearing is changed. */
#define F_CPU 16000000UL /* 16 MHz Internal Oscillator */

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

/* function for long delay */
void delay_ms(uint16_t ms) {
  while ( ms )
  {
    _delay_ms(1);
    ms--;
  }
}

int main (void)
{
  /* PB0 is digital output */
  DDRB = _BV (0);               

  /* loop forever */
  while (1)
  {
    /* clear PB0 on PORTB (digital high) and delay for 1 Second */
    PORTB &= ~_BV(0);
    delay_ms(1000);

    /* set PB0 on PORTB (digital low) and delay for 1 Second */
    PORTB |= _BV(0);
    delay_ms(1000);
  }
}

Saturday, 21 July 2012

DubWorks Studio delay for dub and reggae productions

Studio delay ( DubWorks model, based around the Princeton Technologies  PT2399, redesigned for dub and reggae productions ) getting ready to leave premises..
This model was redesigned so it could give me all the sounds a good reggae and dub production needs( meaning old school grit and sounds)
This one is going to Brad The Manor, in London .



MCP4725 DAC part 2


Sinewave with 360 steps wavetable , using the PROGMEM, as configured in the
  pgmspace.h library, variable in time by the analog in of a pot, just as 
the example before.

/* Includes */
#include <Wire.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

/* Wavetables */
#include "sin360.h"

/* setup() */
void setup()
{
  int potRead = 0; //potentiometer read in pin Analog 0
  long potValue ; //value for potentiometer read 
  pinMode (potRead, INPUT);
  /* Enable Internal pull-up resistors through software (not required with a single module on the I2C bus) */
  pinMode(A4, OUTPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, OUTPUT);
  digitalWrite(A5, HIGH);
  /* Init bus I2C */
  Wire.begin();
}
/* loop() */
void loop(){
  /* Variables  */
  static uint16_t sample, i;
  /* Look-up table (aka wavetable) */
  for(i = 0; i < 360; ++i) {
    /*  Read a sample of the wavetable */
    sample = pgm_read_word(sin360 + i);
    int potRead = 0;     //potentiometer read in pin Analog 0
    long potValue ;     //value for potentiometer read 
    potValue = analogRead(potRead);
    //we map amalog 0-1023/1-4096 for DAC:
    potValue = map(analogRead(potRead), 0, 1023, 1, 4096); 
    /*  Starts communication with the MCP4725 */
    Wire.beginTransmission(B1100000);
    /* Sending the command "DAC Update Register" */
    Wire.write(B1000000);
    /*  Sending the 12-bit data */
    Wire.write((sample & 0xFF0) >> 4); // The 8 bits in first
    Wire.write((sample & 0xF) << 4); // Then the 4 bits of Least Significant Bit- LSB
    _delay_us(potValue); // delay 30 ms, acording to <util/delay.h
    /* Stop  commnication  MCP4725 */
    Wire.endTransmission();
  }
}

"sin360.h"

uint16_t sin360[] PROGMEM = {
  0, 1, 2, 4, 7, 11, 15, 19, 25, 31, 37, 44, 52, 60, 69, 79, 
  89, 100, 111, 123, 135, 149, 162, 176, 191, 207, 223,
  239, 256, 274, 292, 311, 330, 349, 370, 390, 412, 433, 456, 
  478, 502, 525, 549, 574, 599, 625, 650, 677, 704, 731, 758, 
  786, 815, 843, 872, 902, 932, 962, 992, 1023, 1054, 1085, 
  1117, 1149, 1181, 1214, 1247, 1280, 1313, 1346, 1380, 1414, 
  1448, 1482, 1517, 1551, 1586, 1621, 1656, 1691, 1726, 1762, 
  1797, 1833, 1868, 1904, 1939, 1975, 2011, 2046, 2047, 2082, 
  2118, 2154, 2189, 2225, 2260, 2296, 2331, 2367, 2402, 2437, 
  2472, 2507, 2542, 2576, 2611, 2645, 2679, 2713, 2747, 2780, 
  2813, 2846, 2879, 2912, 2944, 2976, 3008, 3039, 
  3070, 3101, 3131, 3161, 3191, 3221, 3250, 3278, 3307, 3335, 
  3362, 3389, 3416, 3443, 3468, 3494, 3519, 3544, 3568, 3591, 
  3615, 3637, 3660, 3681, 3703, 3723, 3744, 3763, 3782, 3801, 
  3819, 3837, 3854, 3870, 3886, 3902, 3917, 3931, 3944, 3958, 
  3970, 3982, 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 
  4062, 4068, 4074, 4078, 4082, 4086, 4089, 4091, 4092, 4093, 
  4094, 4093, 4092, 4091, 4089, 4086, 4082, 4078, 4074, 4068, 
  4062, 4056, 4049, 4041, 4033, 4024, 4014, 4004, 3993, 3982, 
  3970, 3958, 3944, 3931, 3917, 3902, 3886, 3870, 3854, 3837, 
  3819, 3801, 3782, 3763, 3744, 3723, 3703, 3681, 3660, 3637, 
  3615, 3591, 3568, 3544, 3519, 3494, 3468, 3443, 3416, 3389, 
  3362, 3335, 3307, 3278, 3250, 3221, 3191, 3161, 3131, 3101, 
  3070, 3039, 3008, 2976, 2944, 2912, 2879, 2846, 2813, 2780, 
  2747, 2713, 2679, 2645, 2611, 2576, 2542, 2507, 2472, 2437, 
  2402, 2367, 2331, 2296, 2260, 2225, 2189, 2154, 2118, 2082, 
  2047, 2011, 1975, 1939, 1904, 1868, 1833, 1797, 1762, 1726, 
  1691, 1656, 1621, 1586, 1551, 1517, 1482, 1448, 1414, 1380, 
  1346, 1313, 1280, 1247, 1214, 1181, 1149, 1117, 1085, 1054, 
  1023, 992, 962, 932, 902, 872, 843, 815, 786, 758, 731, 704, 
  677, 650, 625, 599, 574, 549, 525, 502, 478, 456, 433, 412, 
  390, 370, 349, 330, 311, 292, 274, 256, 239, 223, 207, 191, 
  176, 162, 149, 135, 123, 111, 100, 89, 79, 69, 60, 52, 44, 
  37, 31, 25, 19, 15, 11, 7, 4, 2, 1, 0
};

Friday, 20 July 2012

PIC16F887 Hitech C Basic

I thought i'd share this here, as might help someone starting to dive into the PIC architecture.
I always been afraid of PICs compared with AVR, as the learning curve is much higher.
But, thanks to a few friends in a forum ( http://lusorobotica.com ). i lost the fear and even dug deep into Assembler... hmmm, you say !! YES !!
When trying to compile a basic example, i realized that wouldnt allow me to compile unless _XTAL_FREQ 4000000 is #defined.
Chip is PIC16F887 (
44-Pin Demo Board from Microchip, DM164120-2 ), compiler Hitech C Basic in MPLab IDE with a PickIt2 programmer ( i said it all...in one breath ! You know what i mean with PICs being scary, right ?!
, 


#include<htc.h>
#include<pic.h>
#define _XTAL_FREQ 4000000 

//__CONFIG(FOSC_HS|WDTE_OFF|PWRTE_ON|LVP_OFF|DEBUG_OFF);
__CONFIG(FOSC_HS|WDTE_OFF|PWRTE_ON|BOREN_OFF|LVP_OFF|CPD_OFF|WRT_OFF|DEBUG_OFF|CP_OFF);

void main(void)
{
 TRISD=0;

while(1)
 { 
  PORTD=0x01;   //turn on LED at RD0. 
             __delay_ms(100);
             PORTD=0x00;   //turn off LED at RD.
  PORTD=0x02;   //turn on LED at RD1.  
             __delay_ms(100);
  PORTD=0x00;   //turn off LED at RD.
  PORTD=0x04;   //turn on LED at RD2. 
  __delay_ms(100);
 } 
} 

12 bits Digital to analog (DAC) MCP4725: variable (basic)sample


A ramp up                      
A round sine                          


#include <Wire.h>
#include <util/delay.h>
// Device = 96;  This hardwired into the IC and the BoB, in other words, it is a given.
#define MCP4725_DID 96 // define device id - see datasheet
int sample = 0 ; //sample variable
int OOMPH[64] = {
  2, 2, 22, 61, 119, 196, 291, 402, 530, 672, 827, 994, 1172,
  1357, 1549, 1747, 1947, 2147, 2347, 2545, 2737, 2922, 3100, 3267, 3422, 3564, 3692, 3803,
  3898, 3975, 4033, 4072, 4092, 4092, 4072, 4033, 3975, 3898, 3803,
  3692, 3564, 3422, 3267, 3100, 2922, 2737, 2545, 2347, 2147, 1947,
  1747, 1549, 1357, 1172, 994, 827, 672, 530, 402, 291, 196, 119, 61,
  22, } 
;
/* uncomment to use */
/* int sintab [64] = {
 2147 , 2347, 2545, 2737, 2922, 3100, 3267, 3422, 3564, 3692, 3803,
 3898, 3975, 4033, 4072, 4092, 4092, 4072, 4033, 3975, 3898, 3803,
 3692, 3564, 3422, 3267, 3100, 2922, 2737, 2545, 2347, 2147, 1947,
 1747, 1549, 1357, 1172, 994, 827, 672, 530, 402, 291, 196, 119, 61,
 22, 2, 2, 22, 61, 119, 196, 291, 402, 530, 672, 827, 994, 1172,
 1357, 1549, 1747, 1947} ;*/

/* int ramp_up [64] = { 
 2347, 2545, 2737, 2922, 3100, 3267, 3422, 3564, 3692, 3803,
 3898, 3975, 4033, 4072, 4092, 2, 22, 61, 119, 196, 
 291, 402, 530, 672, 827, 994, 1172, 1357, 1549, 1747, 
 1947, 2347, 2545, 2737, 2922, 3100, 3267, 3422, 3564, 3692, 
 3803, 3898, 3975, 4033, 4072, 4092, 2, 22, 61, 119, 
 196, 291, 402, 530, 672, 827, 994, 1172, 1357, 1549, 
 1747, 1947, 2347, 2545 } ; */
void setup()
{
  int potRead = 0; //potentiometer read in pin Analog 0
  long potValue ; //value for potentiometer read 
  pinMode (potRead, INPUT);
  Wire.begin() ;
} 


void loop()
{
  int potRead = 0;     //potentiometer read in pin Analog 0
  long potValue ;     //value for potentiometer read 
  potValue = analogRead(potRead);
  //we map amalog 0-1023/1-19000 for DAC:
  potValue = map(analogRead(potRead), 0, 1023, 1, 19000); 
  // Start transmission
  Wire.beginTransmission(MCP4725_DID); //device adress
  Wire.write(64);                     // cmd to update the DAC
  Wire.write(OOMPH[sample] >> 4);        // the 8 most significant bits...
  Wire.write((OOMPH[sample] & 15) << 4); /* the 4 least significant bis...*/
  Wire.endTransmission();
  sample = (sample + 1) &63 ;
  _delay_us(potValue); // delay 30 ms, acording to <util/delay.h
}





Simple siren generator for Arduino.

This is a simple siren generator, as mentioned.
We will only improve on this...
Graphics and schematic by Fritzing (http://fritzing.org/ )


/*
 * Siren Generator with adjustable rate
 * Version 0.1
 * Author: Ras B / Keith Gray 
 * Created: 3/5/12
 */
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int SPKR_PIN = 10; //assigning pin 10 to the speaker
const int MAX_FREQ = 10000; //max frequency of the siren wail
const int MIN_FREQ = 3700; //min frequency of the siren wail

int potRead = 0; //potentiometer read in pin Analog 0
int potValue ; //value for potentiometer read 
int FREQ_SKIP ; //frequency skip variable
int DELAY = potValue; // variable for delay linking it to the potValue variable

void setup()
{
  pinMode(SPKR_PIN, OUTPUT);
  pinMode (potRead, INPUT);

  updateDisplay();
  updatefreqSkip();
}
void updateDisplay() //creating a function we can call that updates the LCD
{
  lcd.clear();
  // adding some name to the values we want to display:
  lcd.print("Rate=");
  // calling the values we want to display:
  lcd.print(potValue);
  lcd.print(" Freq=");
  // Print the value of the frequency skip
  lcd.print(FREQ_SKIP);
}

void updatefreqSkip() //creating a function we can call that updates the FREQ_SKIP
{
  if (potValue >= 8)
  { 
    FREQ_SKIP = 10 ;
  }
  else
  {
    FREQ_SKIP = 30 ;
  }
}


void loop()
{
  updatefreqSkip();

  potValue = analogRead(potRead);
  potValue = map(analogRead(potRead), 0, 1023, 0, 10);

  updateDisplay();

  unsigned long siren_start_time = millis();
  int freq;
  updatefreqSkip();
  updateDisplay();
  do
  {
    for (freq=MIN_FREQ; freq<=MAX_FREQ; freq+=FREQ_SKIP)
    {
      analogRead(potRead);
      DELAY = potValue;
      tone(SPKR_PIN, freq);
      delay(DELAY);
    }
    updateDisplay();
    updatefreqSkip();

    for (freq=MAX_FREQ; freq>=MIN_FREQ; freq-=FREQ_SKIP)
    {
      analogRead(potRead);
      DELAY = potValue;
      tone(SPKR_PIN, freq);
      delay(DELAY);
    }
    updateDisplay();
    updatefreqSkip();
  }
  while (millis() - siren_start_time < 5000L);
}


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.

Thursday, 5 July 2012

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

As we seen in the last tutorial, sometimes bitwise operators are needed, in order to change just a pin, shit a bit, etc..
So lets start by revising quickly the logic truth tables, so we understand a bit better what we on about.

There are logical operators called AND, OR, NOT and XOR among others, that are the ones we will discuss now.
*While in digital systems, the gates work with 2 inputs at least, here we have to work with the 8 bits ! 

Example AND binary number operation (the "&" is used in C programming for AND):


01001011 &
10001101
     =
00001001

Example OR binary number operation ( the character " | " is the ORused in C programming )

01001011 |
10001101
     =
11001111



Example XOR - Exclusive OR - binary number operation ( the character   "^"  is the ORused in C programming )
    01001011 ^
    10001101
    equals
    11000110
    
    
    
    
    * The NOT operator inverts the sense of the bit, so a 1 becomes a 0, and a 0 becomes a 1.
    

       |       =     bit OR
       &     =    bit AND
       ~      =    bit NOT
       ^      =    bit EXLUSIVE OR (XOR)
      <<    =    bit LEFT SHIFT
      >>    =    bit RIGHT SHIFT

    These operators work on bits and not logical values. Take two 8 bit bytes, combine with any of these operators, and you will get another 8 bit byte according to the operator's function. These operators work on the individual bits inside the byte.

    A truth table helps to explain each operation. In a truth table, a 1 bit stands for true, and a 0 stands for false.


    
    
So, we already know what the <avr/io.h> does, but the #include <util/delay.h> hasnt been spoken about; Just like the name implies, the delay.h will provide us with a way to create delays in our program (see http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html for more details). And Just like the name implies, the delay.h will provide us with a way to create delays in our program.
    So we know we have DDRD = 0b11111110
We need only to change the one bit: the pin 0 bit.If we look at the ways above, we can do this with the OR operator, using a binary mask.
    DDRD = DDRD | 0b00000001;
This will "OR" it to a mask. The mask is: 0b00000001. While this looks like the actual binary number, if the previous DDRD was, say, 0b01001010, then doing an OR to that with our mask would be: 0b01001010 | 0b00000001 = 0b01001011. So this result only the pin 0 bit has changed!
This statememt can be further compressed in C++:
DDRD |= 0b00000001;


So why "DDRD |= 1 << PIND0"?
1 << PINB0 is the act of creating the mask. The "1" represents what will be inserted into the mask, the << is a left shift operator. It does EXACTLY what it says, and PIND0 is a number of positions that the "1" will shift left. In essence, PIND0 is just equal to 0. So, you start with a 0b00000000, and you add a "1" to make 0b00000001 and then you shift it left 0 positions. So you are left with 0b00000001, the same number from above. So, what if it was PIND4? The statement would be: 1 << PIND4. The "1" would be left shifted 4 times resulting in: 0b00010000. Remember, we are using a zero index, so there is four 0s after the 1.


We know how to set a specific bit in the binary number, but we don't know how to toggle a bit ( change it to 1 if it is a 0 and vice versa).

    #include <avr/io.h>
    #include <util/delay.h>
    int main(void)
       {
            DDRB |= 1 << PIND0; 
             while (1)
             {
               PORTB |= 1 << PINB0;
                _delay_ms(100);
               PORTB &= ~(1 << PINB0);
               _delay_ms(100);
              }
        }
    If the delay is going to be the same for on and off, we could shorten the previous four lines to only two and take advantage of the XOR operation.
    The " ^ " Bitwise operator toggles the bit, so that if it is a 1 will then become a 0, and vice versa

    #include <avr/io.h>

    #include <util/delay.h>

    int main(void)

    {

      DDRB |= 1 << PIND0; 

      while (1)
      {
        PORTB ^= 1 << PINB0;  */ The " ^ " Bitwise operator toggles the bit, so that if it is a 1 will then become a 0, and vice versa*/
    _delay_ms(100);
      }
    }
    *(...to be continued)

Sunday, 1 July 2012

AVR- Intro to I/O ports in C Language instead of Arduino/Processing Language - (...Cont)


Now lets imagine we need only some of the ports as inputs, the rest as outputs.
Lets assume the port D pins 0-4 to be defined as outputs, the remaining pins 5-7 will function as inputs. For this purpose it is necessary to enter in the port D data direction registers DDRD the following bit configuration :


// as defined in included avr/io.h DDRD  
# include <avr/io.h>
 
int main ( ) 
{ 
  // Set the bits 0,1,2,3 and 4 
  // binary hexadecimal 1F = 00011111 preceded by 0x as stated before
  DDRD = 0x1F;    
 
  // Clear alternative in binary system would be
  // DDRD = 0b00011111;
 
  // Full notation: identical functionality, more typing
  // But clear and self-explanatory:
  // DDRD = (1 << DDD0) | (1 << DDD1) | (1 << DDD2) | (1 << DDD3) | (1 << DDD4); */


So , Maybe now is time to mention something else. We dont necessarily need to refer to the 
pins always through the whole port. As you can probably notice in the last alternative 
example above, you can also use DDD1 or DDB1 if it were in the Port B; PDx, and PINDx, DDDx for the port D or maybe simpler would be also PAx, PBx, PCx, etc... For the compiler
, the expressions (1 << PD5), (1 << DDD5) and (1 << PIND5) are identical to (1 << 5) 
(more precisely, the preprocessor replaces the expressions (1 << PC7). to .(1 << 7)).
All this is specified in the file io.h of the avr-libc and serves only to improve code readability. *(Check last example in this post for a practical example of code)
You can always check also the file iom328p.h under /* Registers and associated bit numbers */ for a better clarification ( or the file corresponding to the chip you might be using).




So , now, lets look at other examples based on these options :  

...
   // All pins of Port D defined as outputs:
  DDRD = 0xff; 
  // Pin0 again left as input and the rest in their original state: 
  DDRD &= ~ ( 1 << DDB0 ) ,
   // pin 3 and 4 as inputs and the rest in their original state:  
  DDRD &= ~ ( ( 1 << DDB3 ) | ( 1 << DDB4 ) ) ,
   // pin 0 and 3 as outputs and rest in their original state: 
  DDRD |= ( 1 << DDB0 ) | ( 1 << DDB3 ) ;
   // All input pins: 
  DDRD = 0x00;

...

So based on what we have learned until now, lets set the pin 5 of port D to output

// as defined in included avr/io.h DDRD : 
# include <avr/io.h>
 
...
    PORTD = 0x10; /* better would have been PORTD = (1 << PD4) */
 
    // Clear alternative would be binary notation 
    PORTD = 0b00010000;     /* direct assignment - clear */
   

PS: Note that the bits are always to be counted from 0 , so the least significant bit is 
bit number 0, not number 1 bit .
So now lets imagine we need to change an output pin, but want to leave the rest unchanged ( see next tutorial "Introduction to C language bitwise operators and relevant truth tables". )

/* as defined in included avr/io.h DDRD : */
# Include <avr/io.h>
...
    PORTD = PORTD | 0x10; /* better would be : PORTD = PORTD | (1 << PD5) */ 
    /* simplified by using the | = operator: */ 
    PORTD | = ( 1 << PD5 ) ;
 
    /* Also several pins "simultaneous": */ 
    PORTD | = ( 1 << PD4 ) | ( 1 << PD5 ) ; /* pins PD4 and PD5  "high" */

Turn those same pins to LOW is somewhat analogous
/* as defined in included avr/io.h DDRD : */
# include <avr/io.h>
...
    PORTB & = ~ ( 1 << PB2 ) ;  /* delete Bit 2 and thus sets pin PB2 in PORTB  to low */
    PORTB & = ~ (  ( 1 << PB4 ) | ( 1 << PB5 )  ) , /* Pins PB4 and PB5  pin "low" */

Now, we should also note the fact that If the initial state of outputs is critical, the sequence must be noted at which the data direction (DDRx) is set and the output value (PORTx) set:
For output pins, which are to be initialized "HIGH" with initial value:
  • First, the bits in the register set PORTx
  • then set the data direction to output
Hence the sequence obtained for a pin that was previously configured as input with pull-up switched off:
  • set PORTx: active internal pull-up
  • DDRx set: output ("high")
In the first sequence DDRx and then  PORTx there may be a short "low pulse", and cause  the external pull-up resistors to be bypassed. The (unfavorable) sequence: input -> set DDRx : output ( on "low" because of PORTx after reset 0) -> set PORTx: output to high. As this might come to influence your design ( or not ) I would advise you to check the datasheet section Configuring the Pin on page 78 ( english version) 
http://www.atmel.com/Images/doc8161.pdf .

#include <avr/io.h>
#include <util/delay.h>
int main(void)         // For now we are just going to turn a led on */

{
  DDRB = 0b00100000;   // Data Direction Register setting pin0 to output and the remaining pins as input
  while(1)
  {
    PORTB = 0b00100000 ; // Set pin PB5 = pin13 no Arduino Uno to 5 volts
    _delay_ms (1000);
   PORTB = 0b00000000 ;
    _delay_ms (1000);
  }

  // * Never reached * /
  return  0 ;
}
or another way would be

#include <avr/io.h>
#include <util/delay.h>
int main(void)// For now we are just going to turn a led on */ {  DDRB = 0b00100000;   // Data Direction Register setting pin0 to output and the remaining pins as input
  while(1)
  {
    PORTB = 0b00100000; 
    _delay_ms (1000);
    PORTB = 0b00000000; 
    _delay_ms (1000);
    // Code would be in here if needed to execute over and over and over ... endlessly */
  }
  // * Never reached * /
  return  0 ;
}
That is all for now, i hope this will have helped you to understand better the intricacies 
of the AVR C with AVR GCC !
PS- this is in no way a detailed ultimate tutorial, but more the result of my understanding of it !! 
So dont take my word for definite as there will be things to add, and more things
that i havent even touched . Remember i come from the Arduino perspective, and 
for now just wanna deepen my knowledge, so i can pass to AVR GCC when ready !



Reference



http://elecrom.wordpress.com/2008/02/12/avr-tutorial-2-avr-input-output/

http://www.nongnu.org/avr-libc/user-manual/modules.html

http://www.mikrocontroller.net/articles/AVR-Tutorial ( Assembler, in German
but a lot of info to be dranked from here !

...too much time on my hands?

WHAT ?!? What do u mean i have too much time on my hands? Lol