I have 3 solenoids that I would like to control using an arduino.
Mode 1:
when Input is HIGH (from a synthesizer) -
solenoid will pulsating at 30ms ON time in a speed determine by the potentiometer (slow(every 5 sec lets say, to fast (every 100ms)
Mode 2:
When input is HIGH (from a synthesizer) - solenoid will do one pulse of 30ms ON time
potentiometer will decide the threshold for making the pulse (acting as comparator threshold)
I guess you set pin 8 as a INPUT and you'll read either LOW or HIGH depending on the position of your button.
By default pins are INPUT but if you were not careful and set the pin to be an OUTPUT LOW and the switch were to be on VCC, you would create a short that would destroy the pin and / or the arduino.
Typically you can connect just Pin 8 --- (2) button (3) --- GND and leave sw1 not connected and set the pin 8 as INPUT_PULLUP. This way there is no risk whatsoever to create a short.
#define NUM_POTS 1 // Number of pots
int heartbeatLED = 13;
const byte POT_pins[] = {A0, A1, A2, A3}; // pot analog input pins
const byte inputPIN[] = {A4, A5, A6, A7}; // input pin from synthesizer
const byte modeSwitchPin[] = {6, 7, 8, 9}; // Digital input pin for mode switch
const byte solenoidPin[] = {2, 3, 4, 5}; // Digital output pin for solenoid
const byte filterPOT = 5; // pot filter
int lastValuePOT[NUM_POTS];
unsigned long lastPulseTime = 0;
unsigned long pulseDuration = 0;
// timing variables
unsigned long previousMillis = 0;
unsigned long heartbeatMillis;
void setup() {
pinMode(heartbeatLED, OUTPUT);
for (byte i = 0; i < NUM_POTS; i++) {
pinMode(POT_pins[i], INPUT);
pinMode(inputPIN[i], INPUT);
pinMode(modeSwitchPin[i], INPUT_PULLUP);
pinMode(solenoidPin[i], OUTPUT);
}
Serial.begin(115200); // Serial initialization outside the loop
}
void loop() {
// Your main loop code here
// Example: Call mode1
mode1();
// Read and filter pot values
for (byte i = 0; i < NUM_POTS; i++) {
// Read the stabilized analog value
int potValue = analogRead(POT_pins[i]);
// Has analog value changed more than the filter amount?
if (abs(lastValuePOT[i] - potValue) > filterPOT) {
if (lastValuePOT[i] != potValue) {
// Update to the new value
lastValuePOT[i] = potValue;
Serial.print("POT");
Serial.print(i + 1);
Serial.print(" ");
Serial.println(potValue);
// Map potValue to the pulsating rate
int pulsatingRate = map(potValue, 0, 1023, 2000, 100); // 2000ms (2 seconds) to 100ms
// Call function to pulsate solenoid with a fixed ON time of 30ms
pulsateSolenoid(30, pulsatingRate);
}
}
}
// Call heartbeat function
checkHeartbeatTIMER();
// Add more modes or functionalities as needed
}
void mode1() {
// Check if inputPIN is HIGH
if (digitalRead(inputPIN[0]) == HIGH) { // Assuming you are checking inputPIN[0] for Mode 1
// Read potentiometer value to determine pulsating rate
int POTValue = 1023 - analogRead(POT_pins[0]); // Assuming you are using POT_pins[0] for Mode 1
// Has analog value changed more than the filter amount?
if (abs(lastValuePOT[0] - POTValue) > filterPOT) {
if (lastValuePOT[0] != POTValue) {
// Update to the new value
lastValuePOT[0] = POTValue;
Serial.print("POT");
Serial.print(1);
Serial.print(" ");
POTValue = map(POTValue, 0, 1023, 255, 0);
Serial.println(POTValue);
// Map the potValue to the pulsating rate
int pulsatingRate = map(POTValue, 0, 1023, 2000, 100); // 2000ms (2 seconds) to 100ms
// Call function to pulsate solenoid with a fixed ON time of 30ms
pulsateSolenoid(30, pulsatingRate);
}
}
}
}
void pulsateSolenoid(int onTime, int rate) {
unsigned long currentTime = millis();
if (currentTime - lastPulseTime >= rate) {
digitalWrite(solenoidPin[0], HIGH); // Assuming you are controlling solenoidPin[0] for Mode 1
Serial.println("Solenoid ON");
delay(onTime);
digitalWrite(solenoidPin[0], LOW);
Serial.println("Solenoid OFF");
lastPulseTime = currentTime;
}
}
void checkHeartbeatTIMER() {
//is it time to toggle the heartbeatLED?
if (millis() - heartbeatMillis >= 500ul) {
//restart this TIMER
heartbeatMillis = millis();
//toggle the heartbeatLED
digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
}
} //END of checkHeartbeatTIMER()
I'm looking through the tiniest of windows, it looks plausible but I see no use of any modes or mode switching.
So it is doing something. Please say what the code does now, and describe how it is doing something it should not, or isn't doing something it should. As of this version.
Then explain again, assuming this version does what it looks like it does and that is correct for this version, how you want to modify the code - what will it do when you are finished?
while input is HIGH pulse the solenoid at a speed determine by the pot with on time of 30ms
so if pot is set to speed of 1000ms the solenoid will be ON for 30ms and then OFF for 970ms. if the pot is set to 200ms the solenoid should be ON for 30ms and then OFF for 170ms. etc etc
--
it seems that when the input is HIGH the pot reading become unstable and no pulsing is accuring
so I have the following code which is working great in one of the modes:
when in mode2 that it should only pulse once when gate is HIGH the solenoid is stuck in his ON position without realising after 30ms. why?
#define SOLENOID_PIN 4 // Digital output pin for solenoid
int inputPIN = A4; // Analog input pin for the input
int potPIN = A0; // Analog input pin for the potentiometer
int switchPIN = 8; // Digital input pin for the switch
unsigned long lastPulseTime = 0;
unsigned long pulseInterval = 200; // Default time between pulses
const int onTime = 30; // Constant ON time for the solenoid
bool switchStateChanged = true;
void setup() {
pinMode(SOLENOID_PIN, OUTPUT);
pinMode(inputPIN, INPUT);
pinMode(potPIN, INPUT);
pinMode(switchPIN, INPUT_PULLUP); // Internal pull-up resistor for the switch
Serial.begin(115200);
}
void loop() {
// Read the input
int inputValue = digitalRead(inputPIN);
int switchState = digitalRead(switchPIN);
// Check if switch state has changed
if (switchState != digitalRead(switchPIN)) {
switchStateChanged = true;
}
if (inputValue == HIGH && switchState == HIGH) {
pulsateSolenoidOnce();
}
// Check if input is HIGH and switch is pressed
if (inputValue == HIGH && switchState == LOW) {
// Read potentiometer value to determine time between pulses
int potValue = analogRead(potPIN);
// Map potValue to the pulse interval
pulseInterval = map(potValue, 0, 1023, 50, 2000); // Adjust the range as needed
// Call function to pulsate solenoid
pulsateSolenoid();
} else if (switchStateChanged) {
Serial.println("Mode 2"); // Switch in the other position
switchStateChanged = false; // Reset the flag
// Call function to pulsate solenoid once in the other switch position
pulsateSolenoidOnce();
}
}
void pulsateSolenoid() {
unsigned long currentTime = millis();
if (currentTime - lastPulseTime >= pulseInterval) {
digitalWrite(SOLENOID_PIN, HIGH);
Serial.println("Solenoid ON");
delay(onTime); // Constant ON time
digitalWrite(SOLENOID_PIN, LOW);
Serial.println("Solenoid OFF");
lastPulseTime = currentTime;
}
}
void pulsateSolenoidOnce() {
digitalWrite(SOLENOID_PIN, HIGH);
Serial.println("Solenoid ON");
delay(onTime); // Constant ON time
digitalWrite(SOLENOID_PIN, LOW);
Serial.println("Solenoid OFF");
}
Remember, you need to do the equivalent of debouncing the switch because it takes time to transition from one contact to the other and when your program reads the switch during that time, pin 2 is floating.
I was digging in and got along before I saw the above snippet.
There are only four references to the variable switchState.
You read the switchPIN into it, then immediately compare by reading the switch again.
Usually, the previous switch state is saved to compare with a new reading. This would requite the the switchState endure, so it must be a global variable or a local variable qualified as static.
I would be re-writing the sketch at this point. So I recommend that you think it out a bit.
You need to do debouncing and state change detection to develop the information that a switch has become high or low (not is high or low), and maintain a state variable that can tell you if the switch is stable and high or low.
You may benefit from using the IPO model.
Input - read all the switches and pots and whatever.
Process - decide based on the inputs and any mode selected and current progress in executing that mode (including timers) what the output should become (or remain)
Output - actually write to the outputs
Input and Output are the only code sections that use digitalWrite(), digitalRead() and analogRead().
Input also sees if any timers in progress are done.
Process deals strictly with the logic - what should the output be, is it necessary to restart any timers.
I like my state change detection as much as everyone likes her own, so try this in the simulation that is linked on the post on the thread where I threw in my version: