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.
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.
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 ********************************************************