Pages: [1]   Go Down
Author Topic: Basic understanding of direct port manipulation code  (Read 1524 times)
0 Members and 1 Guest are viewing this topic.
Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have been trying out some basic direct port manipulation and connected 14 LED’s to digital pins 0 to 13 via 220 ohm resistors.
Purely as a learning exercise I was lighting each LED on / off, left to right by accessing the required pin location from an array. I am using a for loop to do this, firstly from the D port and then the B port. Here is the code I am using .
Code:
  int i = 0;
 
  void setup()
  {
 
    DDRD = B11111111; // Set all the pins to output in port D
    DDRB = B00111111; // Set all the pins to output in port B   
  }
 
  byte digit[] = {B10000000,B01000000,B00100000,B00010000,B00001000,B00000100,B00000010,B00000001};
 
 
  void Krider14_L_to_R()
  {
    for(i = 0; i <= 7; i++)
 
    {
      PORTD = digit[i];
      delay(1000);
      PORTD = 0;
    }
    {
      for(i = 7; i >= 0; i--)
 
      {
        PORTB = digit[i];
        delay(1000);
        PORTB = 0;
      }
    }
  }
 
  void loop()
  {
 
    Krider14_L_to_R();
 
  }
It all works as required, but what I cannot grasp is this There are eight elements in the digit array, which is allocated to firstly the D port and then the B port. But there are only seven pins in each port.

What am I not understanding. Thank you if you can clarify this for me.

Logged


SE USA
Offline Offline
Faraday Member
**
Karma: 40
Posts: 3783
@ssh0le
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

theres 8 pins on a 328 for ports B and D



PB0 - PB7
PD0 - PD7

and even if they were not there you cant make a 7 bit byte in a 8 bit based architecture (for instance the C port which on this chip happens to have PB0-PB6 broken out to 7 pins though somewhere in the silicon of the chip there is an 8th pin)
« Last Edit: March 02, 2013, 07:46:55 pm by Osgeld » Logged


Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for that Osgeld. So I am able to use PB 6 and PB 7 which are pins 9 and 10 on the Atmega 328P. I cannot seem to find which pins these correspond to on the Arduino Uno R3. Any suggestions please.

« Last Edit: March 02, 2013, 09:16:42 pm by Pedro147 » Logged


Left Coast, CA (USA)
Online Online
Brattain Member
*****
Karma: 331
Posts: 16517
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for that Osgeld. So I am able to use PB 6 and PB 7 which are pins 9 and 10 on the Atmega 328. I cannot seem to find which pins these correspond to on the Arduino Uno R3. Any suggestions please.

Those pins are not defined in the standard arduino pin mapping as they are used to support the 16 Mhz resonator wired to the chip to set the clock rate for the chip. If you were to change the fuse settings of the chip to utilize the chip's internal R/C clock source then you could utilize those pins using direct port manipulation.

Lefty
Logged

Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Lefty. Yes I just saw that they are used for the crystal, and I seem to remember reading that the internal clock is 8 Mhz does this pose a big problem or generally only with situations requiring more accurate timing? As I stated in my original post I am just doing this to learn more, and I do not have a particular project that requires this. Thank you to both you and Osgeld for your help Pedro.
Logged


Left Coast, CA (USA)
Online Online
Brattain Member
*****
Karma: 331
Posts: 16517
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Lefty. Yes I just saw that they are used for the crystal, and I seem to remember reading that the internal clock is 8 Mhz does this pose a big problem or generally only with situations requiring more accurate timing? As I stated in my original post I am just doing this to learn more, and I do not have a particular project that requires this. Thank you to both you and Osgeld for your help Pedro.

 The internal R/C clock is not a real precise one, although there are ways to tweak it with internal adjustment values written to some special registers I guess, never tried it. Nothing wrong with using the internal R/C for applications not requiring high timing accuracy. But things like serial communications, especially at the higher baud rates, do justify using an external resonator or using the internal R/C clock source. Trying to keep track of elapsed time over longer spans using millis() will definitely show a difference in the clock accuracy.

 The Atmel datasheets for the specific AVR chip is the best source to learn all the gory details about the different clock options one has and how best to utilize them.

Lefty
Logged

Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Lefty but in regard to my initial query, I am still not happy with my level of understanding with this situation. I know, I am displaying some obsessive compulsive tendancies here, oh well it keeps me off the streets  smiley-cool
I just cannot see how, in the initial posted code, there is an array of eight elements being accessed firstly by the D port (7 pins) and then the B port (another 7 pins) and this is providing a seamless display of 14 LED's. I experimented with my code and made a second array of only six elements being accessed by port B.

Code:
int i = 0;

void setup()
{

  DDRD = B11111111; // Set all the pins to output in port D
  DDRB = B00111111; // Set all the pins to output in port B   
}

byte digit[] = {B10000000,B01000000,B00100000,B00010000,B00001000,B00000100,B00000010,B00000001};
byte digit1[] = {B00100000,B00010000,B00001000,B00000100,B00000010,B00000001};


void Krider14_L_to_R()
{
  for(i = 0; i <= 7; i++)

  {
    PORTD = digit[i];
    delay(1000);
    PORTD = 0;
  }
  {
    for(i = 5; i >= 0; i--)

    {
      PORTB = digit1[i];
      delay(1000);
      PORTB = 0;
    }
  }
}

void loop()
{

  Krider14_L_to_R();

}


 This works just the same as the initial code. Which is a "more correct" method and what am I missing here.
Logged


Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

When you set the bits of any unused registers, the processor simply ignores them. So when, in your array, you set the unused bit to 1 and the rest to 0 it's the same as if you set all of them will be 0.
Logged

Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you WizenedEE,

so does this mean that in the initial code I posted, the D port was "using" the full eight elements of the digit array, and the B port was using the last six elements thus providing a seamless display of on / off LED's left to right?
Logged


Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you WizenedEE,

so does this mean that in the initial code I posted, the D port was "using" the full eight elements of the digit array, and the B port was using the last six elements thus providing a seamless display of on / off LED's left to right?

That sounds right. And there's 2 seconds of no LEDs being lit up at the "end" of the sequence as your code tries to turn on bits 7 and 8 of port B, right?
Logged

Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

WizenedEE, yes that is what is happening. Thank you for your help.
Logged


Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 439
Posts: 23728
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pedro,
Instead of using DDRx command, I just use pinMode as would normally be done, and then commands like

PORTD = PORTD & B11110111;  // clear bit 3
PORTD = PORTD | B00001000;  // set bit 3

and your comands work normally.

I use the above with SPI for fast transfers to shift registers, for example sending out bytes from an array:
Code:
PORTD = PORTD & B11110111;  // clear bit 3, used for slave select/latch
SPI.transfer(dataArray[x]);
SPI.transfer(dataArray[x+1]);
SPI.transfer(dataArray[x+2]);
SPI.transfer(dataArray[x+3]);
PORTD = PORTD | B00001000;  // set bit 3, used for slave select/latch

Lose some portability from '328 to '1284 ot '2560 this way, but I'm usually coding for a specific chip for a specific project so I don't worry about that.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Canberra Australia
Offline Offline
God Member
*****
Karma: 8
Posts: 503
Hardcore Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for that Crossroads. Only had time to have a quick play around with that before work...
damn work  smiley-cool   
Logged


Pages: [1]   Go Up
Jump to: