Should work, but does not

/*
  GFI for safety extension cord
  
*/
#include "simpletools.h"                      
#include "adcDCpropab.h"

void measure_imax();

void trip_breaker();

volatile float i;
volatile float imax;

int main()                                    // Main function runs 7 segment LED's in cog 0
{
  
  cog_run(measure_imax,128);                  // Start littlebird measurments
  
  cog_run(trip_breaker,128);                  // Start circuit breaker control
  
  adc_init(21, 20, 19, 18);
  
  set_directions(15, 0, 0b1111111111111111);  // pins 15 through 0 are outputs
  
  int d[] = {0b1110111, 0b1000100, 0b1101011, 0b1101110, 0b1011100,       //digits 0 through 9
             0b0111110, 0b0011111, 0b1100100, 0b1111111, 0b1111100};
        
      

  pause(1000);                    // Let hardware boot up
  while(1)
  {
       float amps = ((imax - 2.7)) * 3; // Scale Littlebird voltage to mean amps
       int a = (int) amps;        // intger part of amps
       float b = (10 * (amps - a));                
       int c = (int)b;            // fractional part of amps
       
       //print("%f, %d, %d\n", imax, a, c);
       
       set_outputs(15, 9, d[c]);  // c is the decimal value
       set_output(1,1);           // pin 1 is the decimal digit driver
       pause(8);
       set_output(1,0);
       set_outputs(15, 9, d[a]);  // a is the integer value
       set_output(2,1);           // pin 2 is the integer digit driver
       pause(8);
       set_output(2,0);             
  }  
}




    
void measure_imax()               // Runs in a different cog
{    
  while(1)
  {  
    for (int sample = 0; sample <= 60; sample++) // Littlebird samples per loop
       {   
          i =  adc_volts(2);     // i is instantaeous Littlebird voltage
                                   //
          if (i < 2.7)               //
          {                            //
            float temp = 2.7 - i;        //
            i = temp + 2.7;                //
          }                                  //
             float j = adc_volts(2);         
                                               // Invert samples below 2.7 volts
          if (j < 2.7)                         // to the same value above 2.7 volts
          {                                 //
            float temp = 2.7 - j;        //
            j = temp + 2.7;           //
          }                        //
             if (j > i)
               {
                 i = j;
               }        
          }
         
       
        imax = i;               // Stores maximum voltage sample
  }       
}



                      //2.75v reference voltage      Littlebird output of .33volts/Amp
void trip_breaker()          //Amps = (i - 2.75) x 3  
{
  if (i < 2.9)
  {
    set_output(0,1);         //Turn on breaker if current under .45 amps
  }
  
  while(1)
  {
    print("%f, %d, %d\n", imax);
    if (i > 2.9)
    {
      set_output(0,0);      //Turn off breaker and lock out if over .45 amps
    }      
  }     
          
}  


Why cant trip_breaker see "I"?

Comments

  • 16 Comments sorted by Date Added Votes
  • The trip_breaker function does see the variable "i". However, it might not capture the event when i is greater than if 2.9 if this happens for only a very short time. imax may have a value greater than 2.9, but trip_breaker may never see that value in i. Your print statement uses the format "%f, %d, %d\n", but you only provide a single argument to print. Is that intentional, or did you intend to print a couple of fixed point values along with the float value?

    It may also be possible that your set_output(0,0) is immediately undone by set_output(0,1) because i drops below 2.9 immediately after the set_output(0,0). I don't know your setup, so I can really tell you if that's the case. Maybe you could describe the circuit you're controlling.
  • Since breaker on is outside the main loop, can't this event only happen once? If I am wrong about this, it is probably the source of the problem.
  • I have a littlebird current sensor around one conductor of an extension cord. Its output is an AC signal offset by 2.75 VDC. One cog takes the signal, simulates full wave rectification with respect to the 2.75v midline. The ADC on the Propeller WX board takes a scatter sampling of the signal and finds the max value, called imax. Imax is decoded and converted to Amps in the main cog, and puts it on a 7 segment display. I want to throw a breaker based on certain amp threshholds to act as a GFI. Once it trips, I want it to stay off until the Propeller is reset. I am reading amps, the breaker turns on, but wont disengage. I had success throwing this breaker based on purely imax, so I know that this can work. I am just making a mistake. I am just now starting to use multicog designs and am discovering new ways to make mistakes. I think I should try moving "breaker on" before the main loop of cog 0, instead of where I have it now.
  • This implementation of breaker off is based on rectified instantaneous readings of the sensor, or "I". I know that I is a little ambiguous right now, but should still work. The final design wont have a LED display, so all the 7 segment decoding and imax shuffling won't be necessary. It will just be record I, if I is too big then throw breaker.
  • Yes, you are right. The break on is outside the loop, so that should only happen once before entering the loop. In measure_imax, I is updated 61 times for every update of imax. I not sure why this would make a difference over the long run. I would suggest printing the value of both I and imax in your trip breaker routine. This will tell you if I is ever above 2.9.

    Ultimately, it seems like you should move the measure_imax code into the trip_breaker function. I don't see a reason to have them in two difference cogs. This way, trip_breaker will be able to look at every sample that is measured.
  • It seems that in a cog other than 0, it matters where pins are declared as outputs.
  • you have to declare pins JUST in the COG using the pins. Nowhere else.

    all DIRAs and OUTAs from different COGs are 'or'-ed together.

    If one COG declares it as output, it is OUTPUT independent what other COGs think about it.

    And if one COG has it declared as output and set high, no other COG can change that.

    Enjoy!

    Mike


    I am just another Code Monkey.

    A determined coder can write COBOL programs in any language. -- Author unknown.

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this post are to be interpreted as described in RFC 2119.
  • /*
      GFI for safety extension cord
      
    */
    #include "simpletools.h"                      
    #include "adcDCpropab.h"
    
    void measure_imax();
    
    volatile float i;
    volatile float imax;
    
    int main()                                    // Main function runs 7 segment LED's in cog 0
    {
      
      cog_run(measure_imax,128);                  // Start littlebird measurments
      
      adc_init(21, 20, 19, 18);
      
      set_directions(15, 1, 0b111111111111111);  // pins 15 through 0 are outputs
      
      int d[] = {0b1110111, 0b1000100, 0b1101011, 0b1101110, 0b1011100,       //digits 0 through 9
                 0b0111110, 0b0011111, 0b1100100, 0b1111111, 0b1111100};
            
          
    
      pause(1000);                    // Let hardware boot up
     
      
      while(1)
      {
           float amps = ((imax - 2.7)) * 3; // Scale Littlebird voltage to mean amps
           int a = (int) amps;        // intger part of amps
           float b = (10 * (amps - a));                
           int c = (int)b;            // fractinal part of amps
           
           //print("%f, %d, %d\n", imax, a, c);
           
           set_outputs(15, 9, d[c]);  // c is the decimal value
           set_output(1,1);           // pin 1 is the decimal digit driver
           pause(8);
           set_output(1,0);
           set_outputs(15, 9, d[a]);  // a is the integer value
           set_output(2,1);           // pin 2 is the integer digit driver
           pause(8);
           set_output(2,0);             
      }  
    }
    
    
    
    
        
    void measure_imax()               // Runs in a different cog
    { 
    set_direction(0,1);
    set_output(0,1);   
      while(1)
      {  
        for (int sample = 0; sample <= 60; sample++) // Littlebird samples per loop
           {   
              i =  adc_volts(2);     //
              
             if (i > 2.9)
             {
               set_output(0,0);
               cog_end;
             }           
             
               
              
                          
                                       //
              if (i < 2.7)               //
              {                            //
                float temp = 2.7 - i;        //
                i = temp + 2.7;                //
              }                                  //
                 float j = adc_volts(2);         
                                                   // Invert samples below 2.7 volts
              if (j < 2.7)                         // to the same value above 2.7 volts
              {                                 //
                float temp = 2.7 - j;        //
                j = temp + 2.7;           //
              }                        //
                 if (j > i)
                   {
                     i = j;
                   }        
              }
             
           
            imax = i;               // Stores maximum voltage sample
      }       
    }
    



    Here "throw breaker" is in void measure_imax. This code works








    /*
      GFI for safety extension cord
      
    */
    #include "simpletools.h"                      
    #include "adcDCpropab.h"
    
    void measure_imax();
    void throw_breaker();
    
    volatile float i;
    volatile float imax;
    
    int main()                                    // Main function runs 7 segment LED's in cog 0
    {
      
      cog_run(measure_imax,128);                  // Start littlebird measurments
      cog_run(throw_breaker,128);
      
      adc_init(21, 20, 19, 18);
      
      set_directions(15, 1, 0b111111111111111);  // pins 15 through 0 are outputs
      
      int d[] = {0b1110111, 0b1000100, 0b1101011, 0b1101110, 0b1011100,       //digits 0 through 9
                 0b0111110, 0b0011111, 0b1100100, 0b1111111, 0b1111100};
            
          
    
      pause(1000);                    // Let hardware boot up
     
      
      while(1)
      {
           float amps = ((imax - 2.7)) * 3; // Scale Littlebird voltage to mean amps
           int a = (int) amps;        // intger part of amps
           float b = (10 * (amps - a));                
           int c = (int)b;            // fractinal part of amps
           
           //print("%f, %d, %d\n", imax, a, c);
           
           set_outputs(15, 9, d[c]);  // c is the decimal value
           set_output(1,1);           // pin 1 is the decimal digit driver
           pause(8);
           set_output(1,0);
           set_outputs(15, 9, d[a]);  // a is the integer value
           set_output(2,1);           // pin 2 is the integer digit driver
           pause(8);
           set_output(2,0);             
      }  
    }
    
    
    
    
        
    void measure_imax()               // Runs in a different cog
    { 
      while(1)
      {  
        for (int sample = 0; sample <= 60; sample++) // Littlebird samples per loop
           {   
              i =  adc_volts(2);     //                    
                                       //
              if (i < 2.7)               //
              {                            //
                float temp = 2.7 - i;        //
                i = temp + 2.7;                //
              }                                  //
                 float j = adc_volts(2);         
                                                   // Invert samples below 2.7 volts
              if (j < 2.7)                         // to the same value above 2.7 volts
              {                                 //
                float temp = 2.7 - j;        //
                j = temp + 2.7;           //
              }                        //
                 if (j > i)
                   {
                     i = j;
                   }        
              }
             
           
            imax = i;               // Stores maximum voltage sample
      }       
    }
    
    
    void throw_breaker()
    {
      set_direction(0,1);
      set_output(0,1);
      
      while(1)
      {
      
      if (i > 2.9)
             {
               set_output(0,0);
               cog_end;
             }     
      }   
    }
    

    Here "throw_breaker" is in its own cog and does not work. The breaker will turn on with set_output(0,1), but seems like the condition is never met for the breaker to turn off. If the condition is met, then set_output(0,0) is not functioning. What is the functional difference between the two methods. How can I make it work in a separate cog. Later throw_breaker will have more conditions by which to control the breaker, and will need to have its own cog if I understand the last response correctly.
  • Does measure_imax need to return the value "I"?
  • Any Ideas?
  • Beavis3215 wrote: »
    Any Ideas?
    Just some things I would try to test the compiler:

    - define the float i as static instead of volatile.

    - Use integer for i instead of float. There may be a problem with the float library used in different cogs. Just store the voltage in mV to get a good resolution:
      i = (int) (adc_volts(2) * 1000);
    
    Then the throw_breaker cog does not need float calculations:
      if (i > 2900) ...
    

    If it's not really necessary then don't use floats with microcontrollers, especially not if there is not float hardware.

    Andy

  • Thanks, makes sense. I will try it.
  • Beavis3215Beavis3215 Posts: 180
    edited August 28 Vote Up0Vote Down
    /*
      GFI for safety extension cord
      
    */
    #include "simpletools.h"                      
    #include "adcDCpropab.h"
    
    void measure_imax();
    void throw_breaker();
    
    static int imv;
    static int imax;
    
    int main()                                    // Main function runs 7 segment LED's in cog 0
    {
      
      cog_run(measure_imax,128);                  // Start littlebird measurments
      cog_run(throw_breaker,128);
      
      adc_init(21, 20, 19, 18);
      
      set_directions(15, 1, 0b111111111111111);  // pins 15 through 0 are outputs
      
      int d[] = {0b1110111, 0b1000100, 0b1101011, 0b1101110, 0b1011100,       //digits 0 through 9
                 0b0111110, 0b0011111, 0b1100100, 0b1111111, 0b1111100};
            
          
    
      pause(1000);                    // Let hardware boot up
     
      
      while(1)
      {
           float amps = (imax - 2700) *.003; // Scale Littlebird voltage to mean amps
           int a = (int) amps;        // intger part of amps
           float b = (10 * (amps - a));                
           int c = (int)b;            // fractinal part of amps
           
           print("%f, %d, %d\n", imax, a, c);
           
           set_outputs(15, 9, d[c]);  // c is the decimal value
           set_output(1,1);           // pin 1 is the decimal digit driver
           pause(8);
           set_output(1,0);
           set_outputs(15, 9, d[a]);  // a is the integer value
           set_output(2,1);           // pin 2 is the integer digit driver
           pause(8);
           set_output(2,0);             
      }  
    }
    
    
    
    
        
    void measure_imax()
                   
    { 
      while(1)
      {  
        for (int sample = 0; sample <= 60; sample++) // Littlebird samples per loop
           {   
              float i =  adc_volts(2);
              int imv = (int)(i * 1000);     //                    
                                       //
              if (imv < 2700)               //
              {                            //
                float temp = 2700 - imv;        //
                imv = temp + 2700;                //
              }                                  //
                 float j = adc_volts(2);
                 int jmv = (int)(j * 1000);         
                                                   // Invert samples below 2.7 volts
              if (jmv < 2700)                         // to the same value above 2.7 volts
              {                                 //
                int temp = 2700 - jmv;        //
                jmv = temp + 2700;           //
              }                        //
                 if (jmv > imv)
                   {
                     imv = jmv;
                   }        
              }
             
           
            imax = imv;               // Stores maximum voltage sample
      }       
    }
    
    
    void throw_breaker()
    {
      set_direction(0,1);
      set_output(0,1);
      
      while(1)
      {
      
      if (imv > 2900)
             {
               set_output(0,0);
               cog_end;
             }     
      }   
    }
    


    So I made the recommended changes, and for some reason the main loop cant see imax from measure_imax.
    I ran in terminal to verify that imax = 0, and a and b are negative numbers.
    Apparently I don't understand all of the rules yet, any ideas?
  • I think I need a different approach. There is a multicore example sharing data between 2 cogs that is different (has parameters in cogstart to make a variable global). Im not sure how to convert to share with a second cog.
  • Declare variables in a DAT section before you start your cogs.
  • How do I do that? I have never seen an example before.
Sign In or Register to comment.