Toggles and triggers in a program?

I have the feeling that the answer to this one is simple, but it’s been escaping me for the last few days. My current code and breadboard are working just as expected. Expected, because I copied most of it from the work performed by SpikedCola on the old forum. His code worked for him, thanks to an assist from EmilyJane, so it worked for me too. The current code reads the ultrasonic sensor and returns a dimension in inches, then displays it on a 7-segment LED unit x 2. Obviously it is limited to 99 inches, but that’s perfect for my purposes.

What I’d like to do is expand upon this foundation. A rough outline follows:

I’ve discovered that I can easily use the digitalWrite(cam_1,OUTPUT) to trigger the shutter on my Canon cameras using a USB cable and Canon CHDK. I’ll have two cameras triggered by events noted below.

“Arming” button, press to start program, press to idle program. Turn on “Armed” LED indicator (or off). I put this first, as I suspect the rest of the program will reside inside this segment of code.
Read the distance, if it’s greater than 99" or zero (implying out-of-range), just keep reading.
If the distance is less than 36", trigger camera one (cam_1 for 250ms, release), wait 2 seconds, trigger camera two for the same 250ms.
Check the distance again after the second camera triggers and if it’s lower than the initial figure, sequence both cameras again.
Wait until the distance measured exceeds 99" or zero (implying out-of-range) before starting the 36" check again.

#include "Ultrasonic.h"
Ultrasonic ultrasonic(8,9);
// first number is trigger, second is echo

int cam_1 = 10; // camera one pin ten
int cam_2 = 11; // camera two pin eleven
int dataPin = 5;        
int latchPin = 6;
int clockPin = 7;
int j = 1;
int toShift = 0;         
char m[2];               
byte data;
byte dataArray[10];

void setup() {
  //set pins to output to control camera trigger
  pinMode(cam_1, OUTPUT);
  pinMode(cam_2, OUTPUT);
  digitalWrite(cam_1, LOW); // set camera triggers to off
  digitalWrite(cam_2, LOW); 
  pinMode(latchPin, OUTPUT);
  dataArray[0] = 0x3F; // 0    SpikedCola's work for assigning segments to specific digits
  dataArray[1] = 0x06; // 1
  dataArray[2] = 0x5B; // 2
  dataArray[3] = 0x4F; // 3
  dataArray[4] = 0x66; // 4
  dataArray[5] = 0x6D; // 5
  dataArray[6] = 0x7C; // 6
  dataArray[7] = 0x07; // 7
  dataArray[8] = 0x7F; // 8
  dataArray[9] = 0x67; // 9

  // clear both displays with 0's
  // top
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, dataArray[0]);
  shiftOut(dataPin, clockPin, dataArray[0]);
  digitalWrite(latchPin, 1);
}

void loop()
{
  int k = 10;
  toShift = ultrasonic.Ranging(INC); // test segment to determine display works as expected

  // the following code is by EmilyJane of arduino.cc forums
  int temp = toShift;
  for (int i = 1; i >= 0; i--)
  {
    m[i] = temp / k;
    temp = temp - (m[i] * k);
    k = k / 10;
  }
  // end
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, dataArray[m[0]]);
  shiftOut(dataPin, clockPin, dataArray[m[1]]);
  digitalWrite(latchPin, 1);

}

