need help with software logic

Hi guys,
I need some help - I have a fencing scoring machine that I am trying to duplicate from this one
http://www.sonic.net/~schlae/gplscoremach.html
I started out with that same wiring - but could not get good logic 0s. No matter how I set things up everything read in as 1 because the resisters acted like voltage dividers and I couldn't get down to 0.8V for a low. Finally gave up, now have the output lines going thru an open collecter 7406 with 3.3K pullup resistor. Now an output can be grounded and its good & low because it doesn't have an active driver & a resistor in the way. I have 74F374 with 24mA current sink driving the cathode of LEDs low to turn them on (don't have any shift registers handy, guess I should order some).
The problem I am having is below.

I am working the code for Epee weapons. An epee has 2 wires, A & B, that end at a switch at the tip of the blade. When the tip is closed, A & B are connected. If the switch is closed against ground (metallic floor strip, or opponents bellguard), then B & A will have 0 on them.
I have it coded to drive a low signal onto the C wires (opponents Bellguard), and toggle a hi/lo signal onto the B wires. I then read the B wires to see that they are not grounded, and if they are to turn on a ground light for as long as it reads a 0 when it should be a 1.
I can't get that to work - I think I have a s/w logic error, but can't see what it is. With a scope I can see a good 0 at the input.

I also have an issue whereby when the switch is closed for a good touch, then occasionally the touch light goes on & stays on, and won't turn off by itself, but only after a touch on the other side. The code requires the A&B input to match the B output for 30 consecutive reads, which at 106-110uS worked out to 2ms. At 200uS will be ~4mS.

I thought it was a race condition, so I lengthened the interval time of my loop from 100uS to 200uS. Didn't make a difference.

Could use another set of eyes to see what is going on.
Thanks
Robert

// I didn't copy all the pin definitions, takes up a lot of space.  This is the part that is running in void loop(). No interrupts, no functions.

  // start timing interval

  unsigned long currentMicros = micros();  // see how long its been
  if (currentMicros - previousMicros >= hundred_uS_interval) // more than our 0.2mS interval?
  {
    // save the last time we okayed time updates 
    previousMicros = currentMicros; 
    if (toggle == 0){
      toggle = 1;
    }
    else {
      toggle = 0;
    }
    // this ~ (bitwise not) does not seem to work:
    // toggle = ~toggle; // try odd/even kind of thing for sending high/low from outs to ins

    // do stuff on 0.1mS intervals, 1mS intervals, ets.

    // *****************************************************************
    switch(Weaponmode)
    {
    case 1: // epee

      // need contact for 2mS to 10mS to score
      // double touch if 2nd fencer has contact for 2ms within 40mS to 50mS of 1st fencer
      // gnd light if contact against opponents bellguard
      // or to grounded strip
 
      // On Toggle High, put out a 0 on ResBwires
      // On Toggle Low, open collector output is pulled up to a 1
      // Read WireB, if low when ResWire says high, then output is grounded
      // Read WireA & WireB, if they follow ResBWire for 30 occurrences (Hi-Lo-Hi-Lo) then call it
      // a touch, turn on light via shift register
      // if WireB grounded in the middle, start over

      if (toggle == 1){
        digitalWrite (ResBWireL, HIGH); // high on Left B wire -> 0 with 7406
        digitalWrite (ResBWireR, HIGH); // high on Right B wire -> 0 with 7406
        ResBstate = 0;
      }
      else {
        digitalWrite (ResBWireL, LOW); // low on Left B wire -> 1 with 7406
        digitalWrite (ResBWireR, LOW); // low on Right B wire -> 1 with 7406
        ResBstate = 1;
      }
      delayMicroseconds(25);  // << play with this with reels, see if long enough 
      //  signal delay ~1 ns/foot. From uC floor cord to reel to body cord to tip ~30 meters, 90 feet, & back, 180 feet = 180nS, 0.18uS

      // now read the wires
      leftA = digitalRead(AWireL);   // 
      leftB = digitalRead(BWireL);   //

      rightA = digitalRead(AWireR);  //
      rightB = digitalRead(BWireR);  //

      // *****************************************************************
      // check if left is grounded
      if (ResBstate == 1 && leftB == 0) // no touch for left, show ground light for duration
      { 
        outdata = outdata & 0b1111111111011111;  // AND out the ground light to turn it on
        left_contact_count = 0; // reset the contact count
      }
      if (ResBstate ==1 && leftB == 1) // turn it off, not grounded
      {
        outdata = outdata | 0b0000000000100000;  //  OR in the ground light to turn it off
      }
      
      // check if right is grounded
      if (ResBstate == 1 && rightB == 0) // no touch for right, show ground light for duration
      { 
        outdata = outdata & 0b1111111111111011; // AND out the ground light to turn it on
        right_contact_count = 0; // reset the contact count
      }
      if (ResBstate ==1 && rightB == 1) // turn it off, not grounded
      {
        outdata = outdata | 0b0000000000000100;  //  OR in the ground light to turn it off
      }
      if (old_outdata = outdata)  // if data changed, send it out
      {
        // not changed, do nothing
      }
      else{
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  // shift it out
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata); // shift it out
      }
      old_outdata = outdata;
      
      /*
       Look for a left touch, see if contact held for 30 hi/lo cycles (just over 2ms)
       Look for a right touch, see if contact held for 30 hi/lo cycles 
       If either 2mS completes set a corresponding flag, either one starts the 40mS lockout timer.
       At the end of 40mS turn on the score light for the flags that are set.
       */
      if (leftB == ResBstate && leftA == ResBstate && left_main_timer_running == 0) // start left contact count
      {
        left_contact_count = left_contact_count + 1;
      }
      else
      {
        left_contact_count = 0;
      } // case when leftA<>ResBstate i.e. no tip closure

      if (rightB == ResBstate && rightA == ResBstate && right_main_timer_running == 0) // start right contact count
      {
        right_contact_count = right_contact_count + 1;
      }
      else
      {
        right_contact_count = 0;
      } // case when rightA<>ResBstate i.e. no tip closure

      // did left have enough matching contacts?
      if (left_contact_count == 30) // check left contact count
      {
        goodlefttouch = 1; // set flag for a good left touchh
        outdata = outdata & 0b1111111001111111; // AND out the bit to turn it on
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata);
        left_main_timer = millis(); // start 40mS timer
        left_main_timer_running = 1; // flag for 40mS timer running
        left_contact_count = 0; // reset for next pass
      }

      // did right have enough matching contacts?
      if (right_contact_count == 30) // check right contact count
      {
        goodrighttouch = 1; // set flag for a good right touch
        outdata = outdata & 0b1111111011101111; // AND out the bit to turn it on
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata);
        right_main_timer = millis(); // start 40mS timer
        right_main_timer_running = 1; // flag for 40omS timer running
        right_contact_count = 0; // reset for next pass
      }

      if (goodlefttouch == 1){
        left_main_timerend = millis();        }  // check the 40mS timer

      if (goodrighttouch == 1){
        right_main_timerend = millis();
      } // check the 40mS timer

// <<< tried micro() for this 40mS part, would never enter the next if condition (>40000) to
// turn things off after a touch

      if (left_main_timerend - left_main_timer > 40 || right_main_timerend - right_main_timer > 40)
      {
        delay (2000); // leave lights & buzzer on for 2 seconds
        goodlefttouch = 0;  // reset for next pass
        left_main_timer_running = 0;
        left_main_timer = 0;
        left_main_timerend = 0;
        goodrighttouch = 0;  // reset for next pass
        right_main_timer_running = 0;
        right_main_timer = 0;
        right_main_timerend = 0;
        outdata = 0b1111111111111100;  // turn everything off except Epee indicator lights
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata); 
      }
      break;// end of case: epee

      // *******************************************************************  
    } //end of Switch (Weaponmode)
  }  // end of time interval
      if (old_outdata [glow]=[/glow]= outdata)  // if data changed, send it out
      {
        // not changed, do nothing
      }
 // toggle = ~toggle;

No a bitwise NOT (1s complement negation) won't work.
Zero will become 255, but 1 will become 254 (0xfe).

You need a logical NOT "!" operation.

Or your could simply do

toggle = 1 - toggle;
      if (left_main_timerend - left_main_timer > 40 || right_main_timerend - right_main_timer > 40)
      {

You may need a "left_main_timer_running" and a "right_main_timer_running" flag as an interlock.

Thanks guys!
Those darn = vs == in if statements - thought I had checked all those. The ground lights work now!

toggle = 1 - toggle; I didn't think that would work, so I put it in an excel spreadsheet, starting with 0 and with subsequent cells as "=1-(cell above)". Sure enough the result was 0 1 0 1 0 1.

changed the 40mS timeout test to:
if ((left_main_timer_running == 1) && (left_main_timerend - left_main_timer > 40) || (right_main_timer_running == 1) && (right_main_timerend - right_main_timer > 40))

adding the additional test didn't help.

Here's one thing I did notice - if the tip is held closed for more than just a quick blip, like if it was pressed up against some one and held, which is very usual, the touch light can also turn on & stay on.
I think that may be a clue into my problem.
The tip is released during the 2 second
delay(2000);
while the light/buzzer is on, so should be clear by the time all the variables are reset after that. Any ideas?

Any ideas?

Only the ultra-obvious. Don't use delay().

So you think add another flag & then block out starting the 2mS timer if it is set? I can try that.

Okay, I added a lockout_delay flag to only allow good touches to start timing if it is low. Once set, nothing new can start and everything gets reset. Once 2s have passed the lights are turned off.

Am still seeing that the a touch can be scored & not cleared.

[edit] The ground lights still work also while one side is staying on as well.

  // start timing interval

  unsigned long currentMicros = micros();  // see how long its been
  if (currentMicros - previousMicros >= hundred_uS_interval) // more than our 0.1mS interval?
  {
    // save the last time we okayed time updates 
    previousMicros = currentMicros; 
    toggle = 1-toggle;  // results in 0 1 0 1 ...

    // do stuff on 0.1mS intervals, 1mS intervals, ets.

    // *****************************************************************
    switch(Weaponmode)
    {
    case 1: // epee

      // need contact for 2mS to 10mS to score
      // double touch if 2nd fencer has contact for 2ms within 40mS to 50mS of 1st 2mS
      // gnd light if contact against opp's bellguard
      // or to grounded strip
 
      // On Toggle High, put out a 0 on ResBwires
      // On Toggle Low, open collector output is pulled up to a 1
      // Read WireB, if low when ResWire says high, then output is grounded
      // Read WireA & WireB, if they follow ResBWire for 8 occurrences (Hi-Lo-Hi-Lo) then call it a touch
      // if WireB grounded in the middle, start over

      if (toggle == 1){
        digitalWrite (ResBWireL, HIGH); // high on Left B wire -> 0 with 7406
        digitalWrite (ResBWireR, HIGH); // high on Right B wire -> 0 with 7406
        ResBstate = 0;
      }
      else {
        digitalWrite (ResBWireL, LOW); // low on Left B wire -> 1 with 7406
        digitalWrite (ResBWireR, LOW); // low on Right B wire -> 1 with 7406
        ResBstate = 1;
      }
      delayMicroseconds(25);  // << play with this with reels, see if long enough 
      //  signal delay ~1 ns/foot. From uC floor cord to reel to body cord to tip ~30 meters, 90 feet, & back, 180 feet = 180nS, 0.18uS

      // now read the wires
      leftA = digitalRead(AWireL);   // 
      leftB = digitalRead(BWireL);   //

      rightA = digitalRead(AWireR);  //
      rightB = digitalRead(BWireR);  //

      // *****************************************************************
      // check if left is grounded
      if (ResBstate == 1 && leftB == 0) // no touch for left, show ground light for duration
      { 
        outdata = outdata & 0b1111111111011111;  // AND out the ground light to turn it on
        left_contact_count = 0; // reset the contact count
      }
      if (ResBstate ==1 && leftB == 1) // turn it off, not grounded
      {
        outdata = outdata | 0b0000000000100000;  //  OR in the ground light to turn it off
      }
      
      // check if right is grounded
      if (ResBstate == 1 && rightB == 0) // no touch for right, show ground light for duration
      { 
        outdata = outdata & 0b1111111111111011; // AND out the ground light to turn it on
        right_contact_count = 0; // reset the contact count
      }
      if (ResBstate ==1 && rightB == 1) // turn it off, not grounded
      {
        outdata = outdata | 0b0000000000000100;  //  OR in the ground light to turn it off
      }
      if (old_outdata == outdata)  // if data changed, send it out
      {
        // not changed, do nothing
      }
      else{
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  // shift it out
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata); // shift it out
      }
      old_outdata = outdata;
      
      /*
       Look for a left touch, see if contact held for 30 hi/lo cycles (just over 2ms)
       Look for a right touch, see if contact held for 30 hi/lo cycles 
       If either 2mS completes set a corresponding flag, either one starts the 40mS lockout timer.
       At the end of 40mS turn on the score light for the flags that are set.
       */
      if (lockout_delay == 0 && leftB == ResBstate && leftA == ResBstate && left_main_timer_running == 0) // start left contact count
      {
        left_contact_count = left_contact_count + 1;
      }
      else
      {
        left_contact_count = 0;
      } // case when leftA<>ResBstate i.e. no tip closure

      if (lockout_delay == 0 && rightB == ResBstate && rightA == ResBstate && right_main_timer_running == 0) // start right contact count
      {
        right_contact_count = right_contact_count + 1;
      }
      else
      {
        right_contact_count = 0;
      } // case when rightA<>ResBstate i.e. no tip closure

      // did left have enough matching contacts?
      if (lockout_delay == 0 && left_contact_count == 30) // check left contact count
      {
        goodlefttouch = 1; // set flag for a good left touchh
        outdata = outdata & 0b1111111001111111; // AND out the bit to turn it on
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata);
        left_main_timer = millis(); // start 40mS timer
        left_main_timerend = left_main_timer; // resets differene to 0
        left_main_timer_running = 1; // flag for 40mS timer running
        left_contact_count = 0; // reset for next pass
      }

      // did right have enough matching contacts?
      if (lockout_delay == 0 && right_contact_count == 30) // check right contact count
      {
        goodrighttouch = 1; // set flag for a good right touch
        outdata = outdata & 0b1111111011101111; // AND out the bit to turn it on
        shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
        shiftOut(shiftdataout, serialclock, MSBFIRST, outdata);
        right_main_timer = millis(); // start 40mS timer
        right_main_timerend = right_main_timer; // resets difference to 0
        right_main_timer_running = 1; // flag for 40mS timer running
        right_contact_count = 0; // reset for next pass
      }

      if (lockout_delay == 0 && goodlefttouch == 1){
        left_main_timerend = millis();
      }  // check the 40mS timer

      if (lockout_delay == 0 && goodrighttouch == 1){
        right_main_timerend = millis();
      } // check the 40mS timer

      if (
      ((left_main_timer_running == 1) && ((left_main_timerend - left_main_timer) > 40)) 
      ||
      ((right_main_timer_running == 1) && ((right_main_timerend - right_main_timer) > 40))
      )
      // 40 mS has elapsed, lockout whomever didn't score, keep light(s)/buzzer for 2 seconds, reset for next touch
      {
        lockout_delay = 1; // lockout out any more touches
        lockout_delay_timer = millis(); // capture the time for a 2 second light(s)/buzzer
        lockout_delay_timerend = lockout_delay_timer;// resets difference to 0
        goodlefttouch = 0;  // reset for next pass
        left_main_timer_running = 0; // reset for next pass
        left_main_timer = 0; // reset for next pass
        left_main_timerend = 0; // reset for next pass
        goodrighttouch = 0;  // reset for next pass
        right_main_timer_running = 0; // reset for next pass
        right_main_timer = 0; // reset for next pass
        right_main_timerend = 0; // reset for next pass 
      }
      if (lockout_delay == 1) // capture elapsed time
      {
      lockout_delay_timerend = millis(); 
      }      
      if (lockout_delay == 1 &&
          (lockout_delay_timerend - lockout_delay_timer) > 2000 // light/buzzer on for 2s?
         )  
         {lockout_delay = 0;  // reset for the next touch
          outdata = 0b1111111111111100;  // turn everything off except Epee indicator lights
          shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
          shiftOut(shiftdataout, serialclock, MSBFIRST, outdata);
        } 
      
      break; // end of case: epee
    } //end of Switch (Weaponmode)
  }  // end of time interval

