Coding advice for Arduino UNO ATMEGA328P timer 1 register [resolved]

update
Due to insufficient ports, I changed to using an Arduino Mega and my setup is working! Thank you to all who so kindly took time to provide advice.
There might be other errors for the listed code (meant for an UNO) but one major error I spotted was using integers for a float variable! Changing this helped my code in MEGA work.
Beginner’s mistake !


Hi,

I wish to run a solenoid valve with PWM using Timer 1 on UNO. The maximum rated frequency I can run the solenoid valve is pretty low at 10 Hz. At the moment, I am using potentiometers to vary the frequency and duty cycle of the pwm.
Unfortunately, the transistor and valves dont seem to work.
Does anyone have an inkling of what might be wrong? Thank you!

The code I have currently is:

int prescaler = 256; 
// intialize values for the PWM duty cycle set by pots
float potDC1 = 0;

void setup() {
  Serial.begin(9600);

  // input pins for valve switches
  pinMode(12, INPUT);

  // output pins for valve PWM
  pinMode(9, OUTPUT); //for timer 1, available PWM output pins are 9 or 10
  
  TCCR1A =0;// set the eight bits in TCCR register to 0 
  TCCR1B =0; 

  // set waveform generation to frequency and phase correct, non-inverting PWM output
  TCCR1A = _BV(COM1A1); //clear OC1A/OC1B on compare match when upcounting. set on compare match when downcounting 
  TCCR1B = _BV(WGM13) | _BV(CS12); //setting to PWM , phase and frequency correct mode. TOP: ICR1 //CS12 represents a prescaler of 256
    
}

void PWM(float pwmfreq, float pwmDC1){
  //set ICR 
  ICR1=F_CPU/(prescaler*pwmfreq*2);
  Serial.print("ICR1:");
  Serial.print(ICR1);
  Serial.println();
  // set duty cycles
  OCR1A = (ICR1) * (pwmDC1 * 0.01);
  Serial.print("OCR1A:");
  Serial.print(OCR1A);
  Serial.println();
}

void loop() {
  potDC1=0;
  if (digitalRead(12)==HIGH){
    potDC1=analogRead(A1)*100/1024;
    Serial.print(potDC1);} //to obtain duty cycle percentage and manually override the pwm frequency 
  float potpwmfreq=analogRead(A5)*10/1024; <<<<<<<<<<ERROR>>>>>>>>>>>>>>
  
  PWM(potpwmfreq, potDC1);

  }

It could be the code, the circuit or the solenoid power supply. Please post a circuit diagram with the parts clearly identified (hand drawn, not Fritzing), the details of the solenoid power supply, and a link to the solenoid data sheet.

Note that you can verify correct PWM operation with just an LED and 220 Ohm series resistor.

What is your theory about what these lines are doing?

    potDC1=analogRead(A1)*100/1024;
    Serial.print(potDC1);} //to obtain duty cycle percentage and manually override the pwm frequency
  float potpwmfreq=analogRead(A5)*10/1024;
 
  PWM(potpwmfreq, potDC1);

Thank you for the prompt reply.
Atatched is a picture of my circuit diagram. sorry if it looks a little amateur-ish; it’s the best i can provide for now. Also attached is the solenoid’s datasheet.

airtac valve-compressed.pdf (1.38 MB)

Note that you can verify correct PWM operation with just an LED and 220 Ohm series resistor.

I had something set up to do this, so I quickly tested your timer setup and code. When I run your code with a fixed PWM(5,50) the led blinks correctly.

So, if you're serial debugging output confirms what you are getting from the pots, then the problem is with what you are driving and how the output from pin9 is connected to it.

Can you post some detail of “power switch”? I added two lines to your code to send pin 9 output to the onboard led so you can see the output.

int prescaler = 256;
// intialize values for the PWM duty cycle set by pots
float potDC1 = 0;

void setup() {
  Serial.begin(9600);

  // input pins for valve switches
  pinMode(12, INPUT);
  pinMode(13,OUTPUT); //<<<<<<<<<<<<<<<<<<<<<<<

  // output pins for valve PWM
  pinMode(9, OUTPUT); //for timer 1, available PWM output pins are 9 or 10
 
  TCCR1A =0;// set the eight bits in TCCR register to 0
  TCCR1B =0;

  // set waveform generation to frequency and phase correct, non-inverting PWM output
  TCCR1A = _BV(COM1A1); //clear OC1A/OC1B on compare match when upcounting. set on compare match when downcounting
  TCCR1B = _BV(WGM13) | _BV(CS12); //setting to PWM , phase and frequency correct mode. TOP: ICR1 //CS12 represents a prescaler of 256
   
}

void PWM(float pwmfreq, float pwmDC1){
  //set ICR
  ICR1=F_CPU/(prescaler*pwmfreq*2);
  Serial.print("ICR1:");
  Serial.print(ICR1);
  Serial.println();
  // set duty cycles
  OCR1A = (ICR1) * (pwmDC1 * 0.01);
  Serial.print("OCR1A:");
  Serial.print(OCR1A);
  Serial.println();
}

void loop() {
  potDC1=0;
  if (digitalRead(12)==HIGH){
    potDC1=analogRead(A1)*100/1024;
    Serial.print(potDC1);} //to obtain duty cycle percentage and manually override the pwm frequency
  float potpwmfreq=analogRead(A5)*10/1024;
 
  PWM(potpwmfreq, potDC1);
  digitalWrite(13,digitalRead(9)); //<<<<<<<<<<<<<<<<<<<<<<

  }

Are all the grounds connected?

Why are you using PWM? These are not proportional valves.

If it is just for switching them at 10 Hz, do not expect them to last long, as that is the absolute maximum switching frequency. Get them working at much lower frequency before moving on.

Ok, will try with a lower frequency to play it safe. Thanks for the advice.
Also, yea I don't have proportional valves at the moment, so just using these for the moment to test the code.

cattledog:
I had something set up to do this, so I quickly tested your timer setup and code. When I run your code with a fixed PWM(5,50) the led blinks correctly.

So, if you're serial debugging output confirms what you are getting from the pots, then the problem is with what you are driving and how the output from pin9 is connected to it.

Thanks Cattledog, could I know if you perhaps mean you have a setup with a valve as well? If you do, I would appreciate a picture of how your set up looks like. Thank you for your time, appreciate it .

Thanks Cattledog, could I know if you perhaps mean you have a setup with a valve as well?

No, just the indicator led with a coded input of PWM(5,50).