I'm trying to create a project that responds to a transition at the analog comparator. This is a trivial sample of the problem.
// Declare a volatile boolean variable to indicate when the interrupt has occurred
volatile boolean comparatorTriggered = false;
// Interrupt Service Routine (ISR) for the Analog Comparator
ISR(ANALOG_COMP_vect) {
comparatorTriggered = true; // Set the flag when the interrupt fires
}
void setup() {
Serial.begin(115200); // Initialize serial communication
// Disable digital input buffer on comparator pins (optional, but good practice for noise reduction)
// AIN0 (PD6) is the positive input, AIN1 (PD7) is the negative input
DIDR1 |= (1 << AIN1D) | (1 << AIN0D);
// Configure Analog Comparator Control and Status Register (ACSR)
// ACSR = 0b00000000; // Reset ACSR for clarity
// Enable Analog Comparator Interrupt (ACIE)
ACSR |= (1 << ACIE);
// Select interrupt mode (e.g., rising edge, falling edge, or toggle)
// ACIS1 and ACIS0 bits control this:
// 00 = Interrupt on Toggle (any change)
// 01 = Interrupt on Falling Edge
// 10 = Interrupt on Rising Edge
// 11 = Reserved
// For this example, we'll use rising edge (10)
ACSR |= (1 << ACIS1); // Set ACIS1
ACSR &= ~(1 << ACIS0); // Clear ACIS0
// Set the negative input of the comparator to the internal 1.1V reference
// ACME (Analog Comparator Multiplexer Enable) in ADCSRB must be set for this
ADCSRB |= (1 << ACME);
// ADMUX register selects the ADC channel to be connected to the negative input of the comparator
// For internal 1.1V reference, we set MUX bits to 1110 (0x0E)
ADMUX = 0x0E;
// Ensure Global Interrupts are enabled
sei();
Serial.println("Analog Comparator Interrupt Example");
Serial.println("AIN0 (PD6) is positive input, compared against internal 1.1V reference.");
Serial.println("Interrupt will trigger on rising edge when AIN0 > 1.1V.");
}
void loop() {
if (comparatorTriggered) {
Serial.println("Comparator Interrupt Triggered!");
comparatorTriggered = false; // Reset the flag
// You can add more actions here, like turning on an LED
}
// Your main program logic can run here without constantly polling the comparator
delay(100); // Small delay to avoid excessive serial output
}
The problem is that each line that tries to set the registers causes and error and the ISR declaration causes another error.
The posted code was written for an AVR processor, likely an ATmega, and won't compile or work with any other type of processor. It will certainly not work on the R4 WiFi.
Could you please explain what you are trying to accomplish?
In most cases you do not need any registers and ports...
Unless you really need some fast actions on a slow board (like UNO R3)...
Using digitalWrite() will make your code much easier and more portable...
I got the ISR and bit twiddling from snippets on the web purporting to be for the R4 WiFi.
I am monitoring the current draw on a bilge pump using an ACS712 and I want to trigger an interrupt when the pump turns on and then off by comparing the voltage from the ACS712 and a reference that I will create using a voltage divider.
Any assistance and/or suggestions would be greatly appreciated.
What does the interrupt do?
Why not use polling?
How fo you turn off the pump?
With a relay, a mosfet? A SSR maybe?
What type of pump is it? (Ac/dc, 3phase?,voltage, wattage).
Do you want to implement a run dry protection?
The pump is independently powered and has its own auto switch based on the water level. I'm just measuring the current draw to tell when it turns on and off.
I’d start with a much simplier design. Just use AnalogRead() to read the current and your reference voltage. If it is higher, the pump is on, if it is lower, the pump is off. Do this repeatedly inside loop().
Is there a reason something this simple would not work?
They might have been for the R3 WiFi. Certainly not for the R4 WiFi, which has a completely different processor. Unfortunately, Arduino decided to sow great confusion by naming their new board in such a way as to imply that it had some relation to the Uno R3.
As others have said, there is no obvious need for register access or interrupts to do what you want to do.
It looks to me as though it is probably AI generated, certainly not tested.
With a few changes I managed to get it to work.
// Declare a volatile boolean variable to indicate when the interrupt has occurred
volatile boolean comparatorTriggered = false;
byte monitorPin = 12;
// Interrupt Service Routine (ISR) for the Analog Comparator
ISR(ANALOG_COMP_vect) {
comparatorTriggered = true; // Set the flag when the interrupt fires
}
void setup() {
Serial.begin(9600); // Initialize serial communication
pinMode(monitorPin, OUTPUT);
Serial.println("\n");
// Disable digital input buffer on comparator pins (optional, but good practice for noise reduction)
// AIN0 (PD6) is the positive input, AIN1 (PD0) is the negative input
DIDR1 |= (1 << AIN1D) | (1 << AIN0D);
Serial.print("DIDR1 = ");
Serial.print(DIDR1);
Serial.print("\t");
Serial.println(DIDR1, BIN);
// Configure Analog Comparator Control and Status Register (ACSR)
// ACSR = 0b00000000; // Reset ACSR for clarity
// Enable Analog Comparator Bandgap Select (ACBG) - Added by JohnLincoln
ACSR |= (1 << ACBG);
// Enable Analog Comparator Interrupt (ACIE)
ACSR |= (1 << ACIE);
// Select interrupt mode (e.g., rising edge, falling edge, or toggle)
// ACIS1 and ACIS0 bits control this:
// 00 = Interrupt on Toggle (any change)
// 01 = Interrupt on Falling Edge
// 10 = Interrupt on Rising Edge
// 11 = Reserved
// For this example, we'll use rising edge (10)
ACSR |= (1 << ACIS1); // Set ACIS1
ACSR |= (1 << ACIS0); // Set ACIS0 // JohnLincoln
// ACSR &= ~(1 << ACIS0); // Clear ACIS0
Serial.print("ACSR = ");
Serial.print(ACSR);
Serial.print("\t");
Serial.println(ACSR, BIN);
ADCSRA = 0b00000111; // Added JohnLincoln
Serial.print("ADCSRA = ");
Serial.print(ADCSRA);
Serial.print("\t");
Serial.println(ADCSRA, BIN);
// Set the negative input of the comparator to the internal 1.1V reference
// ACME (Analog Comparator Multiplexer Enable) in ADCSRB must be set for this
ADCSRB |= (1 << ACME);
Serial.print("ADCSRB = ");
Serial.print(ADCSRB);
Serial.print("\t");
Serial.println(ADCSRB, BIN);
// ADMUX register selects the ADC channel to be connected to the negative input of the comparator
// For internal 1.1V reference, we set MUX bits to 1110 (0x0E) - This is wrong, JohnLincoln
// For internal 1.1V reference, set REFS1 and REFS0 - added JohnLincoln
// using
ADMUX = 0b11000000;
Serial.print("ADMUX = ");
Serial.print(ADMUX);
Serial.print("\t");
Serial.println(ADMUX, BIN);
Serial.println("");
// Ensure Global Interrupts are enabled
sei();
Serial.println("Analog Comparator Interrupt Example");
Serial.println("AIN0 (PD0) is positive input, compared against internal 1.1V reference.");
Serial.println("Interrupt will trigger on rising edge when AIN0 > 1.1V.");
}
void loop() {
if (comparatorTriggered) {
Serial.println("Comparator Interrupt Triggered!");
comparatorTriggered = false; // Reset the flag
// You can add more actions here, like turning on an LED
digitalWrite(monitorPin, HIGH);
delay(2000);
digitalWrite(monitorPin, LOW);
}
// Your main program logic can run here without constantly polling the comparator
//delay(100); // Small delay to avoid excessive serial output - makes responding to interrupt sluggish - JohnLincoln
}
Here are the results shown on an oscilloscope:
Channel 1 - yellow trace - Ramp voltage from Function Generator, connected to A0.
Channel 2 - red trace - Pin 12 output, goes high when interrupt detected.
Channel 3 - blue trace - Serial output, changed to 9600Bd to make it visible.
Full code would look like this.
A flag is added to only print once when pump state changes.
the abs in the code is there so that polarity of the ADS712 doesn't matter.
Threshold value depends on pump current.
Leo..
int threshold = 200; // 0-512
bool flag;
void setup() {
Serial.begin(115200);
}
void loop() {
if (abs(analogRead(A0) - 512) > threshold) {
if (flag == false) {
Serial.println("pump ON");
flag = true;
} else {
Serial.println("pump OFF");
flag = false;
}
}
}