Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 38 of 38

Thread: KISS problem setting Millis timed pulses during ON time

  1. #26
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    good morning,

    i played a bit with the ElapsedMillis();

    so far i got two signals that are shifted please see pictures:
    Attachment 24520
    Attachment 24521
    Attachment 24522

    but the pulse train stops after a period of time of 1 second and doesnt repeat.


    i removed the functionRepetition_Polarity_Change_Emag()
    and used if else statements after the independent on off.

    could someone elaborate the ElapsedMillis why it doesnt work inside a nested if statement as in the CODE3?
    it just defies logic for me, but it has to do with the global variable i think of ElapsedTimeIndependent and is overwritten?

    this code works and creates a pulsetrain for 1 second with 12ms period. 2ms of this period is the pulse HIGH the other signal for unknown reason stays low.

    any advice?
    Code:
    //Defining the pins
    
    const int INB_AntiClockwise       = 2;
    const int INA_Clockwise           = 3;
    
    unsigned long previousMillis = 0;
    
    unsigned long Timestamp = 10; //10ms per division
    unsigned long PulseWidth = 2; //variable for setting the pulse
    unsigned long timer;
    unsigned long timer2;
    bool VNH5019 = LOW;   //it has not effect changing this from int to byte
    
    unsigned int ON_Time1 = 1000;                     //ON Time
    unsigned int OFFTime1 = 1000;                     //OFF Time
    
    elapsedMillis ElapsedTime;                         //ElapsedMillis for pulses and period
    elapsedMillis ElapsedTimeIndependent;
    elapsedMillis pulse;                               //ElapsedMicros
    
    void setup()
    {
      Serial.begin(9600);
    
      pinMode(13, OUTPUT); digitalWrite(13, LOW);
      pinMode(INB_AntiClockwise, OUTPUT); digitalwrite(INB_AntiClockwise, LOW);
      pinMode(INA_Clockwise, OUTPUT); digitalWrite(INA_Clockwise, LOW);
    
    }
    
    void loop()
    {
    
    
    
      if ((VNH5019 == HIGH) && (ElapsedTimeIndependent >= OFFTime1)) //OFFTime first
      {
        VNH5019 = LOW;
        digitalWrite(INA_Clockwise, LOW); digitalWrite(INB_AntiClockwise, LOW);  //doesnt matter high or low both need to be HIGH or LOW.
        ElapsedTimeIndependent = 0;//this resets the elapsedTime
      }
      else if ((VNH5019 == LOW) && (ElapsedTimeIndependent >= ON_Time1)) //ONTime 1 second
      {
        //Serial.println("On Time");//so that i know i am in this part of the else if statement
        VNH5019 = HIGH;
        //   Repetition_Polarity_Change_Emag();  //this functions sets the PulseWidth and the Period //here I call the function
    
      }
      else if (ElapsedTimeIndependent >= (timer + Timestamp)) 
      {
        digitalWrite(INA_Clockwise, HIGH);
        digitalWrite(INB_AntiClockwise, LOW);
        timer = ElapsedTime + 2; //pulse is shifted with 2ms
        timer2 = ElapsedTime;
        //duration of the Pulse is set here.
        Serial.println("TimeStamp");
      }              // Sets the Output Low for the pulse
      else if ((pulse) > (timer + Timestamp)) 
      {
        digitalWrite(INA_Clockwise, HIGH);
        // Turn the output back to High
    
      }
      else if ((pulse) > (timer2 + Timestamp)) //create a shift between the INA and the INB
      {
    
        digitalWrite(INB_AntiClockwise, HIGH);
        // Turn the output back to High
    
    
      }
          
    
    }

  2. #27
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,080
    Again you've posted code which does not compile when copied into Arduino. In this case the mistake appears to be "digitalwrite" (the W not capitalized) which is an easy problem to fix. Still, I wonder if this really is code you actually used on your Teensy? Why is this sort of error present if you simply copy the code in Arduino and paste it here to the forum?

    Still, I'm trying to look at this again and help if I can.

    First, to answer your specific questions from msg #25:


    Question1: could someone elaborate the ElapsedMillis why it doesnt work inside a nested if statement as in the CODE3?
    elapsedMillis does indeed work from inside nested if statements. The problem is not with elapsedMillis.


    Question2:
    it just defies logic for me, but it has to do with the global variable i think of ElapsedTimeIndependent and is overwritten?
    The problem is larger than any one specific variable or conditional expression in the code.

    Essentially there are 2 large problems here.

    1: Your coding approach is not good.

    2: I can't understand from the words you've written what the program is supposed to do.

    Regarding #2, perhaps you could draw on paper or graphics software a picture of the desired result?

  3. #28
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,080
    Here is an example which can hopefully show you a better way to approach this sort of programming task.

    This a programming paradigm called a state machine. It is a widely used approach in computer programming because it provides a clear way to design your code to meet requirements.

    First, start with a picture of your desired waveform and assign a state number of each portion of the waveform. A clear picture of every state of your designed waveform is the critical key to successfully coding a state machine program. To keep this simpler, here's a waveform which begins with 3 slower pulses, then has an off time, then repeats a burst of 4 faster pulses with a shorter off time between each burst.

    Click image for larger version. 

Name:	statemachine1.jpg 
Views:	7 
Size:	37.4 KB 
ID:	24535

    As you can see, I assigned 6 different states. Each pulse has 2 states, and the 2 off times are their own state.

    Using a single variable for the overall state of your waveform is my primary recommendation. Structure the first level of if-else conditions around this state variable.

    In this example, a secondary state variable counts the number of pulses. You should strive use as few variables as possible. DO NOT add more state variables unless they are truly necessary. The most states, the harder your code is to write and test and debug.

    Usually only 1 elapsedMicros is needed. Do not add more.

    Before you start coding, it's often helpful to draw a map of which states can transition to which other states. This diagram can help you to write correct code because each circle becomes a 1st level "if" and each arrow becomes a 2nd nested "if" inside the condition for the state where it originates (and the code within that 2nd level "if" depends on where the arrow points).

    Click image for larger version. 

Name:	statemachine2.jpg 
Views:	3 
Size:	46.9 KB 
ID:	24536

    For this example, when in state 2, the only possible outcomes from running loop() are to remain in state 2 or to transition to state 4. When in state 3, the possible outcomes from loop() are to remain in state 3 or transition to state 4 or state 5. Knowing which states can transition to which other states is critically important. Each possible transition to a different state becomes a nested "if" condition.

    Here is the code to implement this simple example.

    Code:
    int state;
    int pulseCount;
    elapsedMicros usec;
    
    void setup() {
      // begin state 0
      pinMode(2, OUTPUT);
      digitalWrite(2, LOW);
      while (!Serial && millis() < 5000) ; // wait up to 5 seconds for Arduino Serial Monitor
      // initial state:
      state = 0;
      pulseCount = 0;
      usec = 0;
      Serial.println("Begin program at state 0");
    }
    
    void loop() {
    
      switch (state) {
        case 0: // low portion of slower pulse
          if (usec >= 800) {
            // transition to state 1
            digitalWrite(2, HIGH);
            pulseCount = pulseCount + 1;
            usec = 0;
            state = 1;
            Serial.println("begin state 1");
          }
          break;
    
        case 1: // high portion of slower pulse
          if (usec >= 800) {
            if (pulseCount < 3) {
              // transition back to state 0 if not enough pulses delivered
              digitalWrite(2, LOW);
              usec = 0;
              state = 0;
              Serial.println("begin state 0");
            } else {
              // transition to state 2 after enough slow pulses
              digitalWrite(2, LOW);
              usec = 0;
              state = 2;
              Serial.println("begin state 2");
            }
          }
          break;
    
        case 2: // off time between slower & faster pulses
          if (usec >= 10000) {
            // transition to state 4 to start fast pulsing
            digitalWrite(2, LOW);
            usec = 0;
            pulseCount = 0; // reset pulsecount, since states 3+4 will count pulses
            state = 4;
            Serial.println("begin state ");
          }
          break;
    
        case 3: // high portion of faster pulse
          if (usec >= 400) {
            if (pulseCount < 4) {
              // transition back to state 4 if not enough pulses delivered
              digitalWrite(2, LOW);
              usec = 0;
              state = 4;
              Serial.println("begin state 4");
            } else {
              // transition to state 5 after enough fast pulses
              digitalWrite(2, LOW);
              usec = 0;
              state = 5;
              Serial.println("begin state 5");
            }
          }
          break;
    
        case 4: // low portion of faster pulse
          if (usec >= 400) {
            // transition to state 3
            digitalWrite(2, HIGH);
            usec = 0;
            pulseCount = pulseCount + 1;
            state = 3;
            Serial.println("begin state 3");
          }
          break;
    
        case 5: // off time between bursts of faster pulses
          if (usec >= 5000) {
            // transition back to state 4 to restart fast pulsing
            digitalWrite(2, LOW);
            usec = 0;
            pulseCount = 0;
            state = 3;
            Serial.println("begin state 3 (starting new burst of pulses)");
          }
          break;
    
        default: // state should never be anything other than 0 to 5
          setup();
      }
    }
    The most important concept is to use a clear structure in the code, where each of the first level conditions corresponds to the current state. Within each current state, every second level "if" condition corresponds to exactly 1 of the possible transitions to a different state. For a state like state 3, there are two "if" conditions because state 3 can end with a transition to either state 4 or to state 5.

    Here is the waveform the code creates.

    Click image for larger version. 

Name:	file.png 
Views:	3 
Size:	25.8 KB 
ID:	24537

    While there are many possible way to write your code, I highly recommend you follow this state machine approach. Drawing the waveform on paper, assigning states to each portion, and then drawing the state transition diagram may seen like "trivial" work, but you should do those steps before writing any code. The state transition diagram is particularly important, because as you can see in this example, each item on the diagram becomes a 1st tier or 2nd tier "if" condition. Planning the state machine properly can give you a way to easily write code which will be correct. That is why this state machine programming technique is so widely used.

    If you follow this approach and avoid the temptation to add unnecessary state variables, I'm sure you can find a path towards success.

    While I used numbers 0 to 5 in this simple example, it is common practice to give a name to each state. That can help if your goals require a larger number of states.

    But for communicating your project goals on this forum or on Facebook, I'm afraid I do not have a well defined process like the state machine programming paradigm. Writing clearly in English is difficult. Maybe try drawing pictures of the waveform your program is attempting to create. A diagram like I showed in this example can help communicate. We can try to help you, but without a clear idea of what your program should do, it is very difficult to help.

    Hopefully this simple example at least helps you start on a path to success using the state machine programming approach?

  4. #29
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,080
    While the state machine structure (and drawing the diagrams for planning your code) is by far the most important point, you might also consider a couple minor details about use of elapsedMicros.

    Generally your "if" conditions checking elapsedMicros should look like this, where you check if the elapsed time has become greater than a specific constant or value of a configuration variable.

    Code:
        case 4: // low portion of faster pulse
          if (usec >= 400) {
            // transition to state 3
            digitalWrite(2, HIGH);
            usec = 0;
            pulseCount = pulseCount + 1;
            state = 3;
            Serial.println("begin state 3");
          }
          break;
    I specifically would advise against this sort of structure.


    Code:
      else if (ElapsedTimeIndependent >= (timer + Timestamp))
    Follow an approach where you either set the elapsedMicros variable back to zero, or subtract a constant from it, when you transition to a different state. Then within that state, your "if" conditions checking elapsed time should be kept simple. Only check if the time has become greater than (or equal or greater than) a constant or configuration setting.

    While writing code which computes thresholds like "(timer + Timestamp)" is technically legal code, this sort of approach quickly becomes very confusing. When coupled with an increasing number of ad-hoc if-else conditions and too many redundant state variables, it turns into a terribly difficult and confusing mess. This of this as trying to shoot a moving or changing target! Keep the target only a simple fixed number.

    Use the state machine approach with a clearly drawn state transition diagram, so your code structure is clearly determined by the states and their allowed transitions. Together with only setting the elapsedMicros as needed at state transitions and testing it against only a simple constant (no math of the threshold, only a fixed number) your code will be much simpler to understand and debug.

  5. #30
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,910
    Nicely done Paul

  6. #31
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    Paul,

    Many thanks for your time, understanding, and your explanations.
    Really appreciated!

    The state machine: I only worked with small examples till now. Also including simple if statements.
    I was confused because one of the posts, there was a suggestion that I should reduce the number of elapsedMillis. I was wondering and looking up the various code examples that I lost track.

    Also I was gradually becoming more and more confused, I didn’t know that substracting a value from elapsedMillis could benefit me in this case.

    I used in other code the case structure for a 6pst switch. To select between different menus. I didn’t think this could be adapted for creating signals. But that’s another topic in total.

    As you can see I have a shallow understanding of programming, or a large imagination missing out the smaller details in this case.


    Back to the topic state machine
    ———

    my program consists of three states

    First state OFF: both outputs 2,3 are to be LOW during this time.

    Second state ON: ON can only be reached if the condition of state 1 is fulfilled/reached.

    Third state: Period:// i am confused here because i don't know if the approach is right or where to set the period. here or in the other state. so i splitted up the third state into fourth state Pulse and fifth state dead time for Output2. so correct me if i am wrong, please with red. i thought this makes sense in how to work with the State Diagram. As i said i am confused.and i dont know if i am doing it corectly

    Fourth state

    Output 2 requires to HIGH for 2ms

    Fifth state:
    Output 2 requires to be LOW for 8ms
    ----------------------------------- OUTPUT 3
    Fourth State
    Output 3 LOW 2ms

    Fifth state:
    Output 3 HIGH 2ms

    Sixth State:
    Output 3: LOW 6ms.
    ----------------------------------

    Click image for larger version. 

Name:	State Diagram.jpg 
Views:	5 
Size:	56.6 KB 
ID:	24541
    Click image for larger version. 

