⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fan.c

📁 MSP430单片机常用模块与综合系统实例精讲 的:“程序代码”、“实例插图”、“电路图”3个文件夹。以及MSP430F14X系列单片机的官方源码"CODE-MSP430F14X" 其中各个文件夹主要
💻 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 + -