// the heart of the program
void shiftOut(int mydataPin, int myClockPin, byte mydataOut)
{
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(mydataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(mydataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte mydataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to mydataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if ( mydataOut & (1<<i) ) {
      pinState= 1;
    }
    else {
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(mydataPin, pinState);
    //register shifts bits on upstroke of clock pin
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(mydataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);

}

The code as presented above does not trigger cameras, nor does it perform any of the checking described in my request. If it’s not obvious from the code, I’m using a pair of 74HC595 shift registers to keep the wiring and pin use to a minimum. The comments inside loop() are apparently created by EmilyJane and I’ve not tried to understand every step. What matters is that it’s working with my hardware, so I’m going to run with that.

Part of the overall package requires that the distance displayed remains fixed, not updating, when camera two is triggered. The code above for reading the ultrasonic was to determine that my displays were working as wired and can be placed anywhere appropriate, which is another location of which I’m unsure.

I have memory issues and bring up my exercise sketches, copy code over, make appropriate changes and test and hope. I expect that the arming button will use the bounce library, but I’m not sure how to write the code or more accurately, where to place it. Most of the sketches as part of the beginner package do not include much in the way of conditionals. I don’t expect anyone to write the code for me, but hints and links would be appreciated.

thanks

fred

Maybe something like this:

FireCamera(int pin)
{
  digitalWrite(pin, HIGH);
  delay(250);
  digitalWrite(pin, LOW);
}

void loop()
{
  static enum { WAITING, FIRED1, FIRED2 }  state = WAITING;
  static unsigned long firedTime = 0;
  static int initialDistance;
  int k = 10;
  toShift = ultrasonic.Ranging(INC); // test segment to determine display works as expected

  switch (state)
  {
  case WAITING:
    if (toShift < 36 && toShift > 0)
    {
      FireCamera(cam_1);
      firedTime = millis();
      initialDistance = toShift;
      state = FIRED1;
    }
    break;
  case FIRED1:
    if (millis() - firedTime > 2000)
    {
      FireCamera(cam_2);
      if (toShift < initialDistance && toShift > 0)
      {
        FireCamera(cam_1);
        firedTime = millis();
        state = FIRED1;
      }
      else
      {
        state = FIRED2;
      }
    }
    break;
  case FIRED2:
    if (toShift == 99 || toShift == 0)
      state = WAITING;
    break;
  }

  // the following code is by EmilyJane of arduino.cc forums
  int temp = toShift;
  for (int i = 1; i >= 0; i--)
  {
    m[i] = temp / k;
    temp = temp - (m[i] * k);
    k = k / 10;
  }
  // end
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, dataArray[m[0]]);
  shiftOut(dataPin, clockPin, dataArray[m[1]]);
  digitalWrite(latchPin, 1);

}

That appears to be some tremendously clean code, especially compared with what I might have generated. Between now and my last post, I pulled up the beginner's book and found the debounce segment and button pressing/toggling to attempt to work on the arming section of the code, but you've got me beat by a long shot with your contribution.

I don't understand some of the code but I can research the terms in the glossary and learn more about each section, to better understand things. It might be a day or two before I can get my head wrapped around this new development, but I'm sure it will be easier and faster than my own direction.

thanks very much!

fred

The code implements a "state machine": http://en.wikipedia.org/wiki/Finite-state_machine.

I’ve placed the setup portion from my first attempt in the newest contribution and have begun to attempt to understand it at the base level. I may simply connect up the devices and see that it works, and forget about a basic understanding of the code. To that end, I ran the verify function of the IDE and had to add void ahead of FireCamera() to get rid of one error. It was just a guess on my part, but it appeared to have worked.

I’m getting another error on the second pass at verification and can’t pin that one down. It reads:

\arduino-1.0.1\hardware\arduino\cores\arduino/Arduino.h: In function 'void loop()':
\arduino-1.0.1\hardware\arduino\cores\arduino/Arduino.h:111: error: too few arguments to function 'void shiftOut(uint8_t, uint8_t, uint8_t, uint8_t)'
more_refined_ultrasonic_camera_display:74: error: at this point in file
\arduino-1.0.1\hardware\arduino\cores\arduino/Arduino.h:111: error: too few arguments to function 'void shiftOut(uint8_t, uint8_t, uint8_t, uint8_t)'
more_refined_ultrasonic_camera_display:75: error: at this point in file

This confuses me as the portion of the code that is being highlighted as in error is unchanged from my earlier code which displays the distance on the LED modules with no trouble at all. This is the segment that contains the error highlight, starting with “shiftOut(dataPin, clockPin, dataArray[m[0]]);” The error messages appear to indicate incorrect number of parameters but as noted, the previous program does not generate any error messages and the code is a copy/paste duplication. I’ve done a 'net search for the error message, but what’s returned is almost as obscure as the error itself. I’ve found in previous errors that such messages are not particularly helpful to me, and that my error is more often a missing character or two.

digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, dataArray[m[0]]);
  shiftOut(dataPin, clockPin, dataArray[m[1]]);
  digitalWrite(latchPin, 1);

I’m including the current code verbatim to show my minor changes:

#include "Ultrasonic.h"
Ultrasonic ultrasonic(8,9);
// first number is trigger, second is echo

int cam_1 = 10; // camera one pin ten
int cam_2 = 11; // camera two pin eleven
int dataPin = 5;        
int latchPin = 6;
int clockPin = 7;
int j = 1;
int toShift = 0;         
char m[2];               
byte data;
byte dataArray[10];

void FireCamera(int pin)
{
  digitalWrite(pin, HIGH);
  delay(250);
  digitalWrite(pin, LOW);
}

void loop()
{
  static enum {WAITING, FIRED1, FIRED2}  
  state = WAITING;
  static unsigned long firedTime = 0;
  static int initialDistance;
  int k = 10;
  toShift = ultrasonic.Ranging(INC); // test segment to determine display works as expected

  switch (state)
  {
  case WAITING:
    if (toShift < 36 && toShift > 0)
    {
      FireCamera(cam_1);
      firedTime = millis();
      initialDistance = toShift;
      state = FIRED1;
    }
    break;
  case FIRED1:
    if (millis() - firedTime > 2000)
    {
      FireCamera(cam_2);
      if (toShift < initialDistance && toShift > 0)
      {
        FireCamera(cam_1);
        firedTime = millis();
        state = FIRED1;
      }
      else
      {
        state = FIRED2;
      }
    }
    break;
  case FIRED2:
    if (toShift == 99 || toShift == 0)
      state = WAITING;
    break;
  }

  // the following code is by EmilyJane of arduino.cc forums
  int temp = toShift;
  for (int i = 1; i >= 0; i--)
  {
    m[i] = temp / k;
    temp = temp - (m[i] * k);
    k = k / 10;
  }
  // end
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, dataArray[m[0]]);
  shiftOut(dataPin, clockPin, dataArray[m[1]]);
  digitalWrite(latchPin, 1);

}

