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

📄 motor.c

📁 msp430单片机设计实例及其综合知识。
💻 C
字号:
#include  <msp430x12x.h>
#include "Motor.h"

// 整步状态表A
static const unsigned char fullStepA[] =
{
    0x00,
    0x00,
    0x01,
    0x01
};
//  半步状态表B
static const unsigned char fullStepB[] =
{
    0x01,
    0x00,
    0x00,
    0x01
};
// 半步状态表A
static const unsigned char HalfStepA[] =
{
    0x01,   // 001   1
    0x06,   // 110   2
    0x00,   // 000   3
    0x00,   // 000   4
    0x00,   // 000   5
    0x07,   // 111   6
    0x01,   // 001   7
    0x01    // 001   8
};
// 逆时钟、半步状态表B
static const unsigned char CcwHalfStepB[] =
{
    0x01,   // 001   1
    0x01,   // 001   2
    0x01,   // 001   3
    0x06,   // 110   4
    0x00,   // 000   5
    0x00,   // 000   6
    0x00,   // 000   7
    0x07    // 111   8
};


// 顺时钟、半步状态表B
static const unsigned char CwHalfStepB[] =
{
    0x00,   // 000   1
    0x00,   // 000   2
    0x00,   // 000   3
    0x07,   // 111   4
    0x01,   // 001   5
    0x01,   // 001   6
    0x01,   // 001   7
    0x06    // 110   8
};
void main(void)
{
    // 停止WDT
    WDTCTL = WDTPW + WDTHOLD;
    //初始化
    sys_init();

    //打开中断
    _EINT();
    
    //循环
    for(;;)
    {
    }	
}

void sys_init(void)
{
    // 设置下降沿触发中断
    P1IES = 0x0f;
    P1IFG = 0x00;
    P1IE = 0x0f;

    // 设置 P2.3,2,1,0 为输出
    // 设置 P3.3,2,1,0 为输出
    P2OUT = 0x00;
    P3OUT = 0x00;
    P2DIR |= 0x0f;
    P3DIR |= 0x0f;

    // 设置DCO
    Set_DCO(DCO_FREQ);

    // 初始化 Timer A
    timerA_Init();

    // 初始化 WDT
    wdt_Init();
}
void Set_DCO(unsigned long freq)
{
    unsigned int clkCnt;
    unsigned int numDcoClks;
    unsigned int prevCnt = 0;

    // ACLK = LFXT1CLK/8 = 4096 Hz
    BCSCTL1 |= DIVA_3;                   
    numDcoClks = freq/4096;              

    TACCTL2 = CM_1 + CCIS_1 + CAP;
    TACTL = TASSEL_2 + MC_2 + TACLR;     
    while(1)
    {
	while( !(TACCTL2 & CCIFG) )
	{
	}

	TACCTL2 &= ~CCIFG;
	clkCnt = TACCR2 - prevCnt;
	prevCnt = TACCR2;

	if( numDcoClks == clkCnt )
	{
            //跳出循环
	    break;
	}
	else if( clkCnt > numDcoClks )
	{
	    DCOCTL--;

	    if( DCOCTL == 0xFF )
	    {
		if( BCSCTL1 & 0x07 )
		{
		    BCSCTL1--;
		}
		else
		{
		    break;
		}
	    }
	}
	else
	{
	    DCOCTL++;
	    if( DCOCTL == 0x00 )
	    {
		if( (BCSCTL1 & 0x07) != 0x07 )
		{
		    BCSCTL1++;                   
		}
		else
		{
		    break;
		}
	    }
	}
    }
    // ACLK = LFXT1CLK/1 = 32768 Hz
    BCSCTL1 &= ~DIVA_3;                  

    TACCTL2 = 0; 
    TACTL = 0;
}
void wdt_Init(void)
{
	// 设置时钟源为ACLK,1秒内产生512次
	WDTCTL = WDTPW + WDTTMSEL + WDTCNTCL 
                + WDTSSEL + WDTIS0 + WDTIS1;
}



void timerA_Init(void)
{
    TACCR0 = rate;
    TACCTL0 = CCIE;
    TACTL = TASSEL_2 + MC_1 + TACLR;
}
#if __VER__ < 200
    interrupt [TIMERA0_VECTOR] void TimerA_ISR(void)
#else
    #pragma vector=TIMERA0_VECTOR
    __interrupt void TimerA_ISR(void)
#endif
{
    unsigned char index;
    unsigned char p2 = 0;
    unsigned char p3 = 0;

    // 判断步进速率是否需要改变
    if( change_rate_flag )
    {
	TACCR0 = rate;
	change_rate_flag = 0;
    }

    // 判断状态
    switch( (state & 0x3) )
    {
	case 0x00:  // 整步、逆时钟方向
	    index = stepIndex & 0x03;
	    p2 |= fullStepA[index];
	    p3 |= fullStepB[index];
	    P2OUT = p2;
	    P3OUT = p3;
	    ++stepIndex;
	    break;
	case 0x01:  // 整步、顺时钟方向
	    index = stepIndex & 0x03;
	    p3 |= fullStepA[index];
	    p2 |= fullStepB[index];
	    P3OUT = p3;
	    P2OUT = p2;
	    ++stepIndex;
	    break;
	case 0x02:  // 半步、逆时钟方向
	    index = stepIndex & 0x07;
	    p2 |= HalfStepA[index];
	    p3 |= CcwHalfStepB[index];
	    P2OUT = p2;
	    P3OUT = p3;
	    ++stepIndex;
	    break;
	case 0x03:  // 半步、顺时钟方向
	    index = stepIndex & 0x07;
	    p3 |= CwHalfStepB[index];
	    p2 |= HalfStepA[index];
	    P3OUT = p3;
	    P2OUT = p2;
	    ++stepIndex;
	    break;
	default: break;
    }

    // 如果单步状态下,禁止定时器中断
    if( state & MOTION_MASK )
    {
	TACCTL0 &= ~CCIE;
    }
}
#if __VER__ < 200
    interrupt [WDT_VECTOR] void WDT_ISR(void)
#else
    #pragma vector=WDT_VECTOR
    __interrupt void WDT_ISR(void)
#endif
{
    unsigned char sw_state;
    static unsigned char one_sec_flag = 0;

    // 获得P1口的输入
    sw_state = ~P1IN & 0x0f;

    // 判断是否有键按下
    if( sw_state == 0x00 )
    {
	// 禁止看门狗中断
	IE1 &= ~WDTIE;
		
	// 判断是否S2的激活状态小于1秒
	if( !one_sec_flag && (SW[1] >= DEBOUNCE_CNT) )
	{
	    setMotion();
	}

	// 复位状态计数器
	SW[0] = 0;
	SW[1] = 0;
	SW[2] = 0;
	SW[3] = 0;

	// 复位标志
	one_sec_flag = 0;

	// 使能P1口的中断功能
	P1IFG = 0x00;
	P1IE = 0x0f;
    }
    else
    {
	// 检查是否是S1状态
	if( sw_state & 0x01 )
	{
	    if( SW[0] < ONE_SEC_CNT )
	    {
		// 增加状态计数器
		++SW[0];
	    }

	    if( SW[0] == DEBOUNCE_CNT )
	    {
                //设置方向
		setDirection();
	    }
	}
	else
	{
	    SW[0] = 0;
	}

	// 检查是否是S2状态
	if( sw_state & 0x02 )
	{
	    if( SW[1] < ONE_SEC_CNT )
	    {
		// 增加状态计数器
		++SW[1];
	    }

	    if( SW[1] == ONE_SEC_CNT )
	    {
                //设置步进模式
	        setStepMode();
		one_sec_flag = 1;
		SW[1] = 0;
	    }
	}
	else
	{
	    // 判断是否S2的激活状态小于1秒
	    if( !one_sec_flag && (SW[1] >= DEBOUNCE_CNT) )
	    {
		setMotion();
	    }

	    one_sec_flag = 0;
	    SW[1] = 0;
	}

	// 检查是否是S3状态
	if( sw_state & 0x04 )
	{
	    // 检查是否是连续模式
	    if( (state & MOTION_MASK) == 0 )
	    {
		if( SW[2] < ONE_SEC_CNT )
		{
		    // 增加状态计数器
		    ++SW[2];
		}

		if( SW[2] == DEBOUNCE_CNT )
		{
                    //增加速率
		    incStepRate();
		}
	    }
	    else // 单步模式
	    {
		// 增加状态计数器
		++SW[2];

		if( (SW[2] % DEBOUNCE_CNT) == 0 )
		{
                    //增加速率
		    incStepRate();
		}
	    }
	}
	else  
	{
	    SW[2] = 0;
	}

	// 检查是否是S4状态
	if( sw_state & 0x08 )
	{
	    if( SW[3] < ONE_SEC_CNT )
	    {
		// 增加状态计数器
		++SW[3];
	    }

	    if( SW[3] == DEBOUNCE_CNT )
	    {
                //减少速率
		decStepRate();
	    }
	}
	else
	{
	    SW[3] = 0;
	}
    }
}

#if __VER__ < 200
    interrupt [PORT1_VECTOR] void PORT1_ISR(void)
#else
    #pragma vector=PORT1_VECTOR
    __interrupt void PORT1_ISR(void)
#endif
{
    // 禁止端口1的中断
    P1IE = 0x00;

    // 清除端口1的中断标志
    P1IFG = 0x00;

    // 使能看门狗中断
    IE1 |= WDTIE;
}
void incStepRate(void)
{
    unsigned int new_rate;

    // 检查是否是连续模式
    if((state & MOTION_MASK) == 0 )
    {
	new_rate = rate >> 1;

	if( new_rate >= max_rate )
	{
	    rate = new_rate;
	    change_rate_flag = 1;
	}
    }

    //使能定时器A的中断
    TACCTL0 |= CCIE;
}
void decStepRate(void)
{
    // 检查是否是连续模式
    if((state & MOTION_MASK) == 0 )
    {
	if( rate <= (min_rate >> 1) )
	{
	    rate <<= 1;
	    change_rate_flag = 1;
	}
    }

    // 使能定时器A的中断
    TACCTL0 |= CCIE;
}
void setStepMode(void)
{
    // 切换步进模式
    state ^= STEP_MASK;

    // 检查是否是半步模式
    if( state & STEP_MASK )
    {
	// 从整步模式切换到半步模式
	// 定时器的频率加倍
	rate = (rate >> 1);
	change_rate_flag = 1;
	max_rate = (MAX_RATE >> 1);
	min_rate = (MIN_RATE >> 1);
    }
    else // 整步模式
    {
	// 从半步模式切换到整步模式
	// 定时器的频率减半
	rate = (rate << 1);
	change_rate_flag = 1;
	max_rate = MAX_RATE;
	min_rate = MIN_RATE;
    }
}

void setMotion(void)
{
    state ^= MOTION_MASK;

    // 检查是否是连续步进模式
    if((state & MOTION_MASK) == 0 )
    {
	// 使能定时器中断
	TACCTL0 |= CCIE;
    }
}
void setDirection(void)
{
    state ^= DIR_MASK;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -