Coding a function to toggle a pin based on a pattern..

Hi All,

I want to write a function that will bring a pin high or low based on the pattern passed to it periodically, for example:

void toggle(111001, 3)

Calling this every 10ms will keep a pin high for 30ms, then low for 20ms, then high again for 10ms. The pattern will repeat three times based on the second parameter. Would it be more efficient to do this using binary numbers and bit shifting? Please give me ideas on how best to code this. It should be coded to run as efficiently as possible.

Thanks in advance.

MitchSF:
Hi All,

I want to write a function that will bring a pin high or low based on the pattern passed to it periodically, for example:

void toggle(111001, 3)

Calling this every 10ms will keep a pin high for 30ms, then low for 20ms, then high again for 10ms. The pattern will repeat three times based on the second parameter. Would it be more efficient to do this using binary numbers and bit shifting? Please give me ideas on how best to code this. It should be coded to run as efficiently as possible.

Thanks in advance.

Are you wanting to translate each binary digit into (tens of) milliseconds or just confirm that the number is correct?

In your Original Post 111001 is a decimal number, not a pattern. As you have not explained what the pattern represents it is difficult to help. Maybe it should be in a string "111001" or maybe it should be converted to a binary digit.

How many variations on the pattern are there?

Could you put all the possible variations in an array and then iterate through the array to find a match?

...R

MitchSF:
Hi All,

I want to write a function that will bring a pin high or low based on the pattern passed to it periodically, for example:

void toggle(111001, 3)

Calling this every 10ms will keep a pin high for 30ms, then low for 20ms, then high again for 10ms. The pattern will repeat three times based on the second parameter. Would it be more efficient to do this using binary numbers and bit shifting? Please give me ideas on how best to code this. It should be coded to run as efficiently as possible.

Thanks in advance.

@MitchSF,

your approach is memory efficient, but it adds programming complexity, solving for the number of bits that will lite if the sequence is less than 8. to show you, refer to the example below. But, your method can be extended (efficiently) if sequences are longer than 8 bits.

In the example I included a byte array as another means to solve the problem, not as efficient from a memory use perspective, but less lines of code.

(I was able to compile but not able to test)

const byte ledPin = 13;

int num_times = 3;

byte myArray[] = {1,1,1,0,0,1};

void setup() 
{
  pinMode(ledPin, OUTPUT);
}

void loop() 
{
  while(num_times) toggle(B00100111, num_times);  // notice i reversed the order of your byte
  //while(num_times) arrayToggle(myArray, sizeof(myArray)/sizeof(myArray[0]), num_times);
}

void toggle(byte myBitMask, int &times) 
{
  if (times == 0) return;
  byte magnitude = 0;
  for(byte i = 0; i < 8; i++)  // locate most significant byte
  {
    if(bitRead(myBitMask,i)) 
    magnitude = i;
  }
  for (int i = 0; i <= magnitude; i++)  // only process up to most significant byte
  {
    digitalWrite(ledPin, bitRead(myBitMask,i));
    delay(10);
  }
  digitalWrite(ledPin, LOW);
  times--;
}

void arrayToggle(byte *array, size_t arraySize, int &times)
{
  if (times == 0) return;
  for (byte i = 0; i < arraySize; i++)
  {
    digitalWrite(ledPin, array[i]);
    delay(10);
  }
  digitalWrite(ledPin, LOW);
  times--;
}

Sorry I wasn't clear. 1s and 0s represent high and low on the pin, not a binary number. I thought that possibly using binary numbers and shifting would allow the function to run more efficiently.

MitchSF:
Sorry I wasn't clear. 1s and 0s represent high and low on the pin, not a binary number. I thought that possibly using binary numbers and shifting would allow the function to run more efficiently.

If you represent 1's and 0's in a decimal string, you have to divide by powers of 10 to extract the individual bits. That is horribly inefficient. That's why we assumed that you got your data types mixed up. We were giving you the benefit of the doubt, thinking you made the lesser mistake.

No, I made the greater mistake, but now I see the light. Thanks.

One more question - I want to set a pointer to either array:

globals
const byte effect1[5] = {B10101, B10101, B10101, B11011, B11111};
const byte effect2[5] = {B11111, B00000, B11111, B00000, B11111};
byte *newArray;

newArray = &effect1; this does not work
or
newArray = &effect2;

x = newArray[2]; // this is what I want to be able to do.

Thanks again in advance.

I think you're overcomplicating this. While using individual bits and shifting through them is efficient and fast, the code that does that is insignificant compared to the rest of the code (setting pins, delays, etc.). This is what is called "premature optimization." I would concentration on readability, understandability, maintainability, etc. first.

If, and ONLY IF, you have performance problems, should you try to optimize your code, and then you want to concentrate on the code that is actually slow.

--Doug

The last question I asked is not because the code is slow. It appears to work fine. I want to be able to use several different arrays with the same function. I guess I could pass an array pointer as a function parameter.

newArray = effect1;

or

newArray = effect2;

should work.

--Doug

MitchSF:
No, I made the greater mistake, but now I see the light. Thanks.

But only for 10ms at a time. :slight_smile:

newArray = effect1;

That doesn't seem to work. I'm still interested in finding out if there is a way to use a pointer to one of several arrays, so that I can use the pointer in a function.

The earlier example works perfectly for digit crossfading in my Nixie clock design. Thanks again.

MitchSF:
newArray = effect1;

That doesn't seem to work.

because your arrays are using the const keyword, yes it doesn't work.

Remember effect1 is a pointer to the FIRST ELEMENT of the array... look at the demo code below.

Another way would be to use a two dimensional array:

byte myArray[2][5] =...

FYI:

int effect1[5] = {B10000001, B11000011, B11100111, B11111111, B10101010};
int effect2[5] = {B11111, B00000, B11111, B00000, B11111};

int* newArray;
 
void setup() 
{
  Serial.begin(9600);
  newArray = effect2;
  for (int i = 0; i < 5; i++)
  {
    Serial.println(*(newArray+i), BIN);
  }
  Serial.println();
  newArray = effect1;
  for (int i = 0; i < 5; i++)
  {
    Serial.println(*(newArray+i), BIN);
  }
}

MitchSF:
newArray = effect1;

That doesn't seem to work.

Since newArray will be pointing at constant data, you must have

const byte *newArray;

Thanks. Problem solved.