📄 fan.c
字号:
#include <msp430x417.h>
#include "fan.h"
//温度表,需要根据不同的系统修改该表
const unsigned int resTabPositiveC[POSRANGE] =
{311, 296, 281, 267, 254, 242, 231, 220, 210, 200, 190, 181, 173, 165,
157, 150, 143, 137, 131, 125, 120, 114, 109, 105, 100, 96, 92, 88, 84,
81, 77, 74, 71, 68, 65, 63, 60, 58, 55, 53, 51, 49, 47, 45, 44, 42,
40, 39, 37, 36, 35, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23,
22, 22, 21, 20, 19, 19, 18, 18, 17, 16, 16, 15, 15, 14, 14,
13, 13, 13, 12, 12, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9,
8, 8, 8, 8, 7, 7, 7};
//风扇状态
FanLevel level = FANSLEVEL1;
//系统状态
Status status;
//风扇转数(RPM)
unsigned int tachCount = 0;
//RPM的值
unsigned int tachRPM = 0;
//上一个RPM的值
unsigned int lastRPM = 0;
//摄式温度值
signed int currentDegC = 0;
//华式温度值
signed int currentDegF = 0;
//占空比
unsigned char dutyCycles[ MAXLEVELSETTINGS] =
{ L0DUTYCYCLE, L1DUTYCYCLE, L2DUTYCYCLE,
L3DUTYCYCLE, L4DUTYCYCLE, L5DUTYCYCLE};
void main(void)
{
//系统初始化
SYS_init();
//PWM初始化
PWM_init();
//温度采集初始化
TEMP_init();
//中断使能
_EINT();
for (;;)
{
//低功耗模式0
_BIS_SR(LPM0_bits + GIE);
//更新转速
refreshTach();
//采集温度
sampleTemp();
//设置风扇速度
setFanSpeed();
}
}
void TEMP_init()
{
//P1口功能设置
P1SEL &= ~(REF+THERM);
//方向设置
P1DIR |= (REF+THERM);
//清除输出
P1OUT &= ~(REF+THERM);
//比较器输入禁止
CAPD = (REF+THERM+CA_IN);
//设置比较器
CACTL2 = P2CA0;
}
signed int cnvtTempDegC(long int rSENSE)
{
signed int tempDegC;
int i = 0, k = 1;
//除以100
rSENSE /= 100;
if ((rSENSE < 326) && (rSENSE >= resTabPositiveC[POSRANGE-1]))
{
while(( resTabPositiveC[i] - rSENSE) > 0)
{
//增加值
i++;
//K的值等于温度
k++;
}
//摄式温度
tempDegC = k + 1;
}
else if (rSENSE >= 326)
{
// 温度是0
k = 0;
tempDegC = k;
}
else
{
//温度超界
tempDegC = OUTOFRANGE;
}
//温度值
return (tempDegC + CALFACTORDEGC);
}
unsigned int measureCount(int temperatureSource)
{
unsigned int TIMERCCR_COUNT;
unsigned int TIMERA_COUNT;
//输出高电平
P1OUT |= REF;
//比较器端口管脚使能
CAPD &= ~REF;
//设置记数的周期:TAR+5ms
CCR1 = PERIOD5MSEC;
//比较器模式,中断使能
CCTL1 = CCIE;
//计数器内容清零时钟源为SMCLK,连续记数模式
TA0CTL = TASSEL1+TACLR+MC1;
//等待CCR1中断
LPM0;
//比较器端口管脚禁止
CAPD |= REF;
//输出低电平,测量放电时间
P1OUT &= ~REF;
//比较器负段接内部参考源(0.25*Vcc),
//比较器打开
CACTL1 = CARSEL+CAREF0+CAON;
//下降沿捕获,CCIB为捕获事件的输入源
//工作在捕获模式,中断使能
TA0CCTL1 = CM1+CCIS0+CAP+CCIE;
//将计数器的值存储到变量里
TIMERA_COUNT = TAR;
//比较器端口管脚使能
CAPD &= ~temperatureSource;
//等待CCR1中断
LPM0;
//保存计数器的值
TIMERCCR_COUNT = CCR1;
//得到放电所用的记数值
TIMERCCR_COUNT -= TIMERA_COUNT;
//比较器端口管脚禁止
CAPD |= temperatureSource;
//比较器模块禁止
CACTL1 = 0x00;
//定时器禁止
TA0CCTL1 = 0x00;
TA0CTL = 0x00;
//P2口的管脚中断使能
P2IE |= (TACH);
//返回放电的记数值
return(TIMERCCR_COUNT);
}
void sampleTemp(void)
{
long int tREF, tSENSE;
float rTHERM;
//参考电阻放电记数
tREF = measureCount(REF);
//测量电阻放电记数
tSENSE = measureCount(THERM);
//电阻计算
rTHERM = SLOPEADrREF * ((float)tSENSE / tREF);
//电阻转换成温度
currentDegC = cnvtTempDegC(rTHERM);
//摄式温度转换成华式温度
currentDegF = ((((9.0/5.0) *
(currentDegC)) + 32.0) + CALFACTORDEGF);
}
void PWM_init(void)
{
//设置输出方向
P2DIR |= PWM;
//设置成功能管脚
P2SEL |= PWM;
//设置PWM周期
TA1CCR0 = PERIOD050USEC;
//时钟源为SMCLK,定时器为增记数模式
TA1CTL = TASSEL_2 + MC_1;
//设置PWM输出为置位方式
TA1CCTL1 = OUTMOD_1;
}
void changeLevelAndSpeed(FanLevel systemLevel)
{
float dutyCycle;
//风扇速度等级
level = systemLevel;
//获取占空比
dutyCycle = ((float)(dutyCycles[level])) / 100;
if (dutyCycle > 0.99)
{
//PWM输出复位信号
TA1CCTL1 = OUTMOD_5;
}
else
{
//更新比较的记数值
TA1CCR1 = (dutyCycle * PERIOD050USEC);
//产生PWM信号(置位/复位)
TA1CCTL1 = OUTMOD_3;
}
}
void setFanSpeed(void)
{
FanLevel level;
if (currentDegF <= L0)
{
//数据不正确
return;
}
else if (currentDegF <= L1toL2)
{
//风速等级为1
level = FANSLEVEL1;
}
else if (currentDegF <= L2toL3)
{
//风速等级为2
level = FANSLEVEL2;
}
else if (currentDegF <= L3toL4)
{
//风速等级为3
level = FANSLEVEL3;
}
else if (currentDegF <= L4toL5)
{
//风速等级为4
level = FANSLEVEL4;
}
else
{
//风速等级为5
level = FANSLEVEL5;
}
//更新PWM和更新速度
changeLevelAndSpeed(level);
}
void SYS_init()
{
volatile unsigned int i;
//停止看门狗
WDTCTL = WDTPW + WDTHOLD;
//设置电容
FLL_CTL0 |= XCAP18PF;
//延时一点时间
for(i = 0; i < 10000; i++);
//设置为一般I/O口
P1SEL &= ~(ACTIVITY);
//设置为输出
P1DIR |= (ACTIVITY);
//设置为一般I/O口
P2SEL &= ~(TACH);
//设置为输入方向
P2DIR &= ~(TACH);
//该管脚中断使能
P2IE |= (TACH);
//下降沿触发中断
P2IES |= (TACH);
//ACLK为看门狗的时钟源,清除看门狗记数,
//工作在定时器模式
WDTCTL = WDT_ADLY_1000;
//使能看门狗中断
IE1 |= WDTIE;
}
void setStatusLED( Status status)
{
switch (status)
{
case OK:
{
//设置变量
status = OK;
//切换管脚电平
P1OUT ^= ACTIVITY;
break;
}
case ALARM:
{
//设置变量
status = ALARM;
//输出低电平,LED一直亮
P1OUT &= ~ACTIVITY;
break;
}
default: break;
}
}
void updateTach(void)
{
//中断禁止
P2IE &= ~(TACH);
_NOP();
//将脉冲数转换成转速
tachRPM = (tachCount / PULSESPERREVOLUTION) * 60;
//中断使能
P2IE |= (TACH);
//清除计数器
tachCount = 0;
}
void refreshTach()
{
if (tachRPM == 0)
{
//风扇停止,设置告警LED
setStatusLED(ALARM);
}
else
{
//风扇运行,解除告警LED
setStatusLED(OK);
}
//更性转速
updateTach();
//记录转速
lastRPM = tachRPM;
}
//端口2中断服务程序
#if __VER__ < 200
interrupt [PORT2_VECTOR] void PORT_ISR(void)
#else
#pragma vector=PORT2_VECTOR
__interrupt void PORT_ISR(void)
#endif
{
//脉冲检测到?
if (P2IFG & TACH)
{
//增加计数器
tachCount++;
//清除中断标志
P2IFG &= ~TACH;
}
}
//定时器A1中断服务程序
#if __VER__ < 200
interrupt [TIMER0_A1_VECTOR] void TIMER0_A1_ISR(void)
#else
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void)
#endif
{
//退出LPM0模式
LPM0_EXIT;
//清除中断标志
TA0CCTL1 &= ~CCIFG;
}
//看门狗中断服务程序
#if __VER__ < 200
interrupt [WDT_VECTOR] void WDT_ISR(void)
#else
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
#endif
{
//退出LPM0模式
LPM0_EXIT;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -