📄 motor.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 + -