Go Down

Topic: Contnuous PWM Output while monitoring Input Changes (Read 662 times) previous topic - next topic

tofday

hey folks I am wondering if this code will give me a clean PWM output while I watch for CNC input value changes.
I am having the A Axis change height values (simulate axis movement) to control the signal being sent to a little blue laser controller that is looking for PWM signal.
My concern is that the incoming signal from the computer printer port will not be seen by the arduino or that the PWM will not be steady and will mess up the signal to the laser and in turn mess up the lasers output strength

Thanks for your help.

Duewy

TonyWilk

Hi,
I gather you are trying to read the A axis drive (Enable, Dir, Step) to adjust a value 0..255 to drive PWM on an output pin.

Having Serial.print()'s and delay(5000) in your loop() will make it miss steps.

Your decoding of the drive signals looks a bit suspect...
Once Enable is HIGH, I guess you want to read the Direction pin when the Step pin pulses, not before.

Something like:
Code: [Select]
loop(){
  if( Step is HIGH and Enable is HIGH ){
    read Direction
    adjust Step_Count_Val
    output PWM
    wait for Step to go Low again
  }
}


If you have control over Step pulse width, you want to set it to, say, 500uS with max. 500 steps/sec 


Yours,
  TonyWilk


tofday

#2
Jan 16, 2018, 11:19 pm Last Edit: Jan 16, 2018, 11:34 pm by tofday Reason: Modified Attached Code and Clarified Questions
Hi,
I gather you are trying to read the A axis drive (Enable, Dir, Step) to adjust a value 0..255 to drive PWM on an output pin.

Having Serial.print()'s and delay(5000) in your loop() will make it miss steps.

Your decoding of the drive signals looks a bit suspect...
Once Enable is HIGH, I guess you want to read the Direction pin when the Step pin pulses, not before.

Something like:
Code: [Select]
loop(){
  if( Step is HIGH and Enable is HIGH ){
    read Direction
    adjust Step_Count_Val
    output PWM
    wait for Step to go Low again
  }
}


If you have control over Step pulse width, you want to set it to, say, 500uS with max. 500 steps/sec  


Yours,
  TonyWilk


Hey Tony
Thanks for the suggestions....
The wait 5000 is just there so the arduino is not working when the A axis is not enabled and the Laser is not connected
Yes the main purpose is to take an increase or decrease (direction pin high or low) and read the number of pulse from the step pin.
Then take the information and send a continuous PWM signal to the laser controller from 0% to 100%

This way as the laser goes over the work in the X and Y directions the laser can increase and decrease the intensity of the burn to match the 0 to 255 gray scale of the image it is printing/burning onto the work.

My issue is that the incoming signal from the computer printer port is 5 uS (0.000005) seconds
The communication rate of the MACH 3 CNC program is 25000 baud

So can the Arduino capture the incoming signals?
Can the Arduino send out a constant PWM while it is reading the 3 inputs and calculating the PWM value?

The portion of the code for the printing of the information will be removed for the actual running code.
It will look something like the attached file.

If you or someone has a better bit of code that will make this happen then Please post it.

Thanks for your time and Help
Any information will be greatly appretiated

Duewy



TonyWilk

Assuming you have an Arduino UNO, try this:

Code: [Select]

//
// Example program to capture STEP pulses in interrupt
// - assumes STEP is active on rising edge
// - assumes DIR is stable after STEP edge
// - assumes DIR == HIGH is a +ve step
//
// accumulates a total Step_Count_Val 0..255
// outputs value to fast PWM (62KHz)
//
// TonyWilk



// This must be the PWM output pin
//
const int Laser_PWM_Pin = 9;      // Laser Board connected to PWM pin 9

const int A_Enable_Pin = 4;   // A Axis Enable connected to digital pin 4
const int A_Dri_Pin = 3;      // A Axis Dir connected to digital pin 3
#define DIR_PIN_BITMASK 0x08  // bit 3 of PORTD

// This must be an interrupt-capable pin
//
const int A_Step_Pin = 2;  // A Axis Step connected to digital pin 2

int16_t isr_step_count= 0;

// Interrupt routine called on A_Step_Pin
//
void step_ISR()
{
  if( PIND & DIR_PIN_BITMASK )
    ++isr_step_count;
  else
    --isr_step_count;
}


void setup() {
  cli();    // interrupts off while we set stuff up

  pinMode(Laser_PWM_Pin, OUTPUT);    // sets the pin as output
  pinMode(A_Enable_Pin, INPUT_PULLUP);     // sets the pin as input
  pinMode(A_Dri_Pin, INPUT_PULLUP);        // sets the pin as input
  pinMode(A_Step_Pin, INPUT_PULLUP);       // sets the pin as input

  //pinMode(TEST_PIN, OUTPUT);

  // Set timer1 for 8-bit fast PWM output
  pinMode(9, OUTPUT); // Make timer's PWM pin an output

  TCCR1B = (1 << CS10);     // Set prescaler to full 16MHz
  TCCR1A |= (1 << COM1A1);  // Pin low when TCNT1=OCR1A
  TCCR1A |= (1 << WGM10);   // Use 8-bit fast PWM mode
  TCCR1B |= (1 << WGM12);

  attachInterrupt(digitalPinToInterrupt(A_Step_Pin), step_ISR, RISING );

  sei();      // Enable interrupts to generate waveform!

  Serial.begin( 9600 );   // ********* DEBUG ONLY ***********
}

int Step_Count_Val = 0;      // store the value of cummulated Step_Count_Val  max 255 min 0

void loop() {
  // put your main code here, to run repeatedly:

  if( digitalRead( A_Enable_Pin ) == LOW )
  {
    cli();                // not enabled, zero the isr step count
    isr_step_count= 0;
    sei();

    // Turn off PWM if not enabled ???
    // OCR1AL= 0;
   
  }else{
    // enabled...
    if( isr_step_count != 0 )
    {
      // copy any stepping from isr
      cli();       
      Step_Count_Val+= isr_step_count;
      isr_step_count= 0;
      sei();

      // Pass value to PWM
      Step_Count_Val = constrain(Step_Count_Val, 0, 255);
      OCR1AL= (uint8_t)Step_Count_Val;

      Serial.println( Step_Count_Val );
    }
  }

}



Since it appears you don't have much control over MACH3's step pulse width, then the only chance with an Arduino is to capture the transition in interrupt.

Notice that the pins have had to change.

If it works at all, you should see output on the serial monitor showing the step value.
(this is only printed when steps are detected).


I've tested this on the bench, but I've no idea what your signals are like, what the polarity is etc. etc. etc.

Good luck.

Yours,
  TonyWilk

tofday

#4
Jan 17, 2018, 05:15 pm Last Edit: Jan 17, 2018, 06:17 pm by tofday Reason: Add information
Too Good
Thank you so much

I will try this today.
I take it you are using another code language,,,, "C"?

So many languages ,,, so little grey matter.
I have a heck of a time with this jumbled up mess we call English.

Humbly in your debt

Duewy


I take it that removing the serial command lines will help speed up the arduino uno during the actual operations of the CNC?
sei();      // Enable interrupts to generate waveform!

  //Serial.begin( 9600 );   // ********* DEBUG ONLY ***********
}

int Step_Count_Val = 0;      // store the value of cummulated Step_Count_Val  max 255 min 0

