📄 pc temperature control .c
字号:
//
// Cornell 2005
// Edward Lo and Sihan Goi
// ECE476 final project
// Temperature sensor and fan controller
//
#include <mega32.h>
#include <stdio.h>
#include <string.h>
#include <delay.h>
//number of supported fans
#define MAXFAN 2
//wireless packet definitions (maintain DC balance)
#define start_packet 0b10100110
#define stop_packet 0b11010010
//timeout values for each task
#define t1 20000 //Update LCD
#define t2 20000 //Hyperterminal display
#define t3 1000 //Hyperterminal input
#define t4 500 //Read temperature
#define t5 100 //Adjust fan speed
#define t6 5000 //PWM pulse stretching
//values for temperature calibration
#define inittemp 0.76
#define roomtemp 72.0
#define opampGain 4.00
#define Arefvolt 5.09
//other thresholds
#define t_lockedrotor 5 //when a fault occurs for this many cycles, the user is notified
//conversion macros
#define getTemp(input) ((float)(roomtemp +( ((float)((float)input-fproomtemp)/255.0)*Arefvolt/(0.01 * opampGain) )))
#define getRpm(input) ((unsigned int)(60000.0 / (((float)input/10.0) * tachdivider)))
//I like these definitions
#define begin {
#define end }
#define LCDwidth 16 //characters
//lcd definitions
#asm
.equ __lcd_port=0x15
#endasm
#include <lcd.h> // LCD driver routines
enum { pwm, dac, off }; //fan mode
enum { user, auto }; //opmode
enum { wireless, computer }; //inputmode
enum { start, data, stop }; //wireless data packets
//variables
unsigned char i; //local counter
unsigned char j; //counter in ISR
unsigned char opmode, inputmode, fanmode[MAXFAN]; //operation modes
unsigned int counttime, time1, time2, time3, time4, time5, time6; //task scheduling timeout counters
//wireless stuff
unsigned char rstate; //receive state
unsigned char datain; //data from serial in
//lcd stuff
unsigned char lcddispnum; //remembers which fan we are displaying status for
char lcd_buffer[17]; //LCD display buffer
//alarm stuff
unsigned char f_alarm, f_alarmsound; //flags to determine if an alarm should light and sound
//temperature sensing stuff
unsigned char sensornum; //remembers which temperature sensor we are currently reading from
unsigned char tempsensor[MAXFAN]; //temperature reading from ADC register
unsigned char t_mintemp[MAXFAN]; //minimum temperature threshold when fan turns on
unsigned char t_alarmtemp[MAXFAN]; //maximum temperature threshold when alarm sounds
float fpcurrtemp[MAXFAN]; //current temperature
float t_fpmintemp[MAXFAN]; //min threshold temperature
float t_fpalarmtemp[MAXFAN]; //max threshold temperature
float fproomtemp; //room temperature (for calibration)
float fpmaxtemp; //temporary variable for calculating fan speed
//fan tachometer detection stuff
int tachhi[MAXFAN]; //counts time spent in high phase of tach pulse
int tachlo[MAXFAN]; //counts time spent in low phase of tach pulse
unsigned char rpmsensor[MAXFAN]; //holds current tach pulse value
unsigned char f_readrpm[MAXFAN]; //flag to read rpm
unsigned char f_tachphase[MAXFAN]; //flag to remember which phase of the tach pulse we are in
unsigned char f_lockedrotor[MAXFAN]; //flag to detect a locked rotor
unsigned int rpm[MAXFAN]; //holds the calculated rpm of a fan
float tachdivider; //adjust for each fan - pulses per revolution
//pwm and dac stuff
unsigned char dacout; //holds dac value (0-15)
unsigned char pwmspeed; //holds pwm duty cycle (0-255)
unsigned char pwmcnt; //specifically for fan 2 rpm detection
float fanspeed; //speed to drive fan at: 1.0 = 100% power, 0.0 = 0% power
//keyboard input stuff
char cmd;
unsigned int val1;
//RXC ISR variables
unsigned char r_index; //current string index
unsigned char r_buffer[90]; //input string
unsigned char r_ready; //flag for receive done
unsigned char r_char; //current character
//TX empth ISR variables
unsigned char t_index; //current string index
unsigned char t_buffer[90]; //output string
unsigned char t_ready; //flag for transmit done
unsigned char t_char; //current character
//the subroutines
void gets_int(void); //starts getting a string from serial line
void puts_int(void); //starts a send to serial line
void initialize(void); //all the usual mcu stuff
//scheduled tasks
void DispScreen(void);
void DispLCD(void);
void ReadTemp(void);
void Sysadmin(void);
void AdjustFanSpeed(void);
void PWMPulseStretch(void);
//**********************************************************
//timer 2 comparison ISR
// This ISR ticks down the timers used to run scheduled tasks.
// It generates the square wave for the piezo buzzer when an alarm should sound.
// It reads the tachometer pulses from the fans and detects rpm.
// It detects locked fan rotors based on the behaviour of the tach pulses
interrupt [TIM2_COMP] void timer2_compare(void)
begin
//Decrement the scheduler times if they are not already zero
if (time1>0) --time1;
if (time2>0) --time2;
if (time3>0) --time3;
if (time4>0) --time4;
if (time5>0) --time5;
if (time6>0) --time6;
//generates square wave for the alarm
if( counttime-- == 0 ) {
if( f_alarmsound ) PORTD.5 ^= 1;
counttime = 10;
}
//turn off pwm mode pulse stretching after getting tachometer reading
if( (fanmode[1] == pwm) && (pwmcnt == 3) ) {
TCCR0 = 0b01101011; //resume normal pwm mode
f_readrpm[1] = 0; //don't read rpm anymore
}
//cycle through each fan and get rpm data
for( j = 0; j < MAXFAN; j++ ) {
//get rpm sensor reading
rpmsensor[j] = (PINA >> (j+4)) & 0x1;
//sample tachometer pulses
if( f_readrpm[j] == 1 ) {
//tachometer pulse is HIGH
if (rpmsensor[j] == 1) {
f_tachphase[j] = 1;
if (tachhi[j] > 600) f_lockedrotor[j] = t_lockedrotor; //rotor is locked in place
tachhi[j]++; //counts in 0.1ms intervals
}
//tachnometer pulse is LOW
else {
//check for falling edge
if (f_tachphase[j] == 1) {
//check for locked rotor here! (check if time difference between phases is > factor of 3)
if( ((tachhi[j]-tachlo[j]) > (3*tachlo[j])) && (f_lockedrotor[j] < t_lockedrotor) ||
((tachlo[j]-tachhi[j]) > (3*tachhi[j])) && (f_lockedrotor[j] < t_lockedrotor) ) {
f_lockedrotor[j]++;
}
else {
//rotor operating normally
f_lockedrotor[j] = 0;
//pwm fan 2
if( fanmode[j] == pwm ) pwmcnt++; //for pwm pulse stretching, count number of cycles
}
if( fanmode[j] == pwm ) {
if( pwmcnt == 3 ) rpm[j] = getRpm(tachlo[j]); //converts ms to rpm
}
else {
rpm[j] = getRpm(tachlo[j]); //converts ms to rpm
}
tachhi[j] = 0; //reset for counting next cycle
tachlo[j] = 0; //reset for counting next cycle
}
f_tachphase[j] = 0;
if (tachlo[j] > 600) f_lockedrotor[j] = t_lockedrotor; //rotor is locked in place
tachlo[j]++; //counts in 0.1ms intervals
}
}
} //for loop
end
//**********************************************************
//UART character-ready ISR
interrupt [USART_RXC] void uart_rec(void)
begin
r_char=UDR; //get a char
//computer input mode
if( inputmode == computer ) {
UDR=r_char; //then print it
//build the input string
if (r_char != '\r') r_buffer[r_index++]=r_char;
else
begin
putchar('\n'); //use putchar to avoid overwrite
r_buffer[r_index]=0x00; //zero terminate
r_ready=1; //signal cmd processor
UCSRB.7=0; //stop rec ISR
end
}
//wireless input mode
else {
if( (rstate == start) && (r_char == start_packet) ) {
rstate = data;
}
else if( rstate == data ) {
datain = r_char;
rstate = stop;
}
else if( (rstate == stop) && (r_char == stop_packet) ) {
rstate = start;
}
else {
rstate = start;
}
}
end
/**********************************************************/
//UART xmit-empty ISR
interrupt [USART_DRE] void uart_send(void)
begin
t_char = t_buffer[++t_index];
if (t_char == 0)
begin
UCSRB.5 = 0; //kill isr
t_ready = 1; //transmit done
end
else UDR = t_char; //send the char
end
//**********************************************************
// -- non-blocking keyboard check initializes ISR-driven
// receive. This routine merely sets up the ISR, which then
// does all the work of getting a command.
void gets_int(void)
begin
memset(r_buffer,0x00,90);
r_ready = 0;
r_index = 0;
UCSRB.7 = 1;
end
//**********************************************************
// -- nonblocking print: initializes ISR-driven
// transmit. This routine merely sets up the ISR, then
// send one character. The ISR does all the work.
void puts_int(void)
begin
t_ready = 0;
t_index = 0;
if (t_buffer[0]>0)
begin
putchar(t_buffer[0]);
UCSRB.5=1;
end
end
//**********************************************************
//Entry point and task scheduler loop
// Handles mux selection, alarm and lights, and operation modes.
// Calls various task timers based on the timeout counters.
void main(void)
begin
initialize();
//main task scheduler loop -- never exits!
while(1)
begin
if (time1==0) DispLCD(); //display system status on LCD
if (time2==0) DispScreen(); //display information on terminal
if (time3==0) Sysadmin(); //gets input from keyboard
if (time4==0) ReadTemp(); //reads temperature sensors
if (time5==0) AdjustFanSpeed(); //adjusts fan speeds
if (time6==0) PWMPulseStretch(); //sets PWM to max for rpm detection
//wireless or computer mode?
inputmode = PINB.1;
//mux output
PORTB.0 = opmode;
PORTB.2 = inputmode;
//alarm system
f_alarm = 0;
for( i = 0; i < MAXFAN; i++ ) {
if( (fanmode[i] != off) &&
((fpcurrtemp[i] > t_fpalarmtemp[i]) ||
((fpcurrtemp[i] > t_fpmintemp[i]) && (f_lockedrotor[i] == t_lockedrotor))) ) {
f_alarm = 1;
break;
}
}
f_alarmsound = f_alarm;
PORTD.4 = f_alarm; //alarm status light
//status lights
PORTD.2 = (opmode == auto);
PORTD.3 = (inputmode == wireless);
//manual mode
if( opmode == user ) {
TCCR0 = 0;
PORTB.3 = 1; //drive PWM at full power to maintain rpm detection
PORTA.2 = 1; //enable fan 2 so it will spin
f_readrpm[0] = 1; //continue rpm detection
f_readrpm[1] = 1; //continue rpm detection
pwmcnt = 0; //so interrupt will always read rpm
}
//auto mode
if( opmode == auto ) {
//fan 2 (pwm fan)
if( (fanmode[1] != off) && (fpcurrtemp[1] > t_fpmintemp[1]) ) {
// turn on fan
if( f_readrpm[1] == 0 ) {
OCR0 = pwmspeed; //only set PWM speed if rpm is not being detected
}
TCCR0 = 0b01101011; //clear OC0 on upcount
}
else {
// turn off fan
OCR0 = 0;
TCCR0 = 0;
PORTB.3 = 0; //don't drive PWM
rpm[1] = 0;
f_lockedrotor[1] = 0;
}
//fan1 (dac fan)
if( (fanmode[0] != off) && (fpcurrtemp[0] > t_fpmintemp[0]) ) {
PORTA.2 = 1; //enable fan
}
else {
PORTA.2 = 0; //disable fan
rpm[0] = 0;
f_lockedrotor[0] = 0;
}
//output dac value to port B
PORTB = PINB & 0x0f | (dacout << 4);
}
//wireless input
if( inputmode == wireless ) {
switch( datain ) {
case 0b11000010: t_fpmintemp[0] += 1.0; break;
case 0b10100010: t_fpmintemp[0] -= 1.0; break;
case 0b10010010: t_fpmintemp[1] += 1.0; break;
case 0b10001010: t_fpmintemp[1] -= 1.0; break;
case 0b10000110: opmode ^= 1;
if( opmode == auto ) f_readrpm[1] = 0;
break;
}
datain = 0; //clears received data
}
end
end
//**********************************************************
//Adjusts fan speeds
// This function uses the temperature detected from the sensors
// and adjusts the fan speed accordingly. It assumes linear ramping.
// The percentage of power to use is stored in 'fanspeed'.
void AdjustFanSpeed(void)
begin
time5=t5;
for( i = 0; i < MAXFAN; i++ ) {
//get percentage of max speed to use
fpmaxtemp = (t_fpalarmtemp[i] - t_fpmintemp[i]) * 0.75;
fanspeed = (fpcurrtemp[i] - t_fpmintemp[i]) / fpmaxtemp;
//pwm adjustment (fan 2)
if( i == 1 ) {
if( fanspeed >= 1.0 ) {
pwmspeed = 255;
} else if( fanspeed <= 0 ) {
pwmspeed = 0;
} else {
pwmspeed = (unsigned char)( fanspeed * 255.0 );
}
}
//4 bit DAC adjustment (fan 1)
if( i != 1 ) {
if( fanspeed >= 1.0 ) {
dacout = 15;
} else if( fanspeed <= 0 ) {
dacout = 0;
} else {
dacout = (unsigned char)( fanspeed * 15.0 );
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -