Go Down

Topic: need help with software logic (Read 946 times) previous topic - next topic

CrossRoads

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

Code: [Select]

// 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
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Coding Badly

Code: [Select]
     if (old_outdata [glow]=[/glow]= outdata)  // if data changed, send it out
     {
       // not changed, do nothing
     }


AWOL

Code: [Select]
// 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
Code: [Select]
toggle = 1 - toggle;
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Coding Badly

Code: [Select]
     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.

CrossRoads

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?
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

PaulS

Quote
Any ideas?

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

CrossRoads

So you think add another flag & then block out starting the 2mS timer if it is set? I can try that.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

CrossRoads

#7
Dec 03, 2010, 07:17 pm Last Edit: Dec 03, 2010, 11:17 pm by CrossRoads Reason: 1
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.

Code: [Select]

 // 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
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

CrossRoads

#8
Dec 04, 2010, 07:40 am Last Edit: Dec 04, 2010, 07:42 am by CrossRoads Reason: 1
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?

Code: [Select]

       // *****************************************************************
       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);
       }
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Go Up