I did something similar with a 30KHz Chassis Fan project a while back, but experimented with other Timer/Counter modes ( Phase Correct Mode, Fast PWM Mode, and Asynchronous Mode ). Here's my code for ATtiny85....
//3D Printer Chassis Fan Project, version 1.0
//
// Developed for ATtiny85 microcontroller on Digispark Development Board (16.5MHz, 5V)
// Thermister Sensor Defines
#define THERMISTORPIN 1 // which analog pin connected: using pin P2 (analog pin 1)
#define THERMISTORNOMINAL 10000 // resistance at 25 degrees C
#define TEMPERATURENOMINAL 25 // temp. for nominal resistance (almost always 25 C)
#define NUMSAMPLES 5 // how many samples to take and average, more takes longer
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT 4050 // TT Series,10K ohm, TTC05103, beta = 4050
#define SERIESRESISTOR 10000 // the value of the 'other' resistor
// PWM MOSFET Fan Driver
#define MOSFET_PIN 1 // digital output pin for PWM, using pin P1 ( pin 1)
#define HYSTERESIS 1 // Fan Speed Change Temperature Hysteresis
// Define fan speed temperature ranges (degrees C)
#define MIN_TEMP_DETECT -40 // if less than -40C or sensor short circuit
#define MAX_TEMP_OFF 23 // -40 thru 23C (-40F - 73F), fan off
#define MAX_TEMP_LOW 26 // 24C - 26C(73F - 79F), fan speed low
#define MAX_TEMP_MEDIUM_LOW 30 // 27C - 30C(79F - 86F), fan speed low-medium
#define MAX_TEMP_MEDIUM 35 // 31C - 35C(86F - 95F), fan speed medium
#define MAX_TEMP_MEDIUM_HIGH 40 // 36C - 40C(95F - 104F), fan speed medium-high
// 40C+(104F+), fan speed high, or sensor open circuit
// Define fan speeds (PWM duty cycle values in percent)
#define LOW_SPEED 77 // 30% duty cycle (0.30 * 510/2 = 76.5)
#define MEDIUM_LOW_SPEED 89 // 35% duty cycle (0.35 * 510/2 = 89.25)
#define MEDIUM_SPEED 102 // 40% duty cycle (0.40 * 510/2 = 102)
#define MEDIUM_HIGH_SPEED 178 // 70% duty cycle (0.70 * 510/2 = 178.5)
#define HIGH_SPEED 230 // 90% duty cycle (0.90 * 510/2 = 229.5)
// Variables
uint16_t samples[NUMSAMPLES];
int fanSpeed = 0; // fan speed setting: 0 = off, 1 = low, 2 = low-medium, 3 = medium, 4 = medium-high 5 = high
// Function Prototypes
void runFan(int fanSpeed);
void blinkLED(int numBlinks); // debug code
// Setup
void setup(void) {
// thermister sensor setup
analogReference(DEFAULT);
// fan motor output pin setup
pinMode(MOSFET_PIN, OUTPUT); // PB1 (PortB, pin 1)
// DDRB = _BV(DDB1); // PB1 (PortB, pin 1) sets pin as output, equal to line above
// Timer/Counter setup
// Timer0 setup in "Phase Correct PWM Mode", 32.3KHz (16.5MHz/510) on pin 1 {PB1 (OC0B)}
TCCR0A = _BV(WGM00) // Mode 1, PWM,Phase Correct,TOP = 0xFF, datasheet Table 11-5
// WGM0[2:0] = 0,0,1
| _BV(COM0B1); // OCOB clear up-cnt, set on down-cnt, datasheet Table 11-4
TCCR0B = _BV(CS00); // clk/no-prescaling, datasheet Table 11-6
OCR0B = 0; // set compare match value, initialize to OFF or 0% duty cycle
//*/
/*/ Timer0 for "Fast PWM Mode", 32.2KHz (0.25 * 16.5MHz/(8*256) on pin 1 {PB1 (OC0B) }
TCCR0B = _BV(CS01) // clk/8 from prescaler, datasheet Table 11-6
// CS0[2:0] = 0,1,0
| _BV(WGM02); // Fast PWM Mode, OCRA = TOP
TCCR0A = _BV(WGM01) | _BV(WGM00) // mode 7, datasheet Table 11-5
| _BV(COM0B1) // inverting mode, datasheet Table 11-3
| _BV(COM0B0)
//| _BV(COM0A1)
//| _BV(COM0A0)
;
OCR0A = 64; // set TOP for ~30kHz (0.25 *256 = 64)
OCR0B = 64; // compare match value, initialized to OFF or 0% duty cycle
//*/
/*/ Set Timer1 for "Asynchronous Mode", 30KHz PWM frequency on pin 1 {PB1(OC1A)}
TCCR1 = _BV(PWM1A) // PWM A comparator enable,
| _BV(COM1A1) // clear OC1A output line (pin1 on compare match)
| _BV(CS12) | _BV(CS10); // T/C Prescaler bits set to T1CK/16
OCR1C = 132; // set match value of PWM A comparator
OCR1A = 0; // set pin 1 PWM off (0% duty cycle)
PLLCSR = _BV(PLLE); // enable timer1 PLL
while (!( PLLCSR & _BV(PLOCK) ));// pause until PLL stabalizes and PLOCK bit is set (~100usec)
PLLCSR = _BV(PCKE); // Timer1 PCK clock enable (64MHz)
//*/
//*/
runFan(4); // fan medium-high
delay(1500); // for 1/2 second period
runFan(0); // fan off
//*/
}
void loop(void) {
/*/ Timer0, "Phase Correct PWM Mode" ...
//OCR0B = 230; // 90% duty cycle (0.90 * 510/2 = 229.5)
//delay(5000);
//OCR0B = 178; // 70% duty cycle (0.70 * 510/2 = 178.5)
//delay(5000);
OCR0B = 102; // 40% duty cycle (0.40 * 510/2 = 102)
delay(8000);
OCR0B = 89; // 35% duty cycle (0.35 * 510/2 = 89.25)
delay(8000);
OCR0B = 77; // 30% duty cycle (0.30 * 510/2 = 76.5)
delay(8000);
OCR0B = 0; // PWM off
delay(5000);
// end - Timer0 "Phase Correct PWM Mode" ...
//*/
/*/ Timer0, "Fast PWM Mode" ...
// OCR0B = 32; // 50% duty cycle (0.50 * 64 = 32)
OCR0B = 48; // 25% duty cycle {64 * (1 - 0.25) = 48}
delay(5000);
OCR0B = 64; // PWM off
delay(5000);
// end - Timer0 "Fast PWM Mode" ...
//*/
/* // Timer1 "Asynchronous Mode" ...
OCR1A = 66; // 50% duty cycle
delay(50000);
OCR1A = 0; // PWM off
delay(50000);
// end - Timer 1 "Asynchronous Mode" ...
//*/
// Chassis Fan Main Loop ...
uint8_t i;
float average;
// take N thermistor samples in a row, with a slight delay
for (i=0; i< NUMSAMPLES; i++) {
samples[i] = analogRead(THERMISTORPIN);
delay(10);
}
// average all the samples out
average = 0;
for (i=0; i< NUMSAMPLES; i++) {
average += samples[i];
}
average /= NUMSAMPLES;
// convert the average sampled value (0-256) to average sensor resistance
average = 1023 / average - 1;
average = SERIESRESISTOR / average;
//Serial.print("Thermistor resistance "); // breadboard test with UNO
//Serial.println(average); // breadboard test with UNO
float steinhart;
steinhart = average / THERMISTORNOMINAL; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)
steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // convert to C
delay(1000);
// Adjust cooling fan speed by defined temperature ranges
float temp = steinhart;
int newFanSpeed;
if ( temp >= MIN_TEMP_DETECT ){
if ( (temp < MAX_TEMP_OFF + HYSTERESIS && fanSpeed == 0) || (temp < MAX_TEMP_OFF - HYSTERESIS && fanSpeed > 0) ) newFanSpeed = 0; // fan off
else if ( (temp < MAX_TEMP_LOW + HYSTERESIS && fanSpeed <= 1) || (temp < MAX_TEMP_LOW - HYSTERESIS && fanSpeed > 1) ) newFanSpeed = 1; // low
else if ( (temp < MAX_TEMP_MEDIUM_LOW + HYSTERESIS && fanSpeed <= 2) || (temp < MAX_TEMP_MEDIUM_LOW - HYSTERESIS && fanSpeed > 2) ) newFanSpeed = 2; // low-medium
else if ( (temp <= MAX_TEMP_MEDIUM + HYSTERESIS && fanSpeed <= 3) || (temp < MAX_TEMP_MEDIUM - HYSTERESIS && fanSpeed > 3) ) newFanSpeed = 3; // medium
else if ( (temp <= MAX_TEMP_MEDIUM_HIGH + HYSTERESIS && fanSpeed <= 4) || (temp < MAX_TEMP_MEDIUM_HIGH - HYSTERESIS && fanSpeed > 4) ) newFanSpeed = 4; // medium-high
else newFanSpeed = 5; // temp > MAX_MEDIUM_HIGH, sensor short-circuit
}
else newFanSpeed = 5; // temp < MIN_TEMP_DETECT, in case sensor is open-circuit
if (newFanSpeed != fanSpeed){
fanSpeed = newFanSpeed;
runFan(fanSpeed); // disable this line for debug code to blink LED to indicate fan speed
}
//blinkLED(fanSpeed); // debug code, test fanSpeed changes with temperature using LED blink count
}
// runFan function, Timer0 set to "Phase Correct PWM Mode"
void runFan(int fanSpeed){
switch (fanSpeed){
case 0: OCR0B = 0; // Fan off
break;
case 1: OCR0B = MEDIUM_SPEED; // kickstart fan
delay(100);
OCR0B = LOW_SPEED;
break;
case 2: OCR0B = MEDIUM_LOW_SPEED;
break;
case 3: OCR0B = MEDIUM_SPEED;
break;
case 4: OCR0B = MEDIUM_HIGH_SPEED;
break;
default:OCR0B = HIGH_SPEED;
}
}
ChassisFan.ino (9.04 KB)