void loop() {
  // put your main code here, to run repeatedly:

  if( digitalRead( A_Enable_Pin ) == LOW )
  {
    cli();                // not enabled, zero the isr step count
    isr_step_count= 0;
    sei();

    // Turn off PWM if not enabled ???
    // OCR1AL= 0;
   
  }else{
    // enabled...
    if( isr_step_count != 0 )
    {
      // copy any stepping from isr
      cli();       
      Step_Count_Val+= isr_step_count;
      isr_step_count= 0;
      sei();

      // Pass value to PWM
      Step_Count_Val = constrain(Step_Count_Val, 0, 255);
      OCR1AL= (uint8_t)Step_Count_Val;

     // Serial.println( Step_Count_Val );

TonyWilk

I take it that removing the serial command lines will help speed up the arduino uno during the actual operations of the CNC?
Correct.

Not only does Serial take time, it also uses an interrupt so response of the pin interrupt will vary a bit.

If it works at all, it still might miss the odd step due to another Arduino interrupt (which we can disable if need be).

Yours,
  TonyWilk

tofday

Thanks Again Tony

I tried it out today to see if I can get the Arduino Uno to read and follow the information from the LPT port output of MACH3 CNC software.

Attached is the code I ended up with.
I also attached a note with what I did on which line.

The code follows the MACH3 output very well.
I modified some lines here and there.
One area was to get the PWM to send the signal out at all times.... If that is not needed then I will move it back down to the end.
I added a Spindle pin as it turns on when the CNC Code tells it to and turns off when the CNC code tells it to or when any emergency switch is pressed.


A few questions as I noted

1. Does the PWM output stay at the value that you send it or does it need to have the value sent over and over again????

2. If the Spindle pin goes LOW can we ensure the PWM goes to "0"? (see code notation and info on Note)

Maybe we can swap the Enable_Pin for the Spindle_Pin to act as the one that make the UNO send out a PWM of "0" when the Spindle_Pin is LOW???
But when the Spindle_Pin returns to HIGH the PWM must return to the accumulated Step_Count_Val

This will be controlling a BLUE LED Laser which does burn wood and also will burn unprotected eyes.
Having the safety switches able to turn off the PWM is a must.... so every time the code stops or the emergency stop button is pressed the Spindle goes LOW.

I may need to have a way to trigger the UNO to reset the step value to "0" but that is something that we can add on later....

Once again your assistance has been a blessing

Many thanks

Duewy

TonyWilk

Attached is the code I ended up with.
I also attached a note with what I did on which line.

The code follows the MACH3 output very well.
I modified some lines here and there.
Great... here's my notes as I go along thru the code...

* Ah, you swapped some pins around
  Ok, modified the comment to match the actual pin numbers you have set.
  Hmm, you moved A_Dri_Pin to pin 4

  I Should have mentioned this I suppose...
  Because the usual digitalRead() function takes quite a long time to execute, I 'cheated' and used direct Port I/O to handle the DIR pin.
  see:Port Manipulation

  the line #define DIR_PIN_BITMASK 0x08  // bit 3 of PORTD  was used for this
  now changed to:
Code: [Select]
#define A_DIR_PIN 4           // A Axis Dir connected to digital pin 4
#define DIR_PIN_BITMASK (0x01 << A_DIR_PIN) // A Axis Dir port pin Bit mask


  The interrupt routine handles increment and decrement of the step count by testing the port with this bit mask:
Code: [Select]

void step_ISR()
{
  if( PIND & DIR_PIN_BITMASK )   // test A_DIR_PIN
    ++isr_step_count;            // HIGH= increment count
  else
    --isr_step_count;            // LOW= decrement count 
}



* Into the main loop()...

   Override PWM if spindle stopped... Ok, I'll put this at the top of loop()

   The PWM value written to OCR1AL does continue to be output until told otherwise
   it is done by hardware counters in the chip, once it's running it just runs.

   Ah... the Direction thing.
   because the pin was changed, the interrupt routine was looking at the wrong pin
   so you had to add something in here. 
   I think that can be taken out now.

* tidy up...

  Now that we want to completely disable PWM if the Spindle == LOW, I've added a couple of functions:
  PWM_Output_On() and PWM_Output_Off() - which do what they say.

  Note that PWM_Output_On() takes care of itself, it only resets and turns on the PWM if it is currently off.

  PWM_Output_Off() turns off PWM and sets the output pin LOW

  Added a couple of Serial.print()'s for testing... you can remove 'em later.

* Ah, just spotted:
Quote
But when the Spindle_Pin returns to HIGH the PWM must return to the accumulated Step_Count_Val
...ok, PWM_Output_On() now restores the value


Right... tested that a bit and I'm gonna call it golden :)


Interesting little problem :)

Yours,
  TonyWilk









tofday

Tony my learning curve is just about vertical.
I really appreciate your patient help on this.

As you seen my skills on programming is limited to as needed only.
Seeing the intricate ways to speed up the transfer of data is humbling. I am not even pretending I understand the inter workings you are tapping into.

Once this is complete I will create a little video showing what this allows me to do with the CNC machine and the little blue laser unit.

I will install this code and put it through its paces to ensure I cover every and all issues that may or could arise.
I hate wrapping something up only to find out that I was not thorough enough and I have to redo....

Once again I appreciate your help.

TonyWilk

Once this is complete I will create a little video showing what this allows me to do with the CNC machine and the little blue laser unit.
Excellent... I'd like to see that.

I have a 40W Synrad CO2 laser sitting on the shelf waiting it's turn in my project list, I did make a PWM controller for it but not quite got around to building an XY table for it yet.

Yours,
  TonyWilk

tofday

Well we are close.....
The results are not what we are looking for.
First issue is the major one which is the response of the laser, weak at best. The output of the laser is nothing close to what it is suppose to be. The following of the computer step output is relatively good.... kinda but one thing at a time.

I am wondering if we are too fast.... is the pulsing modulation too close together for the laser controller to read?

http://buildlog.net/cnc_laser/mach_laser_power.html

This web page shows the output frequency of the MACH3 program and the frequencies being used.

I would try to adjust the frequency of the UNO program but it is beyond my coding. The standard PWM is no where near 25000Hz as stated in the AnologWrite page

ArduinoLLC.ArduinoIDE_1.8.10.0_x86__mdqgnx93n4wtt/reference/www.arduino.cc/en/Reference/AnalogWrite.html


I find it funny how the UNO powers up just from the i/o pins connected to the DB25 breakout board.

One question here.... would I be able to connect the PWM from the LPT#1 to the laser controller as well as the PWM from the arduino UNO so I can utilize either as a controller for the laser(not at the same time or on the same program) so I can call up different programs and utilize the various attributes of each, one for a grey-scale burner and one for an on/off burner. Big difference in the CNC code and speed of operation.

TonyWilk

First issue is the major one which is the response of the laser, weak at best. The output of the laser is nothing close to what it is suppose to be. The following of the computer step output is relatively good.... kinda but one thing at a time.

I am wondering if we are too fast.... is the pulsing modulation too close together for the laser controller to read?
When the count gets up to 255, the PWM output is fully ON (it is at +5v 100% of the time) - so if this does not drive your laser at full power, you have some other problem which is nothing to do with the PWM. i.e. at full power the frequency does not matter any more because it's not pulsing.

When you at, say, 50% (a count value of 128) then the PWM is 50% on, 50% off at a frequency of 62kHz
It could be set to 32kHz.


Quote
http://buildlog.net/cnc_laser/mach_laser_power.html

This web page shows the output frequency of the MACH3 program and the frequencies being used.
Er, sorry - what is this ?  Is that your laser ?

I think I need to know what laser and controller you are using.


Quote
I find it funny how the UNO powers up just from the i/o pins connected to the DB25 breakout board.
Try to not do that - backfeeding thru the protection diodes on the i/o pins is not good for the chip. Keep it powered while plugged in.

Quote
One question here.... would I be able to connect the PWM from the LPT#1 to the laser controller as well as the PWM from the arduino UNO so I can utilize either as a controller for the laser(not at the same time or on the same program) so I can call up different programs and utilize the various attributes of each, one for a grey-scale burner and one for an on/off burner. Big difference in the CNC code and speed of operation.
If I understand this right, you would be better off just removing the Arduino completely to run the laser from the LPT#1 PWM output.


To summarise:


1. When the program counts to 255, the output is full on so your laser should be full on.
2. Need to know what your laser and controller is.

Yours,
  TonyWilk
 

tofday

Just wondering why I am getting the spikes??

I will check everything over again and get back to you.

Thanks

D

TonyWilk

#13
Jan 25, 2018, 01:12 am Last Edit: Jan 25, 2018, 01:28 am by TonyWilk
Just wondering why I am getting the spikes??
Completely normal...

With a signal which changes very quickly there is always some 'over-shoot'.

Some of this is 'real', a logic level changing from 0V to 5V in mere nanoseconds causes a 'spike'

Some of it is due to the instrument used to measure the signal.
(especially the calibration of the 'scope probes)

If we just look at the 'real' signal; you have some driver (a logic output for example) which changes very quickly.
The rest of the circuit attached to that output has some capacitance.
If you have a capacitor charged to, say, 5V and then pull up the bottom leg to 5V...

...before the capacitor discharges you have 5V + a charged 5V capacitor = 10V ! ! !

This is, practically, where some 'black magic' and 'experience' comes in:

Is that 'overshoot' voltage 'real' ?
Is it going to damage my components ?

Even if you had a 500MHz 'scope instead of a 20MHz one, this is still a question.

For the 'look' of that signal - I wouldn't worry.

Unless you 'zoom in' with the timebase and see some solid 'above voltage for measurable time' rather than just a spike... you are probably Ok.

I reckon that in realising 'digital' signals can be anything other than 0V or 5V - you are on the way to being a good engineer.

Yours,
  TonyWilk





Go Up