ATTiny85; do{while} structure question or looping two sketches....

Hello All

My question pertains to a {while} or do {while} loop function:
I have two sketches which run as written and expected on the ATTiny85 (Digispark), excluding of course the built in pull-up / pull-down resistor which are integrated on the Digispark board for programming purposes…

The first sketch will (using one ADC input and a potentiometer) output a variable 3 to 60Hz gated signal. The minimum on time and duty cycle of this signal is controlled by user defined variables within the program.

The second sketch will (using two ADC inputs and two potentiometers) output another variable but faster signal, ie; 3 to 260Hz. Likewise the maximum on time and duty cycle are controlled by user defined variables within the program setup.

Both of the sketches run without flaws, (scoped-out) and require no modification when run separately.

OK, now the fun part…

So, I have spent at least 20 hours trying different loop functions in order to make the Second sketch run on a the condition that the output signal of the first sketch is HIGH, true, or 1 ie; (ledPin == HIGH).
I have also tried negating the conditional ie; output signal is !=LOW, !=false, or !=0 ie; (ledPin != LOW).

Basically what this program will do (if I can ever figure this out…) is produce a programmable and adjustable ( in real-time) Gated PWM signal for a DRSSTC.

Here is the last version of the looped code. (this code will to some degree give me what i want, but the code is erratic (buggy) in as much as it reacts to the gated signal but not following the exact temporal layout of the first of gating sketch.

One issue noted is that I want the digitalWrite(ledPin, HIGH); to function as part of the first sketch, as it is represented in the code. Much to my surprise, the LED does NOT light up, so I know something is very wrong with my looping.

I have included a couple of scope shots , the first show just the first sketch running as planned.
The second shows the semi-functional combine result of my looping effort. In this scope shot we can see that gating of the second signal is happening, but it is buggy and the digitalWrite(ledPin, HIGH); does NOT work.

I assume that I am making some basic error trying to configure the loop condition for the combination of the two sketches.

I would appreciate any and all comments, I am here to learn!

thanks in advance.
mjd

OK , Here is the code:

*/
#include <C:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny/WProgram.h>
#include <C:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny/wiring.h>

/*
User definable variables here - this is all you need to adjust!
*/

int maxontime = 2000;          // us - no greater than (32768/5) or 6553us!!
int gateminontime = 10000;     // us - minimum gate on time
int offThresh = 83;            // Define (offTresh/1023 * 5)Volts as off-threshold
float duty = 0.30;             // Max Duty Cycle desired (here it's 30%)
float gdutymax = 0.90;         // Max Gating Duty Cycle

// vpw, vgate and vbs takes an analogRead in for 0 to 1023 as output
// with 1023 for 5V and 0 for 0V.

int vpw;
int vbps;
int vgate;

// Create other variables

float gperiod;                 // us
float gateontime =0;      // always us
int critfreq = (1000000 * duty) / maxontime; // Hertz
int gcritfreq = (1000000 * (gateontime/gperiod)) / gperiod ; // Hertz
float ontime = 0;          // always us
float offtime = 0;         // ms or us
float gateofftime =0 ;  // ms or us
float freq;                   // BPS Hertz
float period;               // us
float gating;               // BPS Hertz

// Define pins for ATTiny85

int outPin = 0;          // PhysicalPin 5; P0
int ledPin = 1;          // PP 6; P1
int gatePin = 3;       // PP 2; P3
int bpsPin = 2;    // PP 3; P4
int pwPin = 1;     // PP 7; P2

void setup() {
                         // initialize the digital pins as an output:
pinMode(outPin, OUTPUT);
pinMode(ledPin, OUTPUT);
}

void loop() {

vpw = analogRead(pwPin);                     // read pw voltage
vbps = analogRead(bpsPin);                   // read bps voltage and calc T and f.
vgate = analogRead(gatePin)-offThresh; // read gate voltage

// will turn off output when *vgate* potentiometer is taken low

if (vgate < 0) {
digitalWrite(outPin, LOW);       // Off
digitalWrite(ledPin, LOW);       // Off
delayMicroseconds(100);         // Short delay
}

else {

gating = 1 + (vgate + 12) / 12;         // Gating frequency varies from 1-60Hz depending on offThresh


/*
If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
the period variable runs over! Hence, we make sure this doesn't happen by
counting the numbers in milliseconds instead of microseconds.
Else, we can be free to count in microseconds
*/


if (gating < 31) {

gperiod = (1.0 / gating) * 1000;      // ms

     gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms

if (gateontime < gateminontime) {
  gateontime = gateminontime;
}

gateofftime = gperiod - gateontime / 1000; // period in ms

/*
   Now send the output signals  
*/    

 //digitalWrite(outPin, HIGH );         // On *USE For DeBugging only*
 digitalWrite(ledPin, HIGH);             // On
 delayMicroseconds(gateontime);    // delay in us

 //digitalWrite(outPin, LOW);          // Off *USE For DeBugging only*
 digitalWrite(ledPin, LOW);             // Off
 delay(gateofftime);                       // delay in ms
 
                            // run 'output()' loop when condition is met
while (digitalWrite,(ledPin) == HIGH) {      // (gateontime == 1) with gate LED & Low frequency;
     output();
  (digitalWrite,(ledPin) == LOW);              // or use; (ledPin == HIGH) No gate LED & High frequency;
}
}

else {
gperiod = (1.0 / gating) * 1000000; // us

if (gating > gcritfreq) {
  gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
}

else {

  gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
}

              // Calculate gateofftime, capping the on-time to some max

if (gateontime < gateminontime) {
  gateontime = gateminontime;
}

gateofftime = gperiod - gateontime;  // period in us

// Now send the gateoutput signals in microseconds

//digitalWrite(outPin, HIGH);            // On *USE For DeBugging only*
digitalWrite(ledPin, HIGH);               // On
delayMicroseconds(gateontime);      // delay in us

//digitalWrite(outPin, LOW);            // Off *USE For DeBugging only*
digitalWrite(ledPin, LOW);               // Off
delayMicroseconds(gateofftime);     // delay in us   if (digitalRead(buttonPin) == HIGH)

                           // run 'output()' loop when condition is met
while (digitalWrite,(ledPin) == HIGH) {       // (gateontime == 1) with gate LED & Low frequency;
output();
 (digitalWrite,(ledPin) == LOW);                // or use; (ledPin == HIGH) No gate LED & High frequency;
} 
}
}               
}

////////////output()LOOP///////////////

void output(){
vpw   = analogRead(pwPin);
vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
vgate = analogRead(gatePin)-offThresh;

if (vgate < 0){
digitalWrite(outPin, LOW);         // Off
digitalWrite(ledPin, LOW);         // Off
delayMicroseconds(100);           // Short delay
}

else {

freq = 1 + (vbps + 2) /2;             // frequency varies from 1-290Hz depnding on offThresh
                                              // This is also why we divide by 2 (from 1023)
if (freq < 31) {
period = (1.0 / freq) * 1000;       // ms


ontime = 1 + (vpw / 1023.0) * maxontime; // us

if (ontime > maxontime) {
ontime = maxontime;
}

offtime = period - ontime / 1000; // period in ms

// Now send the output signals

digitalWrite(outPin, HIGH);          // On 
//digitalWrite(ledPin, HIGH);         // On debuggin only
delayMicroseconds(ontime);          // delay in us

digitalWrite(outPin, LOW);           // Off 
// digitalWrite(ledPin, LOW);         // Off debuggin only
delay(offtime);                            // delay in ms

}

else {

period = (1.0 / freq) * 1000000;                          // us

if (freq > critfreq) {
ontime = 1 + (vpw / 1023.0) * period * duty;    // period in us
}
else {
ontime = 1 + (vpw / 1023.0) * maxontime;      // period in us
}

// Calculate off-times, capping the on-time to some max

if (ontime > maxontime) {
ontime = maxontime;
}

offtime = period - ontime;        // period in us

// Now send the output signals in microseconds

digitalWrite(outPin, HIGH);        // On 
// digitalWrite(ledPin, HIGH);     // On debuggin only
delayMicroseconds(ontime);      // delay in us

digitalWrite(outPin, LOW);        // Off 
// digitalWrite(ledPin, LOW);      // Off debuggin only
delayMicroseconds(offtime);      // delay in us
}
}
} 
/////////////////////END////////////////////

Forgot to attach code:

Forgot to put it in code tags either.

Please read the how to use this forum sticky.

digitalWrite,(ledPin) == LOW
Is not the correct syntax for digitalWrite.

Hello Grumpy

"quote" "digitalWrite,(ledPin) == LOW Is not the correct syntax for digitalWrite."

Thanks for pointing out the typo in my first post above, I corrected it..... In the code it is written correctly.

In the code it is : ' while (digitalWrite,(ledPin) == HIGH) { ' //this is my command for the start of the {while} loop.........

If this is not correct, then this is the problem with the code......

thanks mjd

while (digitalWrite,(ledPin) == HIGH)

`there should be no comma between digitalWrite and the brackets.

That code is wrong anyway as digital write is an output and you are not setting the output to anything. Do you mean digitalRead?

Hello Grumpy

Well, I tried to compile it without the comma, and this is the error message:

:196:32: error: too few arguments to function 'void digitalWrite(uint8_t, uint8_t)'

196 is the line of code where I deleted the comma, and #32 corresponds to the 'n' in ledPin.

Arduino: 1.5.8 (Windows 7), Board: "Digispark (Default - 16.5mhz)"

C:\Program Files\Digistump_Arduino/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD -mmcu=attiny85 -DF_CPU=16500000L -DARDUINO=158 -DARDUINO_AVR_DIGISPARK -DARDUINO_ARCH_AVR -IC:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny -IC:\Program Files\Digistump_Arduino\hardware\digistump\avr\variants\digispark C:\Users\x\AppData\Local\Temp\build4427694372223952310.tmp\v0.63_-_Tested_fully_working__1-254Hz__0-1500us__4working3e.cpp -o C:\Users\x\AppData\Local\Temp\build4427694372223952310.tmp\v0.63_-_Tested_fully_working__1-254Hz__0-1500us__4working3e.cpp.o 

v0.63_-_Tested_fully_working__1-254Hz__0-1500us__4working3e.ino: In function 'void loop()':
v0.63_-_Tested_fully_working__1-254Hz__0-1500us__4working3e.ino[b]:196:32: error: too few arguments to function 'void digitalWrite(uint8_t, uint8_t)'[/b]
In file included from C:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny/WProgram.h:12:0,
                 from v0.63_-_Tested_fully_working__1-254Hz__0-1500us__4working3e.ino:98:
C:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny/wiring.h:169:6: note: declared here
 void digitalWrite(uint8_t, uint8_t);
      ^
Error compiling.

If I insert the comma, then it will compile.

Don't see what I am doing wrong... Thanks mjd

Don't see what I am doing wrong...

I have told you.

You are using digitalWrite in a conditional statement, that it just silly.

If I insert the comma, then it will compile.

It might but it is not doing what you want. All it means when you compile successfully is that the compiler can convert what you wrote into machine code. It does not mean what you wrote makes sense. For example try putting one equals sign in an if statement. It compiles but the if statement will not work.

What do you want to happen when you write that line?

Hello Grumpy

Yes, you are correct... G-in & G-out.

I want the program to 'Read' the line, not 'Write' the line..... So, I changed the code to: while(digitalRead(ledPin)==1) { ...... I also tried : while(digitalRead(ledPin)==HIGH) { .............

Yes, it now complies without the comma, which is good. And... the ' digitalWrite(ledPin, HIGH); ' will turn on the LED, which is good. This signifies that the first half of the sketch is running correctly.....

But, I have no output from my 'output()' loop function, so I still do not have the proper syntax to combine both sketches.

I believe that maybe I should be using a different signal/output to trigger off of. In truth the condition of ledPin is just the result of the state of 'gateontime' . I should probably try to use 'gateontime' as my trigger signal.

What is your opinion? Thanks mjd

I can't follow what the output function is trying to do.

I would suggest that you use Serial.print statements to print the values of your variables to see if they are being calculated correctly. And also that parts of the sketch are being reached that you expect to be reached.

Good afternoon Grumpy

Thanks for taking the time to check out the code.

"I can't follow what the output function is trying to do."

The output() loop is only being used to initiate/run the second sketch. The idea is to run the output() loop during the mark time (gateontime) of the first sketch's signal. gateofftime then corresponds to the signal deadtime.

The second sketch which corresponds to the output() loop function runs perfectly (as does the First Sketch) when run by itself.

All my variables and mathematics are correct as far as each individual and uncombined sketch is concerned. I say this because each separate sketch works as planned. The signals are clean as verified by the scope shots.

As far as I can tell, ( I am new to Arduino, studied Cobol, Basic in the 70's......) the problem is the linkage syntax that I am attempting to use.

I have Googled and tried various examples from different Arduino code, but am beginning to think it might be something related to the actual mechanics of the ATTiny85 architecture.

I will keep trying to figure this out, as I need this software to finish my project (and don't like the idea of an eight legged IC getting the best of me :fearful: )

I will try the Serial.print statements...... but I already know that the output() loop is NOT activating.

thanks mjd

Hello All

OK, I have cleaned up the code…

.

 */
#include <C:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny/WProgram.h>
#include <C:\Program Files\Digistump_Arduino\hardware\digistump\avr\cores\tiny/wiring.h>
/*
User definable variables here - this is all you need to adjust!
Depends on what sort of Tesla Coil you are running. My coil performs well
with 1500us on time, but YMMV! DRSSTCs run more around 100 to 300us.
*/

int maxontime = 2000;          // us - no greater than (32768/5) or 6553us!!
int gateminontime = 10000;     // us - minimum gate on time
int offThresh = 83;            // Define (offTresh/1023 * 5)Volts as off-threshold
float duty = 0.30;             // Max Duty Cycle desired (here it's 30%)
float gdutymax = 0.90;         // Max Gating Duty Cycle  (here it's 90%)

// vpw, vgate and vbs takes an analogRead in for 0 to 1023 as output
// with 1023 for 5V and 0 for 0V.

int vpw;
int vbps;
int vgate;
// Create other variables

float gperiod;          // us
float gateontime =0;      // always us
int critfreq = (1000000 * duty) / maxontime; // Hertz
int gcritfreq = (1000000 * (gateontime/gperiod)) / gperiod ; // Hertz
float ontime = 0;      // always us
float offtime = 0;     // ms or us
float gateofftime =0 ; // ms or us
float freq;            // BPS Hertz
float period;          // us
float gating;          // BPS Hertz
 
// Define pins for ATTiny85

int outPin = 0;    // PhysicalPin 5; P0
int ledPin = 1;    // PP 6; P1
int gatePin = 3;   // PP 2; P3
int bpsPin = 2;    // PP 3; P4
int pwPin = 1;     // PP 7; P2

void setup() {
                               // initialize the digital pins as an output:
  pinMode(outPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() { 
   
  vpw = analogRead(pwPin);               // read pw voltage
  vbps = analogRead(bpsPin);             // read bps voltage and calc T and f.
  vgate = analogRead(gatePin)-offThresh; // read gate voltage

  // will turn off output when *vgate* potentiometer is taken low
  if (vgate < 0) {
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
    }

  else {

    gating = 1 + (vgate + 12) / 12; // Gating frequency varies from 1-60Hz depnding on offThresh
    

    /*
      If the period becomes > 2^15 us (T = 32.768ms or f less than 30.51Hz), then
    the period variable runs over! Hence, we make sure this doesn't happen by
    counting the numbers in milliseconds instead of microseconds.
      Else, we can be free to count in microseconds
    */
       

    if (gating < 31) {

      gperiod = (1.0 / gating) * 1000;                               // ms

           gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); //ms
     
      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime/1000;                       // period in ms
      
      /*
         Now send the output signals  
     */    
      
       //digitalWrite(outPin, HIGH );    // On *USE For DeBugging only*
       digitalWrite(ledPin, HIGH);       // On
       delayMicroseconds(gateontime);    // delay in us

       //digitalWrite(outPin, LOW);      // Off *USE For DeBugging only*
       digitalWrite(ledPin, LOW);        // Off
       delay(gateofftime);               // delay in ms
      
              // run 'output()' loop when condition is met
while(digitalRead(ledPin)==HIGH){                       
    output();
      (digitalRead(ledPin)==LOW);                 
    } 
 }

    else {
      gperiod = (1.0 / gating) * 1000000; // us

      if (gating > gcritfreq) {
        gateontime = 1 + ((vgate*1.05) / 1023.0) * (gperiod * gdutymax); // period in us
      }

      else {

        gateontime = 1 + (vgate / 1023.0) * (gperiod * gdutymax); // period in us
      }

      // Calculate gateofftime, set limit on minimum gateontime

      if (gateontime < gateminontime) {
        gateontime = gateminontime;
      }

      gateofftime = gperiod - gateontime;  // period in us
      
      
      // Now send the gateoutput signals in microseconds
     
      //digitalWrite(outPin, HIGH);       // On *USE For DeBugging only*
      digitalWrite(ledPin, HIGH);         // On
      delayMicroseconds(gateontime);      // delay in us

      //digitalWrite(outPin, LOW);        // Off *USE For DeBugging only*
      digitalWrite(ledPin, LOW);          // Off
      delayMicroseconds(gateofftime);     // delay in us   
      
              // run 'output()' loop when condition is met
while(digitalRead(ledPin)==HIGH){                       
    output();
      (digitalRead(ledPin)==LOW);                       
      }
    }
  }               
}

////////////output()LOOP///////////////

  void output(){
  vpw   = analogRead(pwPin);
  vbps  = analogRead(bpsPin);       // ranges from 0 to 1023
  vgate = analogRead(gatePin)-offThresh;
  
  if (vgate < 0){
    digitalWrite(outPin, LOW);      // Off
    digitalWrite(ledPin, LOW);      // Off
    delayMicroseconds(100);         // Short delay
  }

  else {

  freq = 1 + (vbps + 2) /2; // frequency varies from 1-290Hz depnding on offThresh
  // This is also why we divide by 2(from 1023)
  if (freq < 31) {
    period = (1.0 / freq) * 1000;       // ms
    
    ontime = 1 + (vpw / 1023.0) * maxontime; // us

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime / 1000; // period in ms

    // Now send the output signals

    digitalWrite(outPin, HIGH);       // On 
    //digitalWrite(ledPin, HIGH);     // On debugging only
    delayMicroseconds(ontime);        // delay in us

    digitalWrite(outPin, LOW);        // Off 
    //digitalWrite(ledPin, LOW);      // Off debugging only
    delay(offtime);                   // delay in ms

  }

  else {

    period = (1.0 / freq) * 1000000; // us

    if (freq > critfreq) {
      ontime = 1 + (vpw / 1023.0) * period * duty; // period in us
    }
    else {
      ontime = 1 + (vpw / 1023.0) * maxontime; // period in us
    }

    // Calculate off-times, limit the on-time to some max

    if (ontime > maxontime) {
      ontime = maxontime;
    }

    offtime = period - ontime;      // period in us

    // Now send the output signals in microseconds

    digitalWrite(outPin, HIGH);       // On 
    //digitalWrite(ledPin, HIGH);     // On debugging only
    delayMicroseconds(ontime);        // delay in us

    digitalWrite(outPin, LOW);        // Off 
    //digitalWrite(ledPin, LOW);      // Off debugging only
    delayMicroseconds(offtime);       // delay in us
    }
  }
 }
/////////////////////END////////////////////

Now, with the modifications made, I have the first half of the program working exactly as I want it to.

The second half, denoted after * ////////////output()LOOP///////////////* will run perfectly by itself, so I know that the code is working as it should be.

My problem is that all the commands I have tried to implement in order to make the output(()LOOP run simultaneously with the first half of the program have failed.

I cannot get the second half (////////////output()LOOP///////////////) to run with any configuration of {while} statements.

Is there some trick to make the ATTiny85 respond to {while} loops?

Thanks
mjd

My problem is that all the commands I have tried to implement in order to make the output(()LOOP run simultaneously with the first half of the program have failed.

There is no way you can do that, this is a single core processor. In order for things to appear to run at the same time you must implement a state machine.

See my http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html Or Robin2's several things at once http://forum.arduino.cc/index.php?topic=223286.0

Hello Grumpy.

Thanks for taking the time to answer this question:

So if I understand correctly;

I am asking to run a function (output();) all the while another condition is being met. But, because the processor is a single core, single thread topology, It CANNOT make BOTH actions happen concurrently...........

This would explain why I observe only 1/2 of my program functioning at a time, sometimes the code will signal once (one time pulse) from the output() in time with the gating signal from the first half of the program. Then it seems to reset itself and start the code over instead of giving the multiple burst type cycles called for in the code. Second part of program responds with only one pulse each time it is called. The end result is ONLY one pulse per gated signal.

So..... the solution is to rewrite the code utilizing 'State Machine' logic.

State Machine logic will permit the appearance of multiple threads and thereby allow my code to run?

I will study the links that you provided. Thanks and have a great day! mjd

State Machine logic will permit the appearance of multiple threads and thereby allow my code to run?

Yes that is it. With a state machine you can keep doing little bits of both programs so they look like they are both running.

Excellent Grumpy

Thanks for all the help. If I have a further question regarding State machine logic I will post here again.

take care, peace mjd

Good day Grumpy:

OK, I have studied the example of the link that you gave me.

This is my synopsis:

  1. All of the concurrent parts or functions of the sketch run according to the processor timer.

  2. All concurrent parts of the sketch run independent from one another.

  3. There is NO interaction between any of the three LEDs nor servo functions of the sketch.

  4. All events produced by the different functions of the sketch appear to be happening at the same time (they are concurrent) with only one processor, but............ they are NOT interactive, they might as well be four separate sketches.

What have I missed here?

Can you give me just a hint as to how I can make one function conditional to another function and have both still function?

take care, peace mjd

You can make them interact by using global variables, things can be set by one process and read by another.

Good day Grumpy

OK,:

Global variable: byte LedState = LOW;

1st: Make first function() control LedState;

2nd: Make second function() conditional to LedState;

Last: Have last function() digitalWrite(ledPin, LedState);

Is this the idea?

take care, peace mjd

Yes I think you have got it. :)