ISR and altering PWM output

I am trying to get an interrupt that happens once every 5sec to alter the output of a PWM port. In the main loop the PWM is set to some value that is read from a POT. What I want is that if I set the PWM output to 50% continuously, but every 5 seconds the PWM goes to 100% output for 300ms then goes back to the POT value 50%. It keeps doing it as long as it is powered. The current code does not work as I want. Seems the ISR can't do heavy lifting like set a pin or alter the PWM 50% to 100%. So I tried whatever popped into my mind. Switch cases, if then....passing flags. I just can't get what I described above to work. I would appreciate any help.

I have an add on for later, it will have a SDcard logging feature but will worry about that later.
Thanks! Nick

#include <TimerOne.h>

// The code below allows the user to set the Preload current, Surge current and cycle time. This controls a dynamic motor brake platform to simulate motor momentary stall conditions  
// In normal operation the arduino generates a PWM steady state output, the ISR comes through periodically and generates a new current draw for a window of time then returning back to the preload current PWM setting.
// 

const int Drive = 6;
int SurgeFlag = 0;
int voltage;


void setup(void)
{
  pinMode(Drive, OUTPUT);
  Timer1.initialize(3000000);
  Timer1.attachInterrupt(Surge); 
  Serial.begin(9600);
}


// The interrupt will send a surge current 255 value to PWM. The surge frequency is controlled by the interrupt Timer1.initialize()

void Surge(void)
{
 SurgeFlag = SurgeFlag + 1;
 
}


// The main program will read ADC value and set PWM for preload current

void loop(void)
{
 
  noInterrupts();
  voltage = analogRead(A0);   // ADC reads 0 - 1023
  voltage = voltage/4;        // scale ADC 0 - 255 to set min/max PWM range
  analogWrite(Drive, voltage);
  interrupts();

  if (SurgeFlag == 1) {
  digitalWrite(6, HIGH);
  
  SurgeFlag = 0;
  delay(2000);
  
}

  

  
}

Variables shared with interrupt routines must be declared volatile. Furthermore, multibyte shared variables must be protected from corruption, when accessed by the main program, as follows:

noInterrupts();
int surge_copy = SurgeFlag;
interrupts();
...
if (surge_copy == 1) {

Use an 8 bit variable to avoid the above, if possible.

There is no need to disable interrupts for the analog read/write.

You can do this without using interrupts. Use milles to do your timing not delay(); Check blink without delay example.

Hi, I am interested in using the millis. I am trying my logic to work as following:

running all the time PWM A0- 10k pot set to 30%, every 2000ms I set the PWM to 100% for 300ms, then back to 30% in a loop. I have tried a lot of things and now my code is gibberish, scrapping it to start all over.

I like that Millis lets you drop through to the main C loop and not locked into a routine until finished. It will make saving the data to SD easy. I just can't wrap my head around how to use Millis for the timing described above. I would appreciate help with it.

Hi,

try this code

PS:
Hi,
Oops Sorry @macgman2000 it was a typo.
please correct:

unsigned long myTime1 = 0;
unsigned long myTime2 = 0;

// The code below allows the user to set the Preload current, Surge current and cycle time. This controls a dynamic motor brake platform to simulate motor momentary stall conditions
// In normal operation the arduino generates a PWM steady state output, the ISR comes through periodically and generates a new current draw for a window of time then returning back to the preload current PWM setting.
//
const int Drive = 6;
int voltage;
unsigned long myTime1 = 0;
unsigned long myTime2 = 0;
//------------------------------------------------------------------
void setup(void)
{
  pinMode(Drive, OUTPUT);
  Serial.begin(9600);
  myTime2 = millis();
}
//------------------------------------------------------------------
// The main program will read ADC value and set PWM for preload current
void loop(void)
{
  voltage = analogRead(A0);   // ADC reads 0 - 1023
  voltage = voltage / 4;      // scale ADC 0 - 255 to set min/max PWM range
  analogWrite(Drive, voltage);

  if (millis() - myTime2 >= 5000)       // If past 5 seg
  {
    myTime1 = millis();                 // Init mytime1
    while (millis() - myTime1 < 300)    // While myTime1 < 300 ms
    {
      analogWrite(Drive, 255);          // PWM max
    }
    myTime2 = millis();                 // Init mytime2
  }
}

Ah I see where I had tunnel vision. I was trying to force discrete if then. While would have done it. Thanks

Very weird problem came up. This only works for 4 or 5 passes through the inner 300ms loop then stops. The only thing responsive is A0 connected to a pot, I can vary it and it changes PWM output. Otherwise the 300ms stops executing the while loop.

Perhaps it is an overflow problem?
Are you using int? Best to use unsigned long

unsigned long myTime1 = 0; // etc

yes you are correct. It's been running longer than previously. I will watch it for a few hours to make sure it does not stop running. Thanks!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.