Flashing LEDs with Port Manipulation

I'm a fairly new with Arduino coding and have been trying to build my skills with direct port manipulation. I have 4 LEDs in which I am trying to strobe LEDs 1 & 4 while blinking LEDs 2 & 3. When I push a button, the strobing effect stops on LEDs 1 & 4 but LEDs 2 & 3 continue to blink. Everything for the most part is working, except when the strobe effect is activated I lose the brightness of the middle LEDs. I'm guessing it must have to do with my calls to the PORTD causing a 50% duty cycle on the middle LEDs. I've tried some examples of bitwise OR operators in which I can get the middle LEDs to come on full brightness but then they are trying to strobe. Is there a way to flash the LEDs 2 & 3 at full brightness while strobing LEDs 1 & 4 using Port Manipulation? Any help would be much appreciated. Here is my sketch:

bool strobeState;
bool patternState;
bool buttonState;
bool previousButtonState;
bool buttonRead;

byte strobeRate = 50;
byte portNum;
byte portClear = B00000000;
byte buttonPin = 10;
byte buttonPressCount;
byte debounceDelay = 20;

int interval = 500;

unsigned long currentMillis;
unsigned long patternMillis;
unsigned long strobeMillis;
unsigned long debounceMillis;

void setup() {
  Serial.begin(2400);
  DDRD = DDRD | B01111000;
  pinMode (buttonPin, INPUT_PULLUP);

}

void loop() {
  currentMillis = millis();
  readButtonPin();
  setPattern();
  //pattern1();
  //pattern2();

}
void readButtonPin() {
  buttonRead = digitalRead(buttonPin);
  if (buttonRead != previousButtonState)
    debounceMillis = millis();
  if (millis() - debounceMillis >= debounceDelay) {
    if (buttonRead != buttonState) {
      buttonState = buttonRead;
      if (buttonState == LOW)
        buttonPressCount ++;
    }
  }
  previousButtonState = buttonRead;
}

void setPattern() {
  switch (buttonPressCount) {
    case 0:
      pattern1();
      break;
    case 1:
      pattern2();
      break;
    case 2:
      buttonPressCount = 0;
      break;
  }
}
void strobe() {
  if (currentMillis - strobeMillis >= strobeRate) {
    strobeMillis = currentMillis;
    if (strobeState)
      strobeState = LOW;
    else
      strobeState = HIGH;
  }
  switch (strobeState) {
    case HIGH:
      PORTD = portNum;
      break;
    case LOW:
      PORTD = portClear;
      break;
  }
}

void pattern1() {
  if (currentMillis - patternMillis >= interval) {
    patternMillis = currentMillis;
    if (patternState)
      patternState = LOW;
    else
      patternState = HIGH;
  }
  switch (patternState) {
    case HIGH:
      PORTD = B00000000;
      portNum = B01001000;
      break;
    case LOW:
      PORTD = B00110000;
      portNum = B01001000;
      break;
  }
  strobe();
}
void pattern2() {
  if (currentMillis - patternMillis >= interval) {
    patternMillis = currentMillis;
    if (patternState)
      patternState = LOW;
    else
      patternState = HIGH;
  }
  switch (patternState) {
    case HIGH:
      PORTD = B00000000;
      break;
    case LOW:
      PORTD = B00110000;
      break;
  }
}
1 Like

Before we go further, did you have this all working just right with good old digitalWrite?

I hope so… because if not, you've made things hard on yourself.

When I push a button, the strobing effect stops on LEDs 1 & 4 but LEDs 2 & 3 continue to blink. 

And that is not what you want?

Carefully describe what exactly how the button is meant to control the effects.

a7

The button is only there to toggle between the two patterns. Press the button and the outer LEDs stop strobing. Press it again and the outer LEDs strobe again. I have tried this with digitalWrite commands. The following code seems to work. I am just wondering if there is a way to do the same with using the port commands. I know it is harder...I'm just trying to learn some new skills.

bool strobeState;
bool patternState;
bool buttonState;
bool previousButtonState;
bool buttonRead;

byte strobeRate = 50;
byte portNum;
byte portClear = B00000000;
byte buttonPin = 10;
byte buttonPressCount;
byte debounceDelay = 20;

byte LEDpin = 3;
byte LEDpin2 = 4;
byte LEDpin3 = 5;
byte LEDpin4 = 6;
byte a;
byte b;

int interval = 500;

unsigned long currentMillis;
unsigned long patternMillis;
unsigned long strobeMillis;
unsigned long debounceMillis;

void setup() {
  Serial.begin(2400);
  DDRD = DDRD | B01111000;
  pinMode (buttonPin, INPUT_PULLUP);

}

void loop() {
  currentMillis = millis();
  readButtonPin();
  setPattern();
  //pattern1();
  //pattern2();

}
void readButtonPin() {
  buttonRead = digitalRead(buttonPin);
  if (buttonRead != previousButtonState)
    debounceMillis = millis();
  if (millis() - debounceMillis >= debounceDelay) {
    if (buttonRead != buttonState) {
      buttonState = buttonRead;
      if (buttonState == LOW)
        buttonPressCount ++;
    }
  }
  previousButtonState = buttonRead;
}

void setPattern() {
  switch (buttonPressCount) {
    case 0:
      pattern1();
      break;
    case 1:
      pattern2();
      break;
    case 2:
      buttonPressCount = 0;
      break;
  }
}
void strobe() {
  
  if (currentMillis - strobeMillis >= strobeRate) {
    strobeMillis = currentMillis;
    if (strobeState)
      strobeState = LOW;
    else
      strobeState = HIGH;
  }
  switch (strobeState) {
    case HIGH:
    digitalWrite (a, HIGH);
    digitalWrite (b, HIGH);
      //PORTD = portNum;
      break;
    case LOW:
    digitalWrite (a, LOW);
    digitalWrite (b, LOW);
      //PORTD = portClear;
      break;
  }
}

void pattern1() {
  a = 3;
  b = 6;
  if (currentMillis - patternMillis >= interval) {
    patternMillis = currentMillis;
    if (patternState)
      patternState = LOW;
    else
      patternState = HIGH;
  }
  switch (patternState) {
    case HIGH:
      digitalWrite (LEDpin2, HIGH);
      digitalWrite (LEDpin3, HIGH);
      portNum = B01001000;
      break;
    case LOW:
      digitalWrite (LEDpin2, LOW);
      digitalWrite (LEDpin3, LOW);
      portNum = B01001000;
      break;
  }
  strobe();
}
void pattern2() {
  if (currentMillis - patternMillis >= interval) {
    patternMillis = currentMillis;
    if (patternState)
      patternState = LOW;
    else
      patternState = HIGH;
  }
  switch (patternState) {
    case HIGH:
      PORTD = B00000000;
      break;
    case LOW:
      PORTD = B00110000;
      break;
  }
}

OK, good. THX.

Generally speaking, yes of course. That is all and what digitalWrite and Read can use to do i/o, after all. There's nothing you can't do yourself in your own code. You can def manipulate one bit without effecting any others on the port.

Now that we all are sure the code works logically speaking with digitalWrite, the translation to port manipulation is nearly trivial.

It will depend on some bit wise masking and such like; I will try it when I am at the big rig or someone will before that time.

I assume you've poked around a bit on the internets for a tutorial or two on this, it's fairly straight ahead.

a7

Instead of setting the entire port to a specific value as in

PORTD = 0b01100000 ;

Why not set individual bits so as to retain the previous values of the other bits?

Examples:

To set bit 4 to 1 leaving the other bits untouched :

PORTD |= 0b00010000 ;

To clear bit 5 to 0 again leaving the other bits untouched:

PORTD &= 0b11011111 ;

You can then use the same logic as in your digitalWrite() version.

Yes, like @6v6gt, this below is the same only uses some bit operators to form the constants.

Bits that are 1 in the DRD register are outputs. Set the output bits to 1 in the DRD for the port.

Then set or clear bits in the PORT register to make them HIGH or LOW.

Here's your old friend "blink" with as little as you need to know about the whole thing at this point.

You need to know how to use the bitwise operators |, & and ~.

Or, and, invert.

And the way I've written it, the constants are just 2 raised to the power of the bit number in the port.

bit 0 = 1
bit 1 = 2
bit 2 = 4

and so forth.

as I've put my LED on 3, so I've used 8 below.

/*
  Port Manipulation Blink
*/

// # define THE_LED 3

void setup() {
	DDRD |= 0x8;	// just turn ON bit 3 = pinMode(3, OUTPUT);
}

void loop() {
  dBlink();
}

void dBlink()
{
  PORTD |= 0x8;		// turn ON bit 3 = digitalWrite(3, HIGH);

  delay(133);
 
  PORTD &= ~0x8;	// turn OFF bit 3 = digitalWrite(3, LOW); 

  delay(533);
}

HTH

a7

You can also make the constants using the shift operator, so the whole thing is a bit (<- see what I did there?) less confusing:

/*
  Port Manipulation Blink
*/

# define THE_LED 3

void setup() {
	DDRD |= (1 << THE_LED);	// turn ON bit 3 = pinMode(3, OUTPUT);
}

void loop() {
  dBlink();
}

void dBlink()
{
  PORTD |= (1 << THE_LED);	// turn ON bit 3 = digitalWrite(3, HIGH);
  
  delay(133);
 
  PORTD &= ~(1 << THE_LED);	// turn OFF bit = digitalWrite(3, LOW);
   
  delay(1533);
}

Srsly, that's all I know remember about it!

a7

When you write to the PORTD port like that, you are setting all 8 bits. In general you want to change only a subset of the bits. To turn on a set of bits, use:
PORTD |= B00110000;
To turn off a set of bits, use:
PORTD &= ~B00110000;
These use the bitwise OR and AND operations to force some bits ON or OFF while not changing the other bits.

When speed is important like really important the thing @johnwasser reiterates is useful.

The code can be simpler easier to follow if you just deal with one bit at a time, unless of course you are talking parallel bits to some other hardware that would better see them all change at once.

S'all up to you, naturally. The dual edge sword which is expressing yourself in code. At least dual. Edgy sword, that.

a7

Thank you John and Alto. I got it working by using PORTD |= portNum; in the strobe function.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.