Problem seems to be resolved - I pulled the time passed calculations out of the if statements, seems to be working now. Why should that have made a difference if it compiled okay (and ran fine most of the time?

        // *****************************************************************
        if (goodlefttouch == 1){
          left_main_timerend = millis();
          [glow]left_main_time = left_main_timerend - left_main_timer;[/glow] 
        }  // check the 40mS timer

        // *****************************************************************
        if (goodrighttouch == 1){
          right_main_timerend = millis();
          [glow]right_main_time = right_main_timerend - right_main_timer;[/glow]        } // check the 40mS timer

         // *****************************************************************
         // if 40 mS has elapsed, lock out whomever didn't score, keep light(s)/buzzer for 2 seconds, reset for next touch
          if (left_main_timer_running ==1 && left_main_time > 40 || right_main_timer_running ==1 && right_main_time > 40)
          {
          lockout_delay = 1; // lockout out any more touches
          lockout_delay_timer = millis(); // capture the time for a 2 second light(s)/buzzer
          lockout_delay_timerend = lockout_delay_timer; // resets difference to 0
          left_main_timer_running = 0; // reset for next pass
          left_main_timer = 0; // reset for next pass
          left_main_timerend = 0; // reset for next pass
          right_main_timer_running = 0; // reset for next pass
          right_main_timer = 0; // reset for next pass
          right_main_timerend = 0; // reset for next pass
          goodlefttouch = 0;  // reset for next pass
          goodrighttouch = 0;  // reset for next pass
  
          // added turn on right offtarget light to see if getting in here
          outdata = outdata & 0b1111111111110100;
          shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
          shiftOut(shiftdataout, serialclock, MSBFIRST, outdata); 
        }
      }  // lockout is engaged, watch for 2 seconds to go by
      else {
        lockout_delay_timerend = millis(); //check the lockout time elapsed
        [glow]lockout_time = lockout_delay_timerend - lockout_delay_timer;  [/glow] 
if ( lockout_time > 2000 ) // light/buzzer on for 2s?  
        {
          lockout_delay = 0;  // yes, reset for the next touch
          outdata = 0b1111111110111100;  
          // turn everything off except Epee indicator lights
          // added turn on left offtarget to see if getting in here
          shiftOut(shiftdataout, serialclock, MSBFIRST, (outdata >> 8));  
          shiftOut(shiftdataout, serialclock, MSBFIRST, outdata);
        }