Go Down

Topic: Basic understanding of direct port manipulation code (Read 2140 times) previous topic - next topic

Pedro147

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: [Select]
  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.

http://www.pedroduino.com

Osgeld

#1
Mar 03, 2013, 01:44 am Last Edit: Mar 03, 2013, 01:46 am by Osgeld Reason: 1
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)
http://arduino.cc/forum/index.php?action=unread;boards=2,3,4,5,67,6,7,8,9,10,11,66,12,13,15,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,86,87,89,1;ALL

Pedro147

#2
Mar 03, 2013, 03:08 am Last Edit: Mar 03, 2013, 03:16 am by Pedro147 Reason: 1
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.

http://www.pedroduino.com

retrolefty


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

Pedro147

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.
http://www.pedroduino.com

retrolefty


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

Pedro147

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  8)
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: [Select]
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.
http://www.pedroduino.com

WizenedEE

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.

Pedro147

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?
http://www.pedroduino.com

WizenedEE


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?

Pedro147

WizenedEE, yes that is what is happening. Thank you for your help.
http://www.pedroduino.com

CrossRoads

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: [Select]

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.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Pedro147

Thanks for that Crossroads. Only had time to have a quick play around with that before work...
damn work  8)   
http://www.pedroduino.com

Go Up