Toggling a pin in bursts, without using delay();

I am trying to toggle a pin on and off 16 times in short bursts because my project requires to determine on which edge another pin reads a transition from low to high.

Toggling the pin with a for loop and delay(); is simple enough, it gives me all the control about the delay between rising and falling edges that I need to make precise and consistent readings.
But it also slow everything else down, so much that it's kind of useless in conjunction with pretty much everything else.

I have tried to figure out a way of strobing the pin with the method in the BlinkWithoutDelay-example, but I can't figure out how to control the delay between the edges. Actually, I couldn't even figure out how to use a for loop to toggle the pin 16 times that way. The loop just exits on every toggle.
Am I missing something obvious here or am I trying the wrong method in the first place?

Could someone please point me in the right direction?

Hi MontySylver

Could you post the code you have? Please use code tags (the "</> icon on the button bar).

And please explain more about the timing you need. The pin needs to go on and off 16 times - do you mean "on, off" is one time and you need that 15 times more? Do the 16 changes make up the "short burst"? How long between each transition? How long between the bursts?

Regards

Ray

What you are describing is bit banging. But can't you just use a PWM pin? That shouldn't effect performance, and you can alter the PWM frequency further by messing aroudn with the clock prescaler.

Maybe, if i've understand the question, you can put the toggling on a if statement where you compare the value of a var until it's >= to 0 and for each loop you decrease the var, initialized to 15 and your sketch will toggle you pin for 16 times.

Further, simplified explanation:

  • toggle pin from low to high
  • read other pin
  • toggle pin from high to low
  • do that 15 more times

The not working code I've tried:

const int ledPin =  13;      // the number of the LED pin

int ledState = LOW;             // ledState used to set the LED

unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
}

void loop()
{

  for (int i = 0; i < 15; i++) {
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;

      // if the LED is off turn it on and vice-versa:
      if (ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;

      // set the LED with the ledState of the variable:
      digitalWrite(ledPin, ledState);
    }
  }
}

Hmmm this might work, though pretty inaccurate I'd imagine.

unsigned long time_at_pulse = 0;
boolean state = false; 

void loop()
{
	if( millis() - time_at_pulse > 50 )	// 50 ms between pulses == 20 pulses per second
	{
		state = !state;
		time_at_pulse = millis();
		digitalWrite(pin, state);
	}
}

toggle pin from low to high
read other pin

Do you want to read the input other pin immediately after toggling the output pin, or after a fixed time?

How many times do you read it before the next output toggle? Just once?

What do you do with the reading from the input pin?

toggle pin from high to low

How long between "toggle pin from low to high" and this toggle? A fixed time? As quickly as possible?

How long between this toggle and the next "toggle pin from low to high"?

Okay, I oversimplified it a little.

  • toggle pin from low to high
  • put the "position" (0...15) of the edge into a variable
  • immediately read the other pin for 10 times to avoid false readings
  • do some error correction
  • if the corrected reading is high, return the position
  • wait 1800 microseconds
  • toggle pin from high to low
  • wait 1800 microseconds
  • repeat until 15 is reached
  • when 15 is reached start over at 0

tammytam:
Hmmm this might work, though pretty inaccurate I'd imagine.

Just tried. Same result as with the other code.

Thanks for the details, MontySylver. They are making things clearer.

immediately read the other pin for 10 times to avoid false readings
do some error correction

I should have asked earlier, is this an analog or digital input?

Overall, to summarise, you want to generate 16 cycles of a square wave (1800us high, 1800us low). After each of the 16 low to high transitions, you check if your input is a valid high. The result is the cycle number on which the input goes valid high. Is that correct?

I should have asked earlier, is this an analog or digital input?

It's a digital input.

Overall, to summarise, you want to generate 16 cycles of a square wave (1800us high, 1800us low). After each of the 16 low to high transitions, you check if your input is a valid high. The result is the cycle number on which the input goes valid high. Is that correct?

That is the exact technical description of what I am trying to accomplish! :slight_smile: I am not good at explaining things in technical terms...

As for an explanation what that code is supposed to do: I started to write code for TTP229 capcitive touchpads months ago and want to have something that is usable in a practical situation instead of a "good enough" proof of concept.

Try using this code as a starting point. You need to set correct pin numbers and, obviously, add your code for reading the input pin and deciding if it is a valid high :slight_smile:

Make sure that the code you add is non-blocking and executes quickly enough to allow the 1800us timeout to run "on time" to give you the correct period of the output toggle.

#define HALF_PERIOD 1800UL // duration of high or low in microseconds
#define TEST_LIMIT 15
#define OUTPUT_PIN 13 // set to your value
#define INPUT_PIN  12 // set to your value

int resultCycle;
boolean testRunning;
int outputState;

void setup()
{
  Serial.begin(115200);
  pinMode(OUTPUT_PIN, OUTPUT);
  digitalWrite(OUTPUT_PIN, LOW);
  outputState = LOW;
  pinMode(INPUT_PIN, INPUT); // set INPUT or INPUT_PULLUP

  resultCycle = -1; // valid result will be 0 .. 15, -1 will indicate no valid input received within TEST_LIMIT + 1 cycles
  testRunning = true;
}

void loop()
{
  static unsigned long lastToggle = 0;
  if (testRunning)
  {
    unsigned long currentMicros = micros();
    if (currentMicros - lastToggle >= HALF_PERIOD)
    {
      lastToggle = currentMicros;
      if (outputState == LOW)
      {
        outputState = HIGH;
        digitalWrite(OUTPUT_PIN, outputState);
        resultCycle++;  // resultCycle will be 0 on first low to high toggle
        // add your code to read input
        // add your code to error correct
        if (/*add your expression to test for valid result*/)
        {
          testRunning = false; // stop test with resultCycle holding valid cycle number
        }
      }
      else // outputState == HIGH
      {
        outputState = LOW;
        digitalWrite(OUTPUT_PIN, outputState);
        if (resultCycle == TEST_LIMIT)
        {
          testRunning = false; // stop test
          resultCycle = -1;
        }
      }
    }
  }
  else // test has finished
  {
    Serial.print("resultCycle = ");
    Serial.println(resultCycle);
    while (1); // halt
  }
}

I couldn't get it to work :frowning:

But I won't give up that easily!

It's working (jittery) with my proof of concept code, as it did before.
Here's the code:

  int confirmations = 0;
  int current = 0;
  boolean sdoValue;

  do{

    for(int i = 0; i < 17; i++){
      CLR(PORTD,2);
      delayMicroseconds(10);
      sdoValue = digitalRead(sdoPin);

      if(sdoValue == 1){
       current = i;
      }
      SET(PORTD,2);
      delayMicroseconds(10);
    }
    confirmations++;
    delayMicroseconds(1750);

   }while(confirmations <=20);

   if(confirmations >=21){
    return current;
    confirmations = 0;
  }
}

The code is completely botched together just to make it work somehow. Complete trial and error and barely reliable. Using direct port manipulation to speed things up a bit.

Here is the output on my scope. CH1 is the clock, CH2 is data.

As you can see, data goes high on a rising edge that corresponds with the number touched on the touchpad, in this case 9 (Also, the timing is horribly off). So yeah, it's dead simple and I still can't figure out how to do it properly though.