What can I look for now?

Where is your 3 argument shiftOut function now? The built in Arduino shiftOut takes 4 arguments, hence the compile error that your calls to shiftOut have too few arguments.

That's where my confusion comes in, too. If you look at the first block of code I posted, the last lines of the setup() section have a shiftOut() call with three parameters and the last lines of the loop() segment have the same. The first block of code verifies and loads into the Arduino and does display the distance measured by the ultrasonic sensor.

Since it's copy/paste of that code, why should it fail now?

That said, I just did a quick search and rather than use the tutorial link for shiftOut, I checked the reference link and found exactly what is suggested, that there are four parameters needed. Now it's not so much why this code isn't working but why the other code did work!

That's pretty trivial and insignificant at this point. I see I need either an MSBFIRST or an LSBFIRST parameter in the middle of them.

Since it's copy/paste of that code, why should it fail now?

Your second sample did not contain the 3 argument shiftOut function, so you clearly didn't copy/paste all of the code.

Since the Arduino's shiftOut takes 4 parameters, you'd have to provide your own 3 parameter definition to allow code that passes in 3 arguments to compile.

I've just discovered that in my ignorance, I neglected to put the entire setup() block into the new code. It doesn't explain why the old stuff worked but the new code now verifies properly.

To determine which bit-order is correct, I placed MSBFIRST in each of the appropriate locations in the original code, which does not perform any camera triggering. The code compiles, but the sensor display no longer functions. I get a set of static bars in the LED modules. Swapping LSBFIRST in place of MSBFIRST doesn't do anything differently. I then removed them and the measurement is again displayed.

Running the new code results in static bars in the LED modules just as above. The difference in the new code from the old is that removing MSBFIRST also prevents verification.

Your second sample did not contain the 3 argument shiftOut function, so you clearly didn't copy/paste all of the code.

Since the Arduino's shiftOut takes 4 parameters, you'd have to provide your own 3 parameter definition to allow code that passes in 3 arguments to compile.

I'm using SpikedCola's implementation of the code for a digital thermometer project he completed a couple of years ago. I should have noted that it was missing the third parameter, and now I have, but it's back to basics with my original code or John Wasser's generous contribution. The former works with 3 parameters and fails with four in the shiftOut() call, while the latter doesn't verify/compile without the third of four parameters and does not present useful information on the LED modules with all four parameters in place.

On John's code, I'm going to add a serial.Print segment to see what the ultrasonic sensor is providing and maybe also some byte monitors to determine what data is being moved around.

fred_dot_u: I'm using SpikedCola's implementation of the code for a digital thermometer project he completed a couple of years ago. I should have noted that it was missing the third parameter, and now I have

That code wasn't missing any parameters. He'd create a shiftOut function to perform the functionality that he needed, and that function only took 3 parameters. It's hard code for MSB first, so there's no need to pass in a param to specify that.

The Arduino shiftOut will not replace his function, because it doesn't operate the same. You need to continue using the custom, 3 parameter shiftOut that was in your original code (which means you need to include that code in your current code to use it).

jraskell: That code wasn't missing any parameters. He'd create a shiftOut function to perform the functionality that he needed, and that function only took 3 parameters. It's hard code for MSB first, so there's no need to pass in a param to specify that.

The Arduino shiftOut will not replace his function, because it doesn't operate the same. You need to continue using the custom, 3 parameter shiftOut that was in your original code (which means you need to include that code in your current code to use it).

