10HZ PWM Automotive Fan

Hello

This is my first Arduino project.

I am trying to build a controller for a Mercedes Benz radiator cooling fan. The fan controller operates at 5V@ 10Hz. PWM signal between 0 to 90% duty cycle.

At the moment I have just built a system using a 10K pot to simulate a thremister all works fine except I'm having trouble converting the PWM frequency to 10Hz using the PWH.h library. My code is presented below. It works but only puts out the defaults 500Hz on pin 3. I am using the RoboRed board. As a new user I cant past the code yet but I guess I need to understand following few lines.

Any help would be appreciated.

int32_t frequency = 10;

void setup() {
pinMode(sensorPin, INPUT);
Serial.begin(9600);
InitTimersSafe();
SetPinFrequencySafe(FAN, frequency);
pinMode(FAN, OUTPUT);

}

PWMVal = map(sensorVal, 550, 1000, 26, 255);

pwmWrite(FAN, PWMVal);

You could do 10Hz in software, using the blink-without-delay example.

Please remember to use code tags when posting code.

Thanks for the reply. I will give it a try.

Can you tell me What is a code tag

Using T2 gives a maximum prescale ratio of 1/1024, e.g. about 16kHz from the 16MHz clock. As this is an 8 bit timer it can divide that frequency only down by 256 yielding about 640Hz. Most probably a wider frequency range can be coverd with the TimerOne library.

Are you sure that you need 10Hz PWM? I'd expect 10kHz instead. As already mentioned you can generate 10Hz PWM easily in code.

Definitely 10Hz. You can see it being tested here with a waveform generator and scope.

You're in luck my friend. Another user found this to work (albeit with a different requirement). I made the changes to match your requirement. Give it a shot.

int analogPin = A0;
int val = 0;
uint16_t duty = 0;

void setup() {
  // put your setup code here, to run once:
  PWM_init();
}

void loop() {
  // put your main code here, to run repeatedly:
  val = analogRead(analogPin);
  duty = map(val, 0, 1023, 0, 22500);
  OCR1B = duty;
  delay(50);
}

void PWM_init(void)
{
  /***************************
  Initialize the PWM hardware
  ***************************/

  // set OC1B output pin
  DDRB |= 1<<PORTB2;

  // set TIMER1 for Fast PWM mode, non-inverted output on OC1B pin
  TCCR1A = 1<<WGM11 | 1<<WGM10 | 1<<COM1B1 | 0<<COM1B0;
  TCCR1B = 1<<WGM13 | 1<<WGM12;

  // disable interrupts
  TIMSK1 = 0<<OCIE1B | 0<<OCIE1A | 0<<TOIE1;

  // set TOP value to generate initial 10 Hz [250 KHz / 25000]
  OCR1A = (25000 - 1);

  // set initial duty cycles at 10%
  OCR1B = 2500;

  // start TIMER1 at 250 KHz [DIV64]
  TCCR1B = 1<<WGM13 | 1<<WGM12 | 0<<CS12 | 1<<CS11 | 1<<CS10;

  return;
}

Potentiometer input on A0 and PWM signal out on D10

I did solve the problem. After a little reading I found that a special special high resolution command is required to get 16 bit resolution for frequencies from 1Hz to 2MHz. It also only works on pin's 9 and 10 on the RoboRed.

The following changes made it work

Set the fan pin to pin 9 using int FAN = 9;
Set PWM value to a 16 bit number using int16_t PWMVal;
Use pwmWriteHR(FAN, PWMVal) instead of pwmWrite(FAN, PWMVal);
Use PWMVal = map(sensorVal, 550, 1000, 6000, 65535) instead of PWMVal = map(sensorVal, 550, 1000, 26, 255);

Code that works **********************************

#include <PWM.h>
// Note for low frequency < 31Hz,the high resolution pwmWriteHR() must be used with 16 bit PWM Value
//For the RoboRed only pins 9 and 10 can be used with 16 bit resolution

int sensorPin = A0;
int FAN = 9;
int sensorVal;
int16_t PWMVal;
int32_t frequency = 10;

void setup() {
  // put your setup code here, to run once:
  pinMode(sensorPin, INPUT);
  Serial.begin(9600);
  InitTimersSafe();

  //sets the frequency for the specified pin
  bool success = SetPinFrequencySafe(FAN, frequency);
  
  //if the pin frequency was set successfully, pin 13 turn on. Pin 13 can be used to light an LED etc.
  if(success) {
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);    
  }

}

void loop() {
  // put your main code here, to run repeatedly:
  //this code prints sensor value to the console
  //Serial.println(sensorVal);
  //delay(1000);

  //read sensor value and set upper limit cap
  sensorVal = analogRead(sensorPin);
  if(sensorVal >1000){
    sensorVal = 1000;
  }

  //map and assign pwm values to the fan output 0 to 65535 corresponds to 0 to 100%
  PWMVal = map(sensorVal, 550, 1000, 6000, 65535);

  //set 550 as out cutout or cut in limit where the fan switches from off to the lower PWM limit
  if(sensorVal <550){
    PWMVal = 0;
  }

  //write the PWM value to the pwm output pin
  pwmWriteHR(FAN, PWMVal);

  //Serial.println(sensorVal);
  //Serial.println(PWMVal);
  //delay(1000);

}

End of Code ********************************************************

I figured out the code tag thing.

Thanks to all that replied.

Thanks for the reply. I guess there are 1000 ways to do this but nice to find a solution without libraries.

It's the </> button in the editor for locking preformatted text.

Well, if you dig enough into the PWM library, you'll probably see the same timer registers I configured

I did notice that. But it was scary.