Name:	signal diagram for StateDiagram.jpg 
Views:	5 
Size:	44.0 KB 
ID:	24542

    ------------------------------------------------
    final question:
    OUTPUT 2:
    State1:if ElapsedMillis>=OFFTime
    State2:else if ElapsedMillis>=ONTime
    State3:else if (ElapsedMillis>=Period ) 10ms
    State4:if(ElapsedMillis>Pulse) 2ms OUTPUT2 =HIGH;
    State5:if(ElapsedMillis>Deadtime) 8ms OUTPUT2 =LOW;

    OUTPUT3:
    State1:if ElapsedMillis>=OFFTime
    State2:else if ElapsedMillis>=ONTime
    State3:else if (ElapsedMillis>=Period ) 10ms
    State4:if(ElapsedMillis>Pulse) 2ms OUTPUT3=LOW;
    State5:if(ElapsedMillis>) 2ms OUTPUT3=HIGH // i am confused with the OUTPUT2 State 4 pulse and deadtime because would like to shift it with 2ms
    State6:if(ElapsedMillis>Deadtime


    if the Period is set to a higher value then the ON Time.
    Were in the code do i check for this condition? between state 2 and state 3?
    where do i reset the elapsedMillis =0;
    using multiple elapsedMillis isnt that easier?

    so i have to program like this?

    thanks
    Last edited by Bastiaan; 04-23-2021 at 08:38 AM.

  7. #32
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,910
    not easy to follow - these questions hit me to look at it::

    when : "my program consists of three states" then lists up to the sixth state? And notes on OUTPUT 2 and 3 - but OUTPUT 1 not indicated?

    How many total outputs are there?

    Are the OUTPUTs independent of different inputs?

    The drawings seem to show only two outputs (pin # 2 & 3) and the difference is that Once out#2 is started then out#3 needs to start 2ms after #2 is started and also out#2 goes off? ...


    So that indicates 2 OUTPUTS that depend on the same INPUT or trigger but just have different 'lifetimes' - where that would suggest the listed states are close to correctly defining the system.

    Your system is different than Paul's DEMO of a single output cycling at two different rates.

    Your case is two outputs that trigger on the same condition (?) and then progress on the same timeline but at different rates (?).

    Draw a line for each output, where either one needs to change, this is a new state - where it runs on a single elapsedMicros variable.

    Quick guess ( a shame the shadowed images are not easier to read )

    Starting in state #0 , with :: elapsedMicros T; // defined but not needed in state #0 or #1

    #state : Action
    #0 : Turn off out #2 and out #3 and set state #1
    #1 : if ( triggering input ) THEN:: zero time T, ON output2 and set state #2
    #2 : if T>= 2ms then off output 2 and on output 3, zero time T, and set state #3
    #3 : if T>= 2ms then off output 3 , zero time T, and set state #4
    #4 : if T>= 6ms then on output 2 , zero time T, set state #2

    That should run forever in that pattern that seems to match the second 'timing diagram'

    If at any point they need to stop (Loss of triggering input detected in states #2, #3, #4 perhaps) then that needs to be accounted for to return the system back to state #0 to set both outputs off

  8. #33
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    Hi

    i am trying to drive the direction of the current with the VNH5019
    over the OUTPUT Pins 2,3 from my teensy4.1

    sorry for the shadow on the pictures:

    So that indicates 2 OUTPUTS that depend on the same INPUT or trigger but just have different 'lifetimes' - where that would suggest the listed states are close to correctly defining the system.
    Correct.

    Your system is different than Paul's DEMO of a single output cycling at two different rates.
    I know
    Your case is two outputs that trigger on the same condition (?) and then progress on the same timeline but at different rates (?).
    YES
    Draw a line for each output, where either one needs to change, this is a new state - where it runs on a single elapsedMicros variable.

    Quick guess ( a shame the shadowed images are not easier to read )
    Question: so if i draw the Statemachine on paper: does the State itself resembles a Change?

    Starting in state #0 , with :: elapsedMicros T; // defined but not needed in state #0 or #1 //this is OFF i think

    #state : Action
    #0 : Turn off out #2 and out #3 for 1 second and set state #1 for
    #1 : if (
    triggering input
    ) THEN::
    what do you mean by then(do something >=?) or substract elapsedmillis=?
    zero time T
    This means ElapsedMillis=0?
    , ON output2 and set state #2
    does this not occur in state 2?
    #2 : if T>= 2ms then off output #2 and on output #3, zero time T, and set state #3
    #3 : if T>= 2ms then off output 3 , zero time T, and set state #4
    #4 : if T>= 6ms then on output 2 , zero time T, set state #2
    Still Confused here, i have drawn 5 A4 papers, which i dont want to post, because I dont understand how to do it.

    so when is the elapsedmillis set to Zero=? i want to know this for understanding. and when do I substract. because these two Actions really matter.

    That should run forever in that pattern that seems to match the second 'timing diagram'
    Yes.


    If at any point they need to stop (Loss of triggering input detected in states #2, #3, #4 perhaps) then that needs to be accounted for to return the system back to state #0 to set both outputs off
    I didnt understand this.
    Last edited by Bastiaan; 04-23-2021 at 09:13 AM. Reason: confusion.

  9. #34
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,910
    Anything after a 'then' means :: Write code to do indicated actions like (YES) :: ElapsedMillis T=0;

    The actions are done "at that time in code" off or on as indicated and change the state THEN and break; After that, all is ready to enter the next state ... which waits for its entry condition indicated.

    The final statement is a question not answered :: Once started does this run FOREVER, or must it monitor the 'triggering input' and STOP toggling the outputs?

    If it runs forever then that is all.

    BUT:: If at any point they need to stop (Loss of triggering input detected in states #2, #3, #4 perhaps) then that needs to be accounted for to return the system back to state #0 to set both outputs off

    That could be :: if ( no trigger to continue ) { set state #0; break; } before testing or doing anything else in that state.

  10. #35
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,080
    Quote Originally Posted by Bastiaan View Post
    Third state: Period:// [COLOR="#FF0000"]i am confused here because i don't know if the approach is right or where to set the period.
    Indeed this is very wrong.

    The main problem is you did not identify the individual segments of your waveform diagram and label each as its own state.

    Without key detail of each state clearly representing each small segment of your waveform, you started just making up states starting with "state 3: period", and then started trying to imagine ways of not following this state machine approach. That is absolutely the wrong way. The "period" of your waveform must be at least 3 states, maybe 4. First you need a state for pin 2 driven high. Then maybe a dead time state where neither pin is high. Then a state for pin 3 high. And finally a state where neither pin is high.

    The problem isn't specifically state 3. The problem isn't elapsedMillis. The problem is you did not clearly assign states on your waveform drawing. If you skip that step, everything which follows will be done incorrectly because the states were not defined to represent the individual states of your waveform!

    You need to go back to drawing a clearer picture. I recommend using a wide sheet of paper and drawing both waveforms on a single not-to-scale timeline. Then on that timeline, identify each individual segment of your waveform.

    Look again at the first picture I showed.

    Click image for larger version. 

Name:	statemachine1.jpg 
Views:	5 
Size:	37.4 KB 
ID:	24547

    You see the numbers and arrow in red. These are identifying each small segment of the desired waveform and which state will be used. This is the critical step you skipped. Before you draw the state transition diagram, you must precisely identify each piece of your waveforms and assign the states.

    Each state must be 100% crystal clear as representing a very specific individual waveform segment. Neither waveform can change during a state!

    When you do draw the state transition diagram, each arrow represents the places in your waveform where the state changes. For example, in the transition diagram I showed, state #1 has arrows to state 0 and state 2, because those are the ways it changes on the waveform diagram. You can't even begin to create the state transition diagram until you know all the ways the states do (and do not) change on your waveform diagram.

    DO NOT just make us states like "period", no matter how badly you want the period of a changing signal to happen. There is no signal segment of "period". The period of a waveform must be composed of 2 or more waveform segments. You will only obtain a waveform with a period if you properly identify the multiple states of the waveform which become the human perception of "period". As far as the state machine is concerned, there is never anything like "period". The states are merely the individual moments of the waveform. The purpose of using this state machine approach is to clearly identify the small individual segments where the waveforms are constant. Any change in either waveforms has to be the transition between state. If you skip that step and then start assigning states based on your higher-level desires for a sequence of changes, this approach will fail. Each state must represent one small segment of the waveforms. When any change happens in the waveform, it must be the transition between states.

    Start over with a fresh diagram of both waveforms on a SINGLE TIMELINE. Then identify each tiny unique segment of the waveform and label it as a state, similar to how I showed in my example.
    Last edited by PaulStoffregen; 04-23-2021 at 12:36 PM.

  11. #36
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    Hi Paul

    i took the weekend off, to get my head free.

    Thanks

    thanks a lot,

    so i wrote a simple program for one Output to start with.
    Click image for larger version. 

Name:	FSM Diagram Unipolar 27_04_2021.PNG 
Views:	2 
Size:	22.3 KB 
ID:	24611
    Click image for larger version. 

Name:	FSM Signal Graph Unipolar 27_04_2021.PNG 
Views:	3 
Size:	19.2 KB 
ID:	24609

    i am still confused how the FSM is handling the pulses because just counting up 1 2 3 makes more sense.
    i think this has to do with the FSM that it has to start at resting position then do an action.

    ok so now I have 10 pulses during the Pulse HIGH 50ms and Pulse LOW 50ms
    i have tested the code twice and it works.

    however once in the 5 or 10 pulse trains two pulses in the beginning of the pulse Train are HIGH, instead of
    LOW HIGH LOW HIGH how come ?

    how can I change the FSM to a else if Statement?

    tomorrow ill do the second channel with an extra delay.

    Code:
    #define ENCODER_OPTIMIZE_INTERRUPTS
    #include <SPI.h>
    #include "Adafruit_MAX31855.h"
    #include "HX8357_t3n.h"
    #include <FlickerFreePrint.h>// library to draw w/o flicker
    #include <math.h>
    #include <stdio.h>
    #include <elapsedMillis.h>
    #include <ButtonEvents.h>
    #include <ADC.h>
    #include <Encoder.h>
    #include <PID_v1.h>
    
    //left side of the teensy4.1
    const int INB_AntiClockwise       = 1;
    const int INA_Clockwise           = 0;
    
    const int PWM_DRV_TEC1_2_3        = 5;
    const int PWM_DRV_PUMP            = 4;
    const int PWM_EMAGNET             = 5;
    
    unsigned int OFF_Time1 = 4000;                    //OFF Time
    unsigned long repeatpulse = 10;
    unsigned long PulseLOW = 50;
    unsigned long PulseHIGH = 50;
    elapsedMillis usec;// use only one variable for elapsedMillis/Micros
    int Pulsecnt;
    int state;
    bool VNH5019 = LOW;   //it has not effect changing this from int to byte
    
    
    ////-----------------------------------------------Variables returned from analog inputs
    int CSRAWTEC1_value;
    int CSRAWTEC2_value;
    int CSRAWTEC3_value;
    int CSRAWEMAG_value;
    //Current Factor x 3.3V ==16,7A
    int Currentfactor1 = 5.06;
    int Currentfactor2 = 5.06;
    int Currentfactor3 = 5.06;
    int Currentfactor4 = 5.06;
    
    float TEC1Current;
    float TEC2Current;
    float TEC3Current;
    float EMAGCurrent;
    
    
    
    //-----------------------------------------------Default values for Sensors and PWM
    float TempValue               = 0;               //encoder value to double
    int PMPSpeed                  = 0;               //variable to be changed constrain and map
    float  PMP_Liter_Min_Display  = 0;               //display value from the PUMP ==corresponds with max L/min Datasheet VPP655
    int PMP_PWM                   = 0;               //Pump PWM
    float EMAGNET                 = 0;               //Screen Value current is max 16.7A.
    int EMAGNETPWM                = 0;               //PWM for Emagnet is 0.
    
    //values cant go negative
    unsigned long SampleTime = 0; // 1                 second
    
    
    ButtonEvents myButton;  // Instantiate a Bounce object
    ADC *IADC = new ADC(); //class ADC from the teensy read in Currents
    
    
    
    void setup()
    {
      Serial.begin(9600);
    
      //SPI CS pins for the MAX31855 need to be set high!
    
      //  pinMode(TFT_CS,     OUTPUT);            digitalWrite(TFT_CS, HIGH);
      pinMode(INB_AntiClockwise, OUTPUT);     digitalWrite(INB_AntiClockwise, LOW);
      pinMode(INA_Clockwise, OUTPUT);         digitalWrite(INA_Clockwise, LOW);
      //  pinMode(DIR_TEC_Cool, OUTPUT);
      pinMode(PWM_DRV_TEC1_2_3, OUTPUT);
      pinMode(PWM_DRV_PUMP, OUTPUT);
      pinMode(PWM_EMAGNET, OUTPUT);
    
      analogWriteResolution(12);
      analogWriteFrequency(PWM_DRV_TEC1_2_3, 20000);
      analogWriteFrequency(PWM_EMAGNET, 20000);
    
      state = 0;
      Pulsecnt = 0;
      usec = 0;
    
    }
    
    void loop()
    {
    
      switch (state)
      {
        case 0:
          if (usec >= OFF_Time1)
          {
            VNH5019 = HIGH;
            digitalWrite(INA_Clockwise, LOW); digitalWrite(INB_AntiClockwise, LOW);  //doesnt matter high or low both need to be HIGH or LOW.
            //required for Timedelay max
            usec = 0;
            Pulsecnt = 0;
            state = 1;
            Serial.println("begin state 0");
          }
          break;
    
     case 1:
          if (usec >= PulseLOW)
          {
            digitalWrite(INB_AntiClockwise, LOW); digitalWrite(INA_Clockwise, LOW);
            Pulsecnt = Pulsecnt + 1;
            //reset the elapsedMicros
            state = 2;
            Serial.println("begin state 1");
            usec = 0;
          }
          break;
    
    case 2:
          if (usec >= PulseHIGH) //Case 2 //50ms//50000usec
          {
            if (Pulsecnt < repeatpulse) //repeat pulses 50ms
            {
              digitalWrite(INA_Clockwise, HIGH);
              analogWrite(PWM_DRV_TEC1_2_3, 2500); //2700 is the limit //thermal
              Serial.println("begin state 2");
              usec = 0;
              state = 1;
            }
            else
            {
              digitalWrite(INA_Clockwise, LOW);
              state = 0;
            }
    
          }
          break;
      }
    }
    Last edited by Bastiaan; 04-27-2021 at 09:55 AM. Reason: one Channel, attachment was wrong state

  12. #37
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    hi,

    for using two signals i splitted up the FSM in two FSM which respresent their own channel.
    the first channel 0 is Clockwise as can been seen in post 36.

    the following attached signal Channel 1 represents during the OFF State of Channel 0 = Channel 1, but with two extra states States 1 and State 3: 1 = is the delay which is repeated and state 3 is the Channel 0 which is on in the other FSM.

    I have attached both drawings into one, showing the FSM of the channel 1 and signal Graph for both for understanding.
    Click image for larger version. 

Name:	State Channel 0and 1.PNG 
Views:	2 
Size:	13.4 KB 
ID:	24630
    Click image for larger version. 

Name:	diagram FSM Channel1.PNG 
Views:	2 
Size:	20.3 KB 
ID:	24631

    problem:
    i have problems counting up the case 1 2ms delay how do i count the states of case 1 for channel 1

    the following code is not complete! so do not compile.
    my question is where in the FSM do I place the count of the delays
    i think the FSM is correct for the Channel 1 but i dont understand when to count the delays. because this decides when and where the states are switched from state 3 to state 1 and to state 0.

    its marked in red where i have questions its ( further down in the code).

    Code:
    #define ENCODER_OPTIMIZE_INTERRUPTS
    #include <SPI.h>
    #include "Adafruit_MAX31855.h"
    #include "HX8357_t3n.h"
    #include <FlickerFreePrint.h>// library to draw w/o flicker
    #include <math.h>
    #include <stdio.h>
    #include <elapsedMillis.h>
    #include <ButtonEvents.h>
    #include <ADC.h>
    #include <Encoder.h>
    #include <PID_v1.h>
    
    //left side of the teensy4.1
    const int INB_AntiClockwise       = 1;
    const int INA_Clockwise           = 0;
    
    const int PWM_DRV_TEC1_2_3        = 5;
    const int PWM_DRV_PUMP            = 4;
    const int PWM_EMAGNET             = 5;
    
    unsigned int OFF_Time1 = 4000;                    //OFF Time
    unsigned long repeatpulse = 10;
    unsigned long PulseLOW = 50;
    unsigned long PulseHIGH = 50;
    elapsedMillis usec;// use only one variable for elapsedMillis/Micros
    int Pulsecnt;
    int State_CH0;//INA Clockwise
    
    
    int State_CH1;//INB Anti
    unsigned long repeatpulseAnti = 10;
    unsigned long Delaybetween = 2;
    unsigned long DelayAfter = 2;
    unsigned long PulseAnti = (PulseLOW - (Delaybetween + DelayAfter));
    int PulsecntAnti;
    bool VNH5019 = LOW;   //it has not effect changing this from int to byte
    
    //-----------------------------------------------Default values for Sensors and PWM
    float TempValue               = 0;               //encoder value to double
    int PMPSpeed                  = 0;               //variable to be changed constrain and map
    float  PMP_Liter_Min_Display  = 0;               //display value from the PUMP ==corresponds with max L/min Datasheet VPP655
    int PMP_PWM                   = 0;               //Pump PWM
    float EMAGNET                 = 0;               //Screen Value current is max 16.7A.
    int EMAGNETPWM                = 0;               //PWM for Emagnet is 0.
    
    //values cant go negative
    unsigned long SampleTime = 0; // 1                 second
    
    
    ButtonEvents myButton;  // Instantiate a Bounce object
    ADC *IADC = new ADC(); //class ADC from the teensy read in Currents
    
    
    
    void setup()
    {
      Serial.begin(9600);
    
      //SPI CS pins for the MAX31855 need to be set high!
    
      //  pinMode(TFT_CS,     OUTPUT);            digitalWrite(TFT_CS, HIGH);
      pinMode(INB_AntiClockwise, OUTPUT);     digitalWrite(INB_AntiClockwise, LOW);
      pinMode(INA_Clockwise, OUTPUT);         digitalWrite(INA_Clockwise, LOW);
      //  pinMode(DIR_TEC_Cool, OUTPUT);
      pinMode(PWM_DRV_TEC1_2_3, OUTPUT);
      pinMode(PWM_DRV_PUMP, OUTPUT);
      pinMode(PWM_EMAGNET, OUTPUT);
    
      analogWriteResolution(12);
      analogWriteFrequency(PWM_DRV_TEC1_2_3, 20000);
      analogWriteFrequency(PWM_EMAGNET, 20000);
    
      State_CH0 = 0;
      Pulsecnt = 0;
      usec = 0;
    
      State_CH1 = 0;
      PulsecntAnti =;
    
    
    
    
    }
    
    void loop()
    {
    
      switch (State_CH0)
      {
        case 0:
          if (usec >= OFF_Time1)
          {
            VNH5019 = HIGH;
            digitalWrite(INA_Clockwise, LOW); digitalWrite(INB_AntiClockwise, LOW);  //doesnt matter high or low both need to be HIGH or LOW.
            //required for Timedelay max
            usec = 0;
            Pulsecnt = 0;
            State_CH0 = 1;
            Serial.println("begin State_CH1 0");
          }
          break;
    
        case 1:
          if (usec >= PulseLOW)
          {
            digitalWrite(INB_AntiClockwise, LOW); digitalWrite(INA_Clockwise, LOW);
            Pulsecnt = Pulsecnt + 1;
            //reset the elapsedMicros
            State_CH0 = 2;
            Serial.println("begin State_CH1 1");
            usec = 0;
          }
          break;
    
        case 2:
          if (usec >= PulseHIGH) //Case 2 //50ms//50000usec
          {
            if (Pulsecnt < repeatpulse) //repeat pulses 50ms
            {
              digitalWrite(INA_Clockwise, HIGH);
              analogWrite(PWM_DRV_TEC1_2_3, 2500); //2700 is the limit //thermal
              Serial.println("begin State_CH1 2");
              usec = 0;
              State_CH0 = 1;
            }
            else
            {
              digitalWrite(INA_Clockwise, LOW);
              State_CH0 = 0;
            }
    
          }
          break;
      }
    
    
      /*
    
        int State_CH1;//INB Anti
        unsigned long repeatpulseAnti = 10;
        unsigned long Delaybetween = 2;
        unsigned long DelayAfter = 2;
        unsigned long PulseAnti = (PulseLOW - (Delaybetween + DelayAfter));
        int PulsecntAnti;
        bool VNH5019 = LOW;
    
      */
    ///------------------------------------------------------------------------------------other OUTPUT Channel 1
      switch (State_CH1) //INB_AntiClockwise
      {
        case 0:
          if (usec >= OFF_Time1)
          {
            VNH5019 = HIGH;
            digitalWrite(INA_Clockwise, LOW); digitalWrite(INB_AntiClockwise, LOW);  //doesnt matter high or low both need to be HIGH or LOW.
            //required for Timedelay max
            usec = 0;
            PulsecntAnti = 0;
            State_CH1 = 1;
            Serial.println("begin State_CH1 0");
          }
          break;
        case 1:
          if (usec >= Delaybetween)
          {
            PulsecntAnti=PulsecntAnti+1;
            digitalWrite(INB_AntiClockwise, LOW);
            usec = 0;
            State_CH1 = 2;
    ///
          }
          break;
        case 2:
          if (usec >= PulseAnti) //pulse anti is shorter then the Channel 0! 2ms + 46ms +2ms.
          {
            
           //set the Pulse HIGH
            usec = 0; //reset the delay
            State_CH1 = 1;//repeat the delay state before and after the Case 2
            digitalWrite(INB_AntiClockwise, HIGH);
          }
         if(PulsecntAnti==2)// is this correct, if PulsecntAnti becomes 2 then move tot state 3? can i do this?
        {
         State_CH2=3; //Channel 0 is now high
         usec=0;
         PulsecntAnti=0; //reset count of delays
         }
    
       }
       break;
       case 3:
          if(usec>PulseHIGH)
          {
           digitalWrite(INB_AntiClockwise, LOW);
           usec=0;
           state=1; //back to state 1 delay
           Pulsecnt =Pulsecnt+1;
          }
           if(Pulsecnt==10) //counts the pulses from the previous FSM Channel 0
           {
           usec=0;
           state=0; //back to state 0?
        
    
           }
    
    
    
    
    
    
    
    
    }
    the code where i have doubts are marked in red. am i missing something?
    Last edited by Bastiaan; 04-28-2021 at 11:52 AM.

  13. #38
    Senior Member
    Join Date
    Sep 2016
    Posts
    174
    hi

    I think i almost have the code fixed for 1000 mseconds OFF,
    then 52ms x 10 pulses on and off with a 2ms shift between two channels.

    previous post shows the graphs and the way i understood it from pauls drawings.
    programming for me was not that straightforward.

    I accidently stumbled over a state, which i thought I didnt need. and put it to Zero.
    i tried removing it but that puts my pulses for CH1 LOW. so i somehow need it, but in which constellation of programming i dont know.

    this is the snippet of code which does something miraculously for me.

    Code:
       
     case 3:
          if (usec_CH1 >=0)// be HIGH till 52ms and go low.
          {
    
            usec_CH1 = 0;
            digitalWrite(INB_AntiClockwise, HIGH);
            State_CH1 = 4;
    
    
          }
          break;

    could someone hook up 2 pins 0,1 and run the following code?
    and tell me where my fault is?
    especially for if you change the pulses HIGH and LOW state to 500ms what would happen then?
    and does the drawing i made for the FSM, match the code?
    I created for each OUTPUT a FSM so that i can see what the signal does.

    many thanks.

    this code has been tested a few times.

    Code:
    #define ENCODER_OPTIMIZE_INTERRUPTS
    #include <SPI.h>
    #include "Adafruit_MAX31855.h"
    #include "HX8357_t3n.h"
    #include <FlickerFreePrint.h>// library to draw w/o flicker
    #include <math.h>
    #include <stdio.h>
    #include <elapsedMillis.h>
    #include <ButtonEvents.h>
    #include <ADC.h>
    #include <Encoder.h>
    #include <PID_v1.h>
    
    //left side of the teensy4.1
    const int INB_AntiClockwise       = 1;
    const int INA_Clockwise           = 0;
    
    const int PWM_DRV_TEC1_2_3        = 5;
    const int PWM_DRV_PUMP            = 4;
    const int PWM_EMAGNET             = 5;
    
    unsigned int OFF_Time1 = 1000;                    //OFF Time
    
    elapsedMillis usec_CH0;// use only one variable for elapsedMillis/Micros
    elapsedMillis usec_CH1;// use only one variable for elapsedMillis/Micros
    int Pulsecnt;//pulses for CH0
    int State_CH0;//INA Clockwise
    int State_CH1;//INB Anti
    int PulsecntCH1;// pulses for CH1
    bool VNH5019 = LOW;   //it has not effect changing this from int to byte
    
    //-----------------------------------------------Default values for Sensors and PWM
    float TempValue               = 0;               //encoder value to double
    int PMPSpeed                  = 0;               //variable to be changed constrain and map
    float  PMP_Liter_Min_Display  = 0;               //display value from the PUMP ==corresponds with max L/min Datasheet VPP655
    int PMP_PWM                   = 0;               //Pump PWM
    float EMAGNET                 = 0;               //Screen Value current is max 16.7A.
    int EMAGNETPWM                = 0;               //PWM for Emagnet is 0.
    
    //values cant go negative
    unsigned long SampleTime = 0; // 1                 second
    
    
    ButtonEvents myButton;  // Instantiate a Bounce object
    ADC *IADC = new ADC(); //class ADC from the teensy read in Currents
    
    
    
    void setup()
    {
      Serial.begin(9600);
    
      //SPI CS pins for the MAX31855 need to be set high!
    
      //  pinMode(TFT_CS,     OUTPUT);            digitalWrite(TFT_CS, HIGH);
      pinMode(INB_AntiClockwise, OUTPUT);     digitalWrite(INB_AntiClockwise, LOW);
      pinMode(INA_Clockwise, OUTPUT);         digitalWrite(INA_Clockwise, LOW);
      //  pinMode(DIR_TEC_Cool, OUTPUT);
      pinMode(PWM_DRV_TEC1_2_3, OUTPUT);
      pinMode(PWM_DRV_PUMP, OUTPUT);
      pinMode(PWM_EMAGNET, OUTPUT);
    
      analogWriteResolution(12);
      analogWriteFrequency(PWM_DRV_TEC1_2_3, 20000);
      analogWriteFrequency(PWM_EMAGNET, 20000);
    
    
    //channel OUTPUT 0 FSM 1
      State_CH0       = 0;
      Pulsecnt        = 0;
      usec_CH0        = 0;
    
    //channel OUTPUT 1 FSM 2
      usec_CH1        = 0;
      State_CH1       = 0;
      PulsecntCH1     = 0;
    
    
    
    
    }
    
    void loop()
    {
    //FSM 1
      switch (State_CH0) //INB_AntiClockwise //channel 2 Oscilloscope 52ms pulse LOW and HIGH
      {
    
        case 0:
          if (usec_CH0 >= (OFF_Time1))// off time for both FSM are the same!
          {
            VNH5019 = HIGH;
            digitalWrite(INA_Clockwise, HIGH);  //doesnt matter high or low both need to be HIGH or LOW.
            //required for Timedelay max
            usec_CH0 = 0;
            Pulsecnt = 0;
            State_CH0 = 1;//move to state 1
            Serial.println("begin State_CH0 0");
          }
    
          break;
        case 1:
          if (usec_CH0 >= 50) //below for 50ms
          {
            Pulsecnt=Pulsecnt+1;//start counting on LOW Pulse
            Serial.println("begin State_CH1 State 1 LOW");
            digitalWrite(INA_Clockwise, LOW);
            usec_CH0 = 0;
            State_CH0 = 2;
          }
          break;
        case 2:
          if (usec_CH0 >= 2) //be low for 2ms
          {
    
            digitalWrite(INA_Clockwise, LOW);//add a 2ms delay
            //set the Pulse HIGH
            usec_CH0 = 0; //reset the delay
            State_CH0 = 3;//repeat the delay state before and after the Case 2
    
          }
          break;
        case 3:
          if (usec_CH0 >= 50)// be high for 50ms
          {
            usec_CH0 = 0;
            digitalWrite(INA_Clockwise, HIGH);
            State_CH0 = 4;
          }
          break;
    
        case 4:// be high + 2ms
          if (usec_CH0 >= 2)
          { if (Pulsecnt <= 10)//if number of pulses is not met go bck tot state 1
            {
              usec_CH0 = 0;
              digitalWrite(INA_Clockwise, HIGH);
              State_CH0 = 1;
            }
            else
            {
              digitalWrite(INA_Clockwise, HIGH);
              usec_CH0 = 0;
              State_CH0 = 0;
              Pulsecnt=0;
            }
          }
          break;
    
    
    
    
      }
    
    
      //FSM 2
      switch (State_CH1) //INB_AntiClockwise //channel 1 Oscilloscope
      {
    
        case 0:
          if (usec_CH1 >= (OFF_Time1))// off time for both FSM are the same!
          {
            VNH5019 = HIGH;
            digitalWrite(INB_AntiClockwise, LOW);  
            
            usec_CH1 = 0;
            PulsecntCH1 = 0;
            State_CH1 = 1;
           
    
          }
          break;
        case 1:
          if (usec_CH1 >= 50) //pulse low
    
    {
            Serial.println("begin State_CH1 State 1 LOW");
            digitalWrite(INB_AntiClockwise, LOW);
            usec_CH1 = 0;
            State_CH1 = 2;
          }
          break;
        case 2:
          if (usec_CH1 >=2) //pulse low for 52ms
          {
            PulsecntCH1 = PulsecntCH1 + 1;
            digitalWrite(INB_AntiClockwise, LOW);
            //set the Pulse HIGH
            usec_CH1 = 0; //reset the delay
            State_CH1 = 3;//repeat the delay state before and after the Case 2
          }
          break;
        case 3:
          if (usec_CH1 >=0)///somehow this works, i changed it to Zero, i am not seing the problem or logic error.
          {
            usec_CH1 = 0;
            digitalWrite(INB_AntiClockwise, HIGH);
            State_CH1 = 4;
          }
          break;
    
        case 4:
          if (usec_CH1 >= 52)//pulse high
          {
            if (PulsecntCH1 < 10)
            {
              usec_CH1 = 0;// elapsedmillis =0;
              digitalWrite(INB_AntiClockwise, LOW);
              State_CH1 = 1;//back to State 1; repeat the states.
    
            }
            else
            { usec_CH1 = 0; // elapsedmillis =0;
              State_CH1 = 0;//go back to startf
              PulsecntCH1 = 0;//reset number of pulses if pulses are reached
               digitalWrite(INB_AntiClockwise, LOW);
            }
    
          }
          break;
      }
    
    
    
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •