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

📄 motor.c

📁 基于M430单片机的步进电机控制器的设计与实现 基于的软件开发
💻 C
字号:
#include  <msp430x14x.h>

#define DCO_FREQ        1000000      // DCO frequency
#define ONE_SEC_CNT     512          // Number of WDT interrupts in 1 second
#define DEBOUNCE_CNT    0x05         // (1/512)*5 = ~10 msec debounce

#define DIR_MASK        0x01         // 0x01 is clockwise, 0x00 is counter-clockwise
#define STEP_MASK       0x02         // 0x00 is full-stepping, 0x02 is half-stepping
#define MOTION_MASK     0x04         // 0x00 is continuous, 0x04 is single-step

#define DEFAULT_RATE     0x8000      // Default stepping rate
#define MIN_RATE         0x8000      // Minimum stepping rate
#define MAX_RATE         0x0800      // Maximum stepping rate

// Default state is full-stepping, clockwise, continuous
unsigned char state = 1;             // State variable
unsigned char stepIndex = 0;         // State table index
unsigned int  rate = DEFAULT_RATE;   // Stepping rate
unsigned char change_rate_flag = 0;  // Flag indicating rate change
unsigned int  max_rate = MAX_RATE;   // Maximum stepping rate
unsigned int  min_rate = MIN_RATE;   // Minimum stepping rate

unsigned int SW[4]; 


void sys_init(void);
void Set_DCO(unsigned long freq);
void timerA_Init(void);
void uart0_Init(void);
void wdt_Init(void);

void toggle_stepping_mode(void);
void increase_stepping_rate(void);
void decrease_stepping_rate(void);
void toggle_motion(void);
void toggle_direction(void);

//定义串口操作变量
char nRev_UART0;			// 串口 0 的接收标志
char UART0_TX_BUF[10];		// 串口 0 的发送缓冲区
char UART1_RX_Temp[10];
char UART0_RX_BUF[10];		// 串口 0 的接收缓冲区
int nTX0_Len;
int nRX0_Len;
int nRX0_Len_temp;
char nTX0_Flag;
int nSend_TX0;


// 整步状态表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)
{
int i;
	// 停止WDT
	WDTCTL = WDTPW + WDTHOLD;
	sys_init();

	_EINT();

	for(;;)
	{
		if(nRev_UART0 == 1)
    	{
    	    nRev_UART0 = 0;
			for(i = 0;i < nRX0_Len;i++) UART1_RX_Temp[i] = UART0_RX_BUF[i];
			if((UART1_RX_Temp[0] == 'A') && (UART1_RX_Temp[1] == 'T'))
			{
				UART0_TX_BUF[0] = 'O';
				UART0_TX_BUF[1] = 'K';
				UART0_TX_BUF[2] = 13;
				nTX0_Len = 3;
				switch(UART1_RX_Temp[2])
				{
				case 'D': // 方向
					toggle_direction();
					break;
				case 'C': // 运动模式
					toggle_motion();
					break;
				case 'M': // 步进模式
					toggle_stepping_mode();
					break;
				case 'F': // 增加速率
					increase_stepping_rate();
					break;
				case 'S': // 降低速率
					decrease_stepping_rate();
					break;
				default: break;
				}
			}
			else
			{
				UART0_TX_BUF[0] = 'E';
				UART0_TX_BUF[1] = 'R';
				UART0_TX_BUF[2] = 'O';
				UART0_TX_BUF[3] = 'R';
				UART0_TX_BUF[4] = 'R';
				UART0_TX_BUF[5] = 13;
				nTX0_Len = 6;
			}
			// 设置中断标志,进入发送中断程序
			IFG1 |= UTXIFG0;		
    		nRX0_Len = 0;
		}
	}
}

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();

	// 初始化 UART0
	uart0_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 uart0_Init(void)
{
    //将寄存器的内容清零
    U0CTL = 0X00;
	//数据位为8bit
    U0CTL += CHAR;			
    
    U0TCTL = 0X00;	
	//波特率发生器选择ACLK
    U0TCTL += SSEL0;			
    
	//波特率为9600
    UBR0_0 = 0X03;			
    UBR1_0 = 0X00;
    UMCTL_0 = 0x4A;			
    //使能UART0的TXD和RXD
    ME1 |= UTXE0 + URXE0; 
	//使能UART0的RX中断
    IE1 |= URXIE0;
	//使能UART0的TX中断
    IE1 |= UTXIE0;			
    
	//设置P3.4为UART0的TXD
    P3SEL |= BIT4;
	//设置P3.5为UART0的RXD
    P3SEL |= BIT5;			
    //P3.4为输出管脚
    P3DIR |= BIT4;			
}

void timerA_Init(void)
{
	TACCR0 = rate;
	TACCTL0 = CCIE;
	TACTL = TASSEL_2 + MC_1 + TACLR;
}
interrupt [TIMERA0_VECTOR] void TimerA_ISR(void)
{
	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;
	}
}
////////////////////////////////////////
// 处理来自串口 0 的接收中断
interrupt [UART0RX_VECTOR] void UART0_RX_ISR(void)
{
	//接收来自的数据
    UART0_RX_BUF[nRX0_Len_temp] = RXBUF0;	
    
    nRX0_Len_temp += 1;
        
    if(nRX0_Len_temp >= 2)
    if(UART0_RX_BUF[nRX0_Len_temp - 2] == '\r' && 
		UART0_RX_BUF[nRX0_Len_temp - 1] == '\n')
    {
		// 过滤掉回车换行(\r\n)
    	if(nRX0_Len_temp == 2)			
    	{
    	    nRX0_Len_temp = 0;
    	}
    	else if(nRX0_Len_temp > 2)
    	{
    	    nRX0_Len = nRX0_Len_temp;
    	    nRev_UART0 = 1;
    	    nRX0_Len_temp = 0;
    	}    	
    }

}
////////////////////////////////////////
// 处理来自串口 0 的发送中断
interrupt [UART0TX_VECTOR] void UART0_TX_ISR(void)
{
    if(nTX0_Len != 0)
    {
		// 表示缓冲区里的数据没有发送完
    	nTX0_Flag = 0;				
    	
    	TXBUF0 = UART0_TX_BUF[nSend_TX0];
    	nSend_TX0 += 1;    	
    	if(nSend_TX0 >= nTX0_Len)
    	{
    	    nSend_TX0 = 0;
    	    nTX0_Len = 0;
    	    nTX0_Flag = 1;
    	}
    }
}
interrupt [WDT_VECTOR] void WDT_ISR(void)
{
	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) )
		{
			toggle_motion();
		}

		// 复位状态计数器
		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 )
			{
				toggle_direction();
			}
		}
		else
		{
			SW[0] = 0;
		}

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

			if( SW[1] == ONE_SEC_CNT )
			{
				toggle_stepping_mode();
				one_sec_flag = 1;
				SW[1] = 0;
			}
		}
		else
		{
			// 判断是否S2的激活状态小于1秒
			if( !one_sec_flag && (SW[1] >= DEBOUNCE_CNT) )
			{
				toggle_motion();
			}

			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 )
				{
					increase_stepping_rate();
				}
			}
			else // 单步模式
			{
				// 增加状态计数器
				++SW[2];

				if( (SW[2] % DEBOUNCE_CNT) == 0 )
				{
					increase_stepping_rate();
				}
			}
		}
		else  
		{
			SW[2] = 0;
		}

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

			if( SW[3] == DEBOUNCE_CNT )
			{
				decrease_stepping_rate();
			}
		}
		else
		{
			SW[3] = 0;
		}
	}
}
interrupt [PORT1_VECTOR] void PORT1_ISR(void)
{
	// 禁止端口1的中断
	P1IE = 0x00;

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

	// 使能看门狗中断
	IE1 |= WDTIE;
}
void increase_stepping_rate(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 decrease_stepping_rate(void)
{
	// 检查是否是连续模式
	if( (state & MOTION_MASK) == 0 )
	{
		if( rate <= (min_rate >> 1) )
		{
		rate <<= 1;
		change_rate_flag = 1;
		}
	}

	// 使能定时器A的中断
	TACCTL0 |= CCIE;
}
void toggle_stepping_mode(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 toggle_motion(void)
{
	state ^= MOTION_MASK;

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



⌨️ 快捷键说明

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