📄 步进电动机控制_2812.c
字号:
#include "DSP281x_Device.h"
#include "IQmathLib.h"
#pragma DATA_SECTION(sine_table,"IQmathTables");
#define DIR_MASK 0x01 // 0x01 顺时针,0x00逆时针
#define STEP_MASK 0x02 // 0x00 全步,0x02半步
#define MOTION_MASK 0x04 // 0x00 连续,0x04单步
#define DEFAULT_RATE 0x8000 // 默认步进速度
#define MIN_RATE 0x8000 // 最小速度
#define MAX_RATE 0x0800 // 最大速度
// 默认状态:全步、顺时针、连续模式
unsigned char state = 1; // 状态变量
unsigned char stepIndex = 0; // 状态表索引
unsigned int rate = DEFAULT_RATE; // 步进速度
unsigned char change_rate_flag = 0; // 改变速度标识
unsigned int max_rate = MAX_RATE; // 最大步进速度
unsigned int min_rate = MIN_RATE; // 最小步进速度
unsigned int SW[4] = {0, 0, 0, 0}; // 开关状态计数
// 系统初始化
void Gpio_select(void);
void InitSystem(void);
void SCI_Init(void);
interrupt void T1_Compare_isr(void); // 定时器1中断服务程序
interrupt void SCI_RX_isr(void) // 串口接收数据中断服务程序
// 控制操作函数
void toggle_stepping_mode(void);
void increase_stepping_rate(void);
void decrease_stepping_rate(void);
void toggle_motion(void);
void toggle_direction(void);
// 全步状态表 table A
static const unsigned char fullStepA[] =
{
0x00,
0x00,
0x01,
0x01
};
// 全步状态表 table B
static const unsigned char fullStepB[] =
{
0x01,
0x00,
0x00,
0x01
};
// 半步状态表 table 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
};
// 逆时针半步状态表 table 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
};
// 顺时针半步状态表 table 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)
{
InitSystem(); // 初始化DSP内核寄存器
Gpio_select(); // 设置GPIO引脚功能
InitPieCtrl(); // 初始化外设中断扩展单元 ( 代码在: DSP281x_PieCtrl.c)
InitPieVectTable(); // 初始化外设中断扩展向量表( 代码在:DSP281x_PieVect.c )
// 重新映射定时器1(Timer 1)的比较中断入口
EALLOW; // 允许更改保护的寄存器
PieVectTable.T1CINT = &T1_Compare_isr;
PieVectTable.RXAINT = &SCI_RX_isr;
EDIS; // 禁止更改保护的寄存器
// 使能T1比较中断:PIE-组2,中断5
PieCtrlRegs.PIEIER2.bit.INTx5=1;
// 使能PIE中的SCI_A_RX_INT中断
PieCtrlRegs.PIEIER9.bit.INTx1 = 1;
// 使能 CPU INT2,GP -Timer1的比较中断连接到该中断
// 使能 CPU INT 9
IER |= 0x102;
// 全局中断使能,并使能具有更高优先级的适时调试方式
EINT; // 使能全局中断 INTM
ERTM; // 使能全局适时中断DBGM
// 串口初始化
SCI_Init();
// 配置事件管理器A EVA
// 假定事件管理器A的时钟已经在InitSysCtrl()中使能;
// T1/T2逻辑驱动T1PWM / T2PWM ;
EvaRegs.GPTCONA.bit.TCMPOE = 1;
// GP Timer 1 比较输出配置:低电平有效
EvaRegs.GPTCONA.bit.T1PIN = 1;
EvaRegs.T1CON.bit.FREE = 0; // 仿真操作时挂起
EvaRegs.T1CON.bit.SOFT = 0; // 仿真操作时挂起
EvaRegs.T1CON.bit.TMODE = 2; // 连续递增计数模式
EvaRegs.T1CON.bit.TPS = 0; // 预定标系数 = 1 : 75 MHz
EvaRegs.T1CON.bit.TENABLE = 0; // 禁止GP Timer 1操作
EvaRegs.T1CON.bit.TCLKS10 = 0; // 使用内部时钟
EvaRegs.T1CON.bit.TCLD10 = 0; // 等于0时比较装载
EvaRegs.T1CON.bit.TECMPR = 1; // 使能比较操作
EvaRegs.T1PR = 1500;
EvaRegs.T1CMPR = EvaRegs.T1PR/2;
EvaRegs.EVAIMRA.bit.T1CINT = 1;
EvaRegs.T1CON.bit.TENABLE = 1; // 使能 GP Timer 1
while(1)
{
EALLOW;
SysCtrlRegs.WDKEY = 0x55; // 看门狗控制
SysCtrlRegs.WDKEY = 0xAA;
EDIS;
}
}
// 通用IO选择
void Gpio_select(void)
{
EALLOW;
GpioMuxRegs.GPAMUX.all = 0x0; // 所有GPIO端口配置成I/O方式
GpioMuxRegs.GPBMUX.all = 0x0;
GpioMuxRegs.GPDMUX.all = 0x0;
GpioMuxRegs.GPFMUX.all = 0x0;
GpioMuxRegs.GPEMUX.all = 0x0;
GpioMuxRegs.GPGMUX.all = 0x0;
GpioMuxRegs.GPADIR.all = 0xFFFF; // GPIO PORT 配置为输入
GpioMuxRegs.GPBDIR.all = 0xFFFF; // GPIO PORT 配置为输出
GpioMuxRegs.GPDDIR.all = 0x0; // GPIO PORT 作为输入
GpioMuxRegs.GPEDIR.all = 0x0; // GPIO PORT 作为输入
GpioMuxRegs.GPFDIR.all = 0x0; // GPIO PORT 作为输入
GpioMuxRegs.GPGDIR.all = 0x0; // GPIO PORT 作为输入
GpioMuxRegs.GPAQUAL.all = 0x0; // 设置GPIO量化值为0
GpioMuxRegs.GPBQUAL.all = 0x0;
GpioMuxRegs.GPDQUAL.all = 0x0;
GpioMuxRegs.GPEQUAL.all = 0x0;
EDIS;
}
// 系统初始化
void InitSystem(void)
{
EALLOW;
SysCtrlRegs.WDCR= 0x00AF; // 配置看门狗
// 0x00E8 禁止看门狗,预定标系数Prescaler = 1
// 0x00AF 使能看门狗,预定标系数Prescaler = 64
SysCtrlRegs.SCSR = 0; // 看门狗产生RESET
SysCtrlRegs.PLLCR.bit.DIV = 10; // 设置系统锁相环倍频系数5
SysCtrlRegs.HISPCP.all = 0x1; // 配置高速外设时钟预定标系数:除以2
SysCtrlRegs.LOSPCP.all = 0x2; // 配置低速外设时钟预定标系数:除以4
// 使能本应用程序使用的外设时钟
SysCtrlRegs.PCLKCR.bit.EVAENCLK=1;
SysCtrlRegs.PCLKCR.bit.EVBENCLK=0;
SysCtrlRegs.PCLKCR.bit.SCIAENCLK=0;
SysCtrlRegs.PCLKCR.bit.SCIBENCLK=0;
SysCtrlRegs.PCLKCR.bit.MCBSPENCLK=0;
SysCtrlRegs.PCLKCR.bit.SPIENCLK=0;
SysCtrlRegs.PCLKCR.bit.ECANENCLK=0;
SysCtrlRegs.PCLKCR.bit.ADCENCLK=0;
EDIS;
}
void SCI_Init(void)
{
SciaRegs.SCICCR.all =0x0007; // 1bit 停止位 无循环模式
// 无极性, 字符长度:8 bits,
// 异步模式, 空闲线协议
SciaRegs.SCICTL1.all =0x0003; // 使能 TX, RX, 内部 SCICLK,
// 禁止 RX ERR, SLEEP, TXWAKE
SciaRegs.SCIHBAUD = 487 >> 8 ; // 波特率:9600(LSPCLK = 37.5MHz) ;
SciaRegs.SCILBAUD = 487 & 0x00FF;
SciaRegs.SCICTL2.bit.RXBKINTENA = 1; // 使能SCI接收中断
SciaRegs.SCIFFTX.all = 0xE060; // bit 15 = 1 : 退出复位
// bit 14 = 1 : 使能FIFO增强模式
// bit 13 = 1 : 使能 TX FIFO操作
// bit 6 = 1 : CLR TXFFINT-标志
// bit 5 = 1 : 使能TX FIFO匹配
// bit 4-0 : 如果TX FIFO等于0, TX-ISR中断
SciaRegs.SCIFFRX.all = 0xE065; // Rx 中断级设置为5
SciaRegs.SCICTL1.all =0x0023; // 使SCI退出复位
}
// Timer1中断服务程序
//
interrupt void T1_Compare_isr(void)
{
unsigned char index;
unsigned char p2 = 0;
unsigned char p3 = 0;
// 检测步进速度改变标志
if( change_rate_flag )
{
EvaRegs.T1CMPR = rate;
change_rate_flag = 0;
}
//
// 检查LED D1状态
//
if(GpioDataRegs.GPADAT. GPIOA4 & 1 )
{
GpioDataRegs.GPADAT. GPIOA4 =1;
}
// 检查LED D2状态
//
if(GpioDataRegs.GPBDAT. GPIOA4 & 1 )
{
GpioDataRegs.GPBDAT. GPIOA4 =1;
}
// 检查当前状态
//
switch( (state & 0x3) )
{
case 0x00: // 全步,逆时针
index = stepIndex & 0x03;
p2 |= fullStepA[index];
p3 |= fullStepB[index];
GpioDataRegs.GPADAT. GPIOA2 = p2;
GpioDataRegs.GPADAT. GPIOA3 = p3;
++stepIndex;
break;
case 0x01: // 全步,顺时针
index = stepIndex & 0x03;
p3 |= fullStepA[index];
p2 |= fullStepB[index];
GpioDataRegs.GPADAT. GPIOA3 = p3;
GpioDataRegs.GPADAT. GPIOA2 = p2;
++stepIndex;
break;
case 0x02: // 半步,逆时针
index = stepIndex & 0x07;
p2 |= HalfStepA[index];
p3 |= CcwHalfStepB[index];
GpioDataRegs.GPADAT. GPIOA2 = p2;
GpioDataRegs.GPADAT. GPIOA3 = p3;
++stepIndex;
break;
case 0x03: // 半步,顺时针
index = stepIndex & 0x07;
p3 |= CwHalfStepB[index];
p2 |= HalfStepA[index];
GpioDataRegs.GPADAT. GPIOA3 = p3;
GpioDataRegs.GPADAT. GPIOA2 = p2;
++stepIndex;
break;
default:
_never_executed();
break;
};
// 如果处于单步运行,禁止Timer 0中断
if( state & MOTION_MASK )
{
EvaRegs.T1CON.bit.TENABLE = 1; // 使能 GP Timer 1
}
}
// 串口接收中断程序
//
interrupt void SCI_RX_isr(void)
{
int i;
UTXIFG0= SciaRegs.SCIRXBUF.all;
SciaRegs.SCIFFRX.bit.RXFIFORESET = 0; // 复位 FIFO指针
SciaRegs.SCIFFRX.bit.RXFIFORESET = 1; // 使能操作
SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1; // 清除FIFO INT中断标志
PieCtrlRegs.PIEACK.all = 0x0100; // 响应中断
switch(U0RXBUF)
{
case 'D': // 方向(顺时针或逆时针)
case 'd':
toggle_direction();
break;
case 'C': // 运动(连续或单步)
case 'c':
toggle_motion();
break;
case 'M': // 步进模式(全步或半步)
case 'm':
toggle_stepping_mode();
break;
case 'F': // 提高速度
case 'f':
increase_stepping_rate();
break;
case 'S': // 降低速度
case 's':
decrease_stepping_rate();
break;
default:
break;
};
}
// 提高步进速度
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;
}
}
// 复位定时器1比较中断标志
EvaRegs.EVAIFRA.bit.T1CINT = 1;
// 响应该中断并允许从组2中接收更多的中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
}
// 降低步进速度
void decrease_stepping_rate(void)
{
// 检查是否工作在连续模式
if( (state & MOTION_MASK) == 0 )
{
if( rate <= (min_rate >> 1) )
{
rate <<= 1;
change_rate_flag = 1;
}
}
// 复位定时器1比较中断标志
EvaRegs.EVAIFRA.bit.T1CINT = 1;
// 响应该中断并允许从组2中接收更多的中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
}
// 全步或半步模式切换
//
void toggle_stepping_mode(void)
{
// 切换步进模式状态
state ^= STEP_MASK;
// 检查是否工作在半步模式
if( state & STEP_MASK )
{
// 从全步模式切换到半步模式
// 改变定时器1中断周期为原2倍
rate = (rate >> 1);
change_rate_flag = 1;
max_rate = (MAX_RATE >> 1);
min_rate = (MIN_RATE >> 1);
// Turn on LED D2
P3OUT |= 0x08;
}
else // 全步模式
{
// 从半步模式切换到全步模式
// 改变定时器1中断周期为原1/2倍
rate = (rate << 1);
change_rate_flag = 1;
max_rate = MAX_RATE;
min_rate = MIN_RATE;
// 熄灭LED D2
GpioDataRegs.GPBDAT. GPIOA4 = 0;
}
}
// 连续模式和单步模式转换
void toggle_motion(void)
{
state ^= MOTION_MASK;
// 检查是否工作在连续工作状态
if( (state & MOTION_MASK) == 0 )
{
// 复位定时器1比较中断标志
EvaRegs.EVAIFRA.bit.T1CINT = 1;
// 响应该中断并允许从组2中接收更多的中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP2;
// 熄灭LED D1
GpioDataRegs.GPADAT. GPIOA4 = 0;
}
else
{
// 点亮 LED D1
GpioDataRegs.GPADAT. GPIOA4 = 1;
}
}
// 方向转换
void toggle_direction(void)
{
state ^= DIR_MASK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -