I am looking to control the timing of a 3/2 solenoid valve with either a knob or keypad. I was wondering if it was useful to use the Arduino or another microcontroller, or get any other suggestions on how to create a control for the solenoid.
I am basically needing to control the frequency in which the solenoid valve opens and closes and also the time in which the valve stays open compared to the time it is closed.
You can add a knob with potentionmeter to an analog input of the Arduino.
But perhaps a lcd display with buttons is easier.
How to control the valve depends on the solenoid valve, for a 12V solenoid valve a "logic level" power mosfet could be used. For a mains voltage solenoid valve, a SSR (Solid State Relay) or relay can be used.
The Arduino is for fast prototyping. There are other possibilities, like a complete PLC module (with Arduino inside).
You need some programming skills to make it all work together. But there are many examples, and you can ask on this forum.
I would like to be able to control the frequency and the duty cycle separately by two potentiometers. I have found code to do this, shown below, but it is at a much higher frequency than what I need. My requirements are a freqency from just above 0 Hz to 3.5 Hz. And a duty cycle from about 20% to 80%.
The code I found is shown here, but it's lowest frequency is about 7 kHz,
// portions extracted from Timer1
// http://www.arduino.cc/playground/Code/Timer1
/* The wiper of a potentiometer should be hooked up to A0
and controls the frequency of the function generator. The
other connections of the potentiometer should be hooked up
to +5 and GND.
Possible frequencies are between about 7 khz and 300 khz.
Another potentiometer hooked up to A1 controls the duty
cycle, from very low to very high.
*/
int user_cycles;
int user_duty;
void set(int cycles, float duty) {
char oldSREG;
int dutyCycle = cycles * duty;
if (dutyCycle < 6) {
dutyCycle = 6; // Prevent duty cycle from being too short
}
if (dutyCycle > 1015) {
dutyCycle = 1015; // Prevent duty cycle from being 100%
}
if (cycles < 5) {
cycles = 5;/// Prevent frequency from being too high
}
oldSREG = SREG; // Save the registers
cli(); // Disable interrupts for 16 bit register access
ICR1 = cycles; // ICR1 is TOP in p & f correct pwm mode
OCR1A = dutyCycle; // OCR1A is BOTTOM
SREG = oldSREG; // Restore the registers
}
void setup()
{
pinMode(9, OUTPUT);
TCCR1A = 0; // clear control register A
TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // Clear all prescaler bits
TCCR1B |= _BV(CS10); // choose prescaler 1, no prescaling, and start the clock
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(13, OUTPUT);
}
void loop()
{
int temp_cycles = analogRead(A0);
int temp_duty = analogRead(A1);
if (temp_cycles != user_cycles || temp_duty != user_duty) {
user_cycles = temp_cycles;
user_duty = temp_duty;
set(user_cycles, user_duty / 1024.0);
}
}
If you just want some PWM outputs with frequency and duty cycle controlled by knobs then look at http://www.rmcybernetics.com/shop/PWM-OCmi or your local equivalent - for around the same cost as an Arduino you can get a robust working solution off the shelf, all you'd need to supply is the wiring connections and enclosure.
I am still pretty confused... I changed the code from TCCR1B |= _BV(CS10) to TCCR1B |= _BV(CS12); in the code below. I went from a low frequency of 7 kHz to 30.5 Hz, but I still need to get in the range of 0 to 3.5 Hz. I am not really sure what my change did or what I need to do from here.
// portions extracted from Timer1
// http://www.arduino.cc/playground/Code/Timer1
/* The wiper of a potentiometer should be hooked up to A0
and controls the frequency of the function generator. The
other connections of the potentiometer should be hooked up
to +5 and GND.
Possible frequencies are between about 7 khz and 300 khz.
Another potentiometer hooked up to A1 controls the duty
cycle, from very low to very high.
*/
int user_cycles;
int user_duty;
void set(int cycles, float duty) {
char oldSREG;
int dutyCycle = cycles * duty;
if (dutyCycle < 6) {
dutyCycle = 6; // Prevent duty cycle from being too short
}
if (dutyCycle > 1015) {
dutyCycle = 1015; // Prevent duty cycle from being 100%
}
if (cycles < 5) {
cycles = 5;/// Prevent frequency from being too high
}
oldSREG = SREG; // Save the registers
cli(); // Disable interrupts for 16 bit register access
ICR1 = cycles; // ICR1 is TOP in p & f correct pwm mode
OCR1A = dutyCycle; // OCR1A is BOTTOM
SREG = oldSREG; // Restore the registers
}
void setup()
{
pinMode(9, OUTPUT);
TCCR1A = 0; // clear control register A
TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // Clear all prescaler bits
TCCR1B |= _BV(CS12); // choose prescaler 1, no prescaling, and start the clock
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(13, OUTPUT);
}
void loop()
{
int temp_cycles = analogRead(A0);
int temp_duty = analogRead(A1);
if (temp_cycles != user_cycles || temp_duty != user_duty) {
user_cycles = temp_cycles;
user_duty = temp_duty;
set(user_cycles, user_duty / 1024.0);
}
}
If you look at the blink without delay code, you'll see that it produces a 0.5Hz PWM waveform with a 50% duty cycle.
It is very simple to modify to increase the frequency to 3.5Hz and modify the duty cycle
I recently changed my code to the following, which brought my lowest frequency to 7.5 Hz:
// portions extracted from Timer1
// http://www.arduino.cc/playground/Code/Timer1
/* The wiper of a potentiometer should be hooked up to A0
and controls the frequency of the function generator. The
other connections of the potentiometer should be hooked up
to +5 and GND.
Possible frequencies are between about 7 khz and 300 khz.
Another potentiometer hooked up to A1 controls the duty
cycle, from very low to very high.
*/
int user_cycles;
int user_duty;
void set(int cycles, float duty) {
char oldSREG;
int dutyCycle = cycles * duty;
if (dutyCycle < 6) {
dutyCycle = 6; // Prevent duty cycle from being too short
}
if (dutyCycle > 1015) {
dutyCycle = 1015; // Prevent duty cycle from being 100%
}
//if (cycles < 50) {
// cycles = 50; // Prevent frequency from being too high
// }
oldSREG = SREG; // Save the registers
cli(); // Disable interrupts for 16 bit register access
ICR1 = cycles; // ICR1 is TOP in p & f correct pwm mode
OCR1A = dutyCycle; // OCR1A is BOTTOM
SREG = oldSREG; // Restore the registers
}
void setup()
{
pinMode(9, OUTPUT);
TCCR1A = 0; // clear control register A
TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // Clear all prescaler bits
// TCCR1B |= _BV(CS10); // choose prescaler 1, no prescaling, and start the clock
TCCR1B |= (_BV(CS12) | _BV(CS10)); // Choose prescaler 1024 and start the clock
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(13, OUTPUT);
}
void loop()
{
int temp_cycles = analogRead(A0);
int temp_duty = analogRead(A1);
if (temp_cycles != user_cycles || temp_duty != user_duty) { // see if freq or duty cycle adjust has changed
user_cycles = temp_cycles*15; // if freq has been adjusted, change
user_duty = temp_duty; // if duty cycle has, change
set(user_cycles, user_duty / 1024.0);
}
}
I still need to bring the frequency to a range of approximately 300 mHz to 3.5 Hz, with controllable frequency and controllable duty cycle with potentiometers at A0 and A1, respectively.
I have looked over the "Blink without Delay" code and I don't understand how I could integrate it into my existing code. I apologize for my ignorance but I am a complete novice in programming and am not able to put it together.
OK, the example has a variable "interval" that controls the on and off times of the LED.
Guess how you could vary the frequency and duty cycle using analogRead
Would I define a variable as the analogRead() and utilize an if statement somehow but delete the interval variable and the current if statement they have with currentmillis, etc.? I really have no idea how to do this.
Well, why not work on one thing at a time?
First, set the frequency using analogRead to set the variable "interval".
Maybe use "map" to get the right range.
I set interval=analogRead(A0) and then set invterval=map(val, 0, 1023, 0, 255)... It never changed with the potentiometer and it's frequency was all over the place. I apologize for not understading, but I have no background and don't understand any of this