2

I have a very simple circuit, but my program is some what complicated.

Here is the circuit diagram:

enter image description here

Here is the code:

/*
  01 - GND -------- GND
  02 - +5V -------- 5V
  03 - V0  -------- Potentiometer Middle
  04 - Reset ------ 9
  05 - Read/Write - GND
  06 - Enable ----- 8
  07 - Data0 ------ NC
  08 - Data1 ------ NC
  09 - Data2 ------ NC
  10 - Data3 ------ NC
  11 - Data4 ------ 10
  12 - Data5 ------ 11
  13 - Data6 ------ 12
  14 - Data7 ------ 13
  15 - +LCD ------- 5V
  16 - -LCD ------- GND
*/

//include LCD library
#include <LiquidCrystal.h>

//Initialize an LCD object
/*Pins should be mentioned in this order:
  Reset
  Enable
  Data4
  Data5
  Data6
  Data7
*/
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
int onTimePin = A0;
int onTime = 0;
int offTimePin = A1;
int offTime = 0;
int ledPin = 13;

void setup()
{

  pinMode(onTimePin, INPUT);
  pinMode(offTimePin, INPUT);

  pinMode(ledPin, OUTPUT);

  //Begin the LCD interface
  lcd.begin(16, 2);

  lcd.print("ON  TIME : ");
  lcd.setCursor(0, 2);
  lcd.print("OFF TIME : ");

}

void loop()
{
  onTime = map(analogRead(onTimePin), 0, 1023, 1, 3);
  lcd.setCursor(11, 0);
  lcd.print(onTime);

  offTime = map(analogRead(offTimePin), 0, 1023, 1, 9);
  lcd.setCursor(11, 1);
  lcd.print(offTime);

  digitalWrite(ledPin, HIGH);
  delay(onTime * 1000);

  digitalWrite(ledPin, LOW);
  delay(offTime * 1000);
}

The above code works. But there is a small problem:

When I turn the potentiometer wiper, there is a delay.

It's obvious because when the loop completes, the changed value of potentiometer is displayed. So, I decided to do the same thing using interrupts. But only digital pins have interrupts.

I would like to know the solution for using interrupts on analog input.

Gerben
  • 11,332
  • 3
  • 22
  • 34
Vishal
  • 131
  • 5

2 Answers2

3

Avoid delay.

Very simplistic alternative:

unsigned long lastLedToggleTime;
unsigned long currentLedToggleInterval;

void loop() {
  ...

  unsigned long now = millis();

  if ( (now - lastLedToggleTime) > currentLedToggleInterval) {
    lastLedToggleTime = now;
    // We need to toggle the LED now.
    if ( digitalRead( ledPin ) == LOW ) {
      // LED was LOW, so we set it HIGH and setup next toggling after onTime.
      digitalWrite(ledPin, HIGH);
      currentLedToggleInterval = (onTime * 1000);
    } else {
      // LED was HIGH, so we set it LOW and setup next toggling after offTime.
      digitalWrite(ledPin, LOW);
      currentLedToggleInterval = (offTime * 1000);
    }
  } 
  ...
}

Notice that we're dealing with 32 bit unsigned integer values here, which is why this code will work even if/when millis() rolls over to 0. Specifically, not only will now - lastLedToggleTime always return a positive value (because it is cast into the unsigned data type), it will also return the correct value due to two's complement representation and modulo arithmetic base 2^32.

Example: Let's just look at an 8 bit value for simplicity:

Say, lastLedToggleTime was at the last tick of the 8 bit timer value, i.e. lastLedToggleTime == 255. In the next timer tick, now will overflow to 0, so next we have now - lastLedToggleTime = 0 - 255 = -255. In two's complement, this value would need (at least) 9 bits to represent (binary: 1 0000 0001), but because we only have 8 bits of storage, the sign bit (MSB) is just discarded resulting in 0000 0001 binary = 1. We can see that 1 is the correct value for the number of ticks to get from 255 to 0; it's exactly one tick.

JimmyB
  • 155
  • 6
3

You are looking for the bad solution for a simple problem. As Ignacio Vazquez-Abrams puts it, the problem is you using delay(). The simplest solution is to manage the timings with millis(). See the Blink Without Delay Arduino tutorial.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81