Welcome to the Parallax Discussion Forums, sign-up to participate.

Should work, but does not

Posts: 180
```/*
GFI for safety extension cord

*/
#include "simpletools.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

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;                //
}                                  //
// 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"?

• Posts: 5,456
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.
• Posts: 180
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.
• Posts: 180
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.
• Posts: 180
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.
• Posts: 5,456
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.
• Posts: 180
It seems that in a cog other than 0, it matters where pins are declared as outputs.
• Posts: 1,939
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.
Press any key to continue, any other key to quit

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.
• Posts: 180
```/*
GFI for safety extension cord

*/
#include "simpletools.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

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
{

if (i > 2.9)
{
set_output(0,0);
cog_end;
}

//
if (i < 2.7)               //
{                            //
float temp = 2.7 - i;        //
i = temp + 2.7;                //
}                                  //
// 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"

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);

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
{
//
if (i < 2.7)               //
{                            //
float temp = 2.7 - i;        //
i = temp + 2.7;                //
}                                  //
// 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.
• Posts: 180
Does measure_imax need to return the value "I"?
• Posts: 180
Any Ideas?
• Posts: 2,182
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

• Posts: 180
Thanks, makes sense. I will try it.
• Posts: 180
edited August 2017
```/*
GFI for safety extension cord

*/
#include "simpletools.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);

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
{
int imv = (int)(i * 1000);     //
//
if (imv < 2700)               //
{                            //
float temp = 2700 - imv;        //
imv = temp + 2700;                //
}                                  //
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?
• Posts: 180
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.
• Posts: 1,142
Declare variables in a DAT section before you start your cogs.
• Posts: 180
How do I do that? I have never seen an example before.