I have to believe sometimes that I'm dense as a brick. I found SpikedCola's function in the original code and moved it over to the updated stuff. Now that code compiles and the circuit displays the desired numbers. My next step will be to wire in a couple LEDs to represent the camera triggers. I'll temporarily change the timing so I'm not trying to observe a quarter-second LED flash.

I probably would have been "happier" with code for the LED modules that used stock/standard Arduino calls, but now that I've put this much into the project, I'm going to keep it on this line.

The next portion of uncertain code is the armed/not-armed button and LED indicator. Any suggestions to that end?

Since I've moved over the custom shiftOut() code, should I post an updated, accurate version to my next post?

fred_dot_u: The next portion of uncertain code is the armed/not-armed button and LED indicator. Any suggestions to that end?

A state variable should do exactly what you want. Declare a boolean and toggle the state of that boolean when you push your arming button.

Use that boolean to set your LED indicator (set the LED in your button code after toggling the variable) as well as enabling/disabling your timing code.

Having run into hardware problems, the coding has been put on hold until now. I’ve changed my requirements and parameters for the program and was not able to make use of the switch method, primarily because I am unable to come up with the “backbone” for the code. The hardware works as it should and I’m returning to the code anew.

Here’s the stuff I used to test the board and assemblies:

#include "Ping.h"
Ping ping = Ping(9,0,0); // ping sensor on pin 9

int cam_1 = 10; // camera one pin ten
int cam_2 = 11; // camera two pin eleven
int dataPin = 5;        
int latchPin = 6;
int clockPin = 7;
int j = 1;
int toShift = 0;         
char m[2];               
byte data;
byte dataArray[10];

void setup() {
  digitalWrite(cam_1, LOW); // set triggers to off
  digitalWrite(cam_2, LOW); 
  pinMode(latchPin, OUTPUT);  
  // bytes representing each LED digit
  dataArray[0] = 0x3F; // 0
  dataArray[1] = 0x06; // 1
  dataArray[2] = 0x5B; // 2
  dataArray[3] = 0x4F; // 3
  dataArray[4] = 0x66; // 4
  dataArray[5] = 0x6D; // 5
  dataArray[6] = 0x7C; // 6
  dataArray[7] = 0x07; // 7
  dataArray[8] = 0x7F; // 8
  dataArray[9] = 0x67; // 9

  // debug - Serial.begin(9600);

  // clear both displays with 0's
  // top
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, dataArray[0]);
  shiftOut(dataPin, clockPin, dataArray[0]);
  digitalWrite(latchPin, 1);
}

void loop()
{
  int k = 10;
  ping.fire();
  int toShift = ping.inches();
  // debug - Serial.println(toShift);
  if (toShift >0 && toShift < 36) // if ping results are greater than 36 inches or zero, don't do anything)
  {

    // the following code is by EmilyJane of arduino.cc forums - loads array with appropriate byte for digits to display
    int temp = toShift;
    for (int i = 1; i >= 0; i--)
    {
      m[i] = temp / k;
      temp = temp - (m[i] * k);
      k = k / 10;
    }
    // end of EmilyJane's solution
    // send bytes to shift register - if digits are in reverse order, reverse 0,1 in shiftOut order
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, dataArray[m[0]]);
    shiftOut(dataPin, clockPin, dataArray[m[1]]);
    digitalWrite(latchPin, 1);
  
  }

}

// program by SpikedCola on forum
void shiftOut(int mydataPin, int myClockPin, byte mydataOut)
{
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(mydataPin, OUTPUT);

  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(mydataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte mydataOut?
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to mydataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if ( mydataOut & (1<<i) ) {
      pinState= 1;
    }
    else {
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(mydataPin, pinState);
    //register shifts bits on upstroke of clock pin
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(mydataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);

}

When I approach a programming task, I try to create a textual flow chart of sorts. It worked for me in the late 70s when I was learning Fortran, although in class we had to use the stencils and make the real thing. I haven’t been able to wrap my head around this one.

In the process of trying to figure out the code, I also simplified the requirements, which amounts to a refinement overall. What I’d like to do is have cam_1 HIGH for 250 ms when the conditional listed above is met (toShift > 0 && toShift < 36) with a 250 ms delay after cam_1 returns LOW. Checking toShift each time, bringing cam_1 HIGH each time, until toShift exceeds the parameters.

At that point, I’d like to have cam_2 HIGH for 250 ms with a delay again of 250 ms and execute that operation four times.

If the conditional is not met, both cam_ leads are to remain LOW.

if toShift matches the conditional during the cam_2 4x sequence, it is to be aborted in order to “start at the top”.

fred