main.c
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "oled.h"
#include "key.h"
#include "EXTI.h"
#include "timer.h"
#include "pwm.h"
#include "dcmotor.h"
#include "linesensor.h"
#include "stepmotor.h"
extern u32 Toggle_Pulse[4];
//直线运动插补测试
void line_test1();
void line_test2();
void cir_test2();
//全局变量,存储按键键码
u8 GLOKEYVAL=0;
u8 pwmflag=0;
u8 pwmaddsubflag=0;
int main(void)
{
int shuzi=987;
u8 keyval=0;
float aa=123.456;
float vvtemp=0.2;
delay_init(168);
LED_Init();
OLED_Init();
//TIMER14_CH1_PWM1_Init(500-1,84-1);//初始化 2khz F9
uart_init(115200);
KEY_Init();//按键初始化
// TIMER13_Init(200-1,8400-1);//定时器定时扫描,读取按键状态
//定时器时钟 84M,分频系数 8400,所以 84M/8400=10Khz ===0.1MS
//的计数频率,计数 5000 次为 500ms
// TIM1_PWM_Init(500-1,84-1);//1US*500=500US====实际250us 300/500=0.6
delay_ms(30);
OLED_Clear();
//LineSensor_Init();
//TIM1_PWM_Init(600-1,84-1);
// DCMotor1Init();
// DCMotor2Init();
// DCMotor3Init();
// DCMotor4Init();
//TIM_Cmd(TIM13,ENABLE);//按键定时器,定时扫描20ms扫描一次。
// TIM_Cmd(TIM14, DISABLE);
//
// Toggle_Pulse[0]=100;
// Toggle_Pulse[1]=1000;
stepmotor1234_gpio_Init();
stepmotor1234_timer8_Init(65535,168-1);//
//168分频,168MHz/168=1Mhz,1us计算一次,那么计算Toggle_Pulse[0]=100次,100*1us=100us
//反转一次电平。那么得到周期是100+100=200us
printf("逐点比较法\r\n");
delay_ms(10);
while(1)
{
// line_test1();
//line_test2();
cir_test2();
}
}
//直线运动测试
void line_test1()//单轴前进后退
{
u8 keyval=0;
task_num=LineMove_TaskMode;//LineMove_TaskMode
keyval=KEY_Scan();
//主程序如果利用这个函数,需要关闭定时器13,不然会不断进入中断,冲突
if(keyval==20)
{
printf("k2(x,y)\r\n");
Linear_move_pul(0*3200,2*3200,500);//3200
}
if(keyval==30)
{
printf("k3(x,y)\r\n");
Linear_move_pul(0*3200,-2*3200,500);
}
if(keyval==40)
{
printf("k4(x,y)\r\n");
//Linear_move(10*10,0,500);
Linear_move_pul(3*3200,0*3200,500);
}
if(keyval==50)
{
printf("k5(x,y)\r\n");
//Linear_move(-10*10,0,1000);
Linear_move_pul(-3*3200,0*3200,500);//th=1ms,tl=1ms,f=500hz,nfall=100pulse
}
}
//直线运动测试
void line_test2()//直线插补
{
u8 keyval=0;
task_num=LineMove_TaskMode;//LineMove_TaskMode
keyval=KEY_Scan();
if(keyval==20)
{
printf("k2(x,y)\r\n");
Linear_move_pul(3*3200,2*3200,150);//3200
}
if(keyval==30)
{
printf("k3(x,y)\r\n");
Linear_move_pul(-3*3200,-2*3200,150);
}
if(keyval==40)
{
printf("k4(x,y)\r\n");
//Linear_move(10*10,0,500);
Linear_move_pul(-3*3200,2*3200,150);
}
if(keyval==50)
{
printf("k5(x,y)\r\n");
//Linear_move(-10*10,0,1000);
Linear_move_pul(3*3200,-2*3200,150);//th=1ms,tl=1ms,f=500hz,nfall=100pulse
}
}
//利用打印串口显示数据,验证
void cir_test1()
{
printf("oooooooooooooooooooooooo\r\n");
printf("第一象限,逆圆\r\n");
Circle_Interpolation(10,0,7,7,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("=========================================\r\n");
printf("第2象限,逆圆\r\n");
Circle_Interpolation(0,10,-7,7,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("=========================================\r\n");
printf("第3象限,逆圆\r\n");
Circle_Interpolation(-10,0,-7,-7,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("=========================================\r\n");
printf("第4象限,逆圆\r\n");
Circle_Interpolation(0,-10,7,-7,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("=========================================))))))\r\n");
printf("第1象限,顺圆\r\n");
Circle_Interpolation(0,10,7,7,500,CW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("第2象限,顺圆\r\n");
Circle_Interpolation(-10,0,-7,7,500,CW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("第3象限,顺圆\r\n");
Circle_Interpolation(0,-10,-7,-7,500,CW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("第4象限,顺圆\r\n");
Circle_Interpolation(10,0,7,-7,500,CW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
printf("=========================================\r\n");
printf("=========================================\r\n");
printf("=========================================\r\n");
printf("四分之一圆弧--------------\r\n");
printf("第一象限,逆圆\r\n");
Circle_Interpolation(10,0,0,10,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
printf("=========================================\r\n");
printf("第2象限,逆圆\r\n");
Circle_Interpolation(0,10,-10,0,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
printf("=========================================\r\n");
printf("第3象限,逆圆\r\n");
Circle_Interpolation(-10,0,0,-10,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
printf("=========================================\r\n");
printf("第4象限,逆圆\r\n");
Circle_Interpolation(0,-10,10,0,500,CCW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(2000);
// printf("----整--------------\r\n");
// printf("第一象限,逆圆\r\n");
// Circle_Interpolation(10,0,10,0,500,CCW);//不成功,说明这个函数只能最多是四分之一圆弧插补
// while(circular_para.motionstatus==1);
// printf("=========================================\r\n");
printf("oooooooooooooooooooooooo\r\n");
delay_ms(2000);
}
//**********************************************************************
//3200一圈,8mm导程
void cir_test2()
{
u8 keyval=0;
task_num=CircleMove_TaskMode;//LineMove_TaskMode
keyval=KEY_Scan();
if(keyval==20)
{
printf("k20四分之一圆弧--------------\r\n");
printf("第一象限,圆\r\n");
Circle_Interpolation(4*3200,0,0,-4*3200,100,CW);//8分之一圆
while(circular_para.motionstatus==1);
Circle_Interpolation(0,-4*3200,-4*3200,0,100,CW);//8分之一圆
while(circular_para.motionstatus==1);
delay_ms(1000);
Circle_Interpolation(-4*3200,0,0,4*3200,100,CW);//8分之一圆
while(circular_para.motionstatus==1);
Circle_Interpolation(0,4*3200,4*3200,0,100,CW);//8分之一圆
while(circular_para.motionstatus==1);
// printf("=========================================\r\n");
// printf("第2象限,逆圆\r\n");
// Circle_Interpolation(0,2*3200,-2*3200,0,100,CCW);//8分之一圆
// while(circular_para.motionstatus==1);
//
// printf("=========================================\r\n");
// printf("第3象限,逆圆\r\n");
// Circle_Interpolation(-2*3200,0,0,-2*3200,100,CCW);//8分之一圆
// while(circular_para.motionstatus==1);
// printf("=========================================\r\n");
// printf("第4象限,逆圆\r\n");
// Circle_Interpolation(0,-2*3200,2*3200,0,100,CCW);//8分之一圆
// while(circular_para.motionstatus==1);
}
if(keyval==30)
{
printf("k30四分之一圆弧--------------\r\n");
printf("第一象限,圆\r\n");
Circle_Interpolation(0,-4*3200,4*3200,0,100,CCW);//8分之一圆
//Circle_Interpolation(0,1*16,1*16,0,200,CW);//4分之一圆 8---143
while(circular_para.motionstatus==1);
// printf("=========================================\r\n");
// printf("第2象限,圆\r\n");
// Circle_Interpolation(2*3200,0,0,-2*3200,200,CW);//4分之一圆
// while(circular_para.motionstatus==1);
//
// printf("=========================================\r\n");
// printf("第3象限,圆\r\n");
// Circle_Interpolation(0,-2*3200,-2*3200,0,200,CW);//4分之一圆
// while(circular_para.motionstatus==1);
// printf("=========================================\r\n");
// printf("第4象限,圆\r\n");
// Circle_Interpolation(-2*3200,0,0,2*3200,200,CW);//4分之一圆
// while(circular_para.motionstatus==1);
}
}
step.c
#include "stepmotor.h"
//翻转点,决定速度
u32 Toggle_Pulse[4]={900,500,500,500};
int32_t xend=0;//x终点坐标
int32_t yend=0;//x终点坐标
u32 steptotalnum=0;//总步长
int32_t fi=0;//偏差
u8 moveaxisflag=0;//=0,x轴,=1,y轴
u8 movingstatus=0;//运动标记位,=0停止,=1正在运动
u16 xspeed;
u16 yspeed;
Axis_TypeDef axis;
Quadrant_TypeDef quadrant;
Circle_Interpolation_TypeDef circular_para={0};
TaskMode_TypeDef task_num;
void stepmotor1234_gpio_Init(void)//初始化
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
//xdir
STEPMOTOR1_DIR_CLK_ENA(); //初始化KEY时钟
GPIO_InitStructure.GPIO_Pin = STEPMOTOR1_DIR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(STEPMOTOR1_DIR_PORT, &GPIO_InitStructure);
//xena
STEPMOTOR1_ENA_CLK_ENA(); //初始化KEY时钟
GPIO_InitStructure.GPIO_Pin = STEPMOTOR1_ENA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
GPIO_Init(STEPMOTOR1_ENA_PORT, &GPIO_InitStructure);
//ydir
STEPMOTOR2_DIR_CLK_ENA(); //初始化KEY时钟
GPIO_InitStructure.GPIO_Pin = STEPMOTOR2_DIR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(STEPMOTOR2_DIR_PORT, &GPIO_InitStructure);
//yena
STEPMOTOR2_ENA_CLK_ENA(); //初始化KEY时钟
GPIO_InitStructure.GPIO_Pin = STEPMOTOR2_ENA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(STEPMOTOR2_ENA_PORT, &GPIO_InitStructure);
}
//(1) TIM_OCMode:比较输出模式选择,总共有八种,常用的为PWM1/PWM2。它设定CCMRx寄存器OCxM[2:0]位的值。
//(2) TIM_OutputState:比较输出使能,决定最终的输出比较信号OCx是否通过外部引脚输出。它设定TIMx_CCER寄存器CCxE/CCxNE位的值。
//(3) TIM_OutputNState:比较互补输出使能,决定OCx的互补信号OCxN是否通过外部引脚输出。它设定CCER寄存器CCxNE位的值。
//(4) TIM_Pulse:比较输出脉冲宽度,实际设定比较寄存器CCR的值,决定脉冲宽度。可设置范围为0至65535。
//(5) TIM_OCPolarity:比较输出极性,可选OCx为高电平有效或低电平有效。它决定着定时器通道有效电平。它设定CCER寄存器的CCxP位的值。
//(6) TIM_OCNPolarity:比较互补输出极性,可选OCxN为高电平有效或低电平有效。它设定TIMx_CCER寄存器的CCxNP位的值。
//(7) TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出1或输出0,即在空闲状态(BDTR_MOE位为0)时,经过死区时间后定时器通道输出高电平或低电平。它设定CR2寄存器的OISx位的值。
//(8) TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出1或输出0,即在空闲状态(BDTR_MOE位为0)时,经过死区时间后定时器互补通道输出高电平或低电平,
//设定值必须与TIM_OCIdleState相反。它设定是CR2寄存器的OISxN位的
void stepmotor1234_timer8_Init(u32 arr,u32 psc)//初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM1时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTA时钟
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8); //GPIOA8复用为定时器1
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOA8复用为定时器1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7; //GPIOA8--
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_PuPd_DOWN; //下拉
GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化PA8
//-------------------
//选择定时器模式
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频0
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 65535最大值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // ((uint16_t)0x0000)
TIM_TimeBaseStructure.TIM_RepetitionCounter=0; //20201020
TIM_TimeBaseInit(TIM8,&TIM_TimeBaseStructure);//初始化定时器8
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
//输出极性:TIM输出比较极性低TIM_OCPolarity_High
TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity= TIM_OCNPolarity_Low;
// TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出1或输出0
TIM_OCInitStructure.TIM_OCIdleState= TIM_OCIdleState_Reset ;// ((uint16_t)0x0000)
TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Set;//((uint16_t)0x0000)
TIM_OCInitStructure.TIM_Pulse =Toggle_Pulse[0];
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//
TIM_OC1Init(TIM8, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 4OC1
TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);
//禁止使能TIM1在CCR1上的预装载寄存器
TIM_OC1FastConfig(TIM8, TIM_OCFast_Disable);
TIM_OCInitStructure.TIM_Pulse=Toggle_Pulse[1];
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//
TIM_OC2Init(TIM8, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 4OC1
TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable); //使能TIM1在CCR1上的预装载寄存器
//
// 不对定时器做任何分频,并且让它满计数,即计数周期为65535。接下去再设置个
// 通道的的工作模式为输出比较翻转模式,设置通道1的比较值为CCR1_Val、CCR3_Val、CCR3_Val、CCR4_Val,
// 它们的值在OCToggle.h中定义。然后打开个通道的输出比较事件的中断。最后在打开定时器。这样的话,
// 定时器这段就配置完成了。
//主函数NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn; //TIM8中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级1级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级1级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_ARRPreloadConfig(TIM8,DISABLE);//ARPE使能
TIM_ClearITPendingBit(TIM8, TIM_IT_CC1);//清除标志位TIM_IT_CC1
TIM_ClearITPendingBit(TIM8, TIM_IT_CC2);//清除标志位TIM_IT_CC1
//中断标志
//打开定时器8,先不打开,后面需要的时候再打开,ENABLE
TIM_Cmd(TIM8, DISABLE);
TIM_CtrlPWMOutputs(TIM8, DISABLE); //ENABLE,这个语句智能关闭pwm输出,但是还是能够产生中断
TIM_ITConfig(TIM8, TIM_IT_CC1 | TIM_IT_CC2 , DISABLE);
movingstatus=0;
}
//以当前为原点,移动到终点坐标xendtemp,yendtemp,相对移动
void Interpolation_move_pul(u32 xendtemp,u32 yendtemp,u16 speedtemp)
{
//一开始,偏差=0
fi=0;
//设置终点坐标
xend=xendtemp;
yend=yendtemp;
//总步长
steptotalnum=(xendtemp+yendtemp)*2;
printf("steptotalnum=%d\r\n",steptotalnum);
moveaxisflag=0;//一开始是x轴运动=0是x轴,=1是y轴;
//第一步的偏差计算
// fi = fi - yendtemp;
//设置速度
TIM_SetCompare1(TIM8, speedtemp);//式1
TIM_SetCompare2(TIM8, speedtemp);//式2
TIM_SetAutoreload(TIM8, speedtemp);//式3
TIM_ARRPreloadConfig(TIM8, ENABLE);//式4,
TIM_ITConfig(TIM8, TIM_IT_CC1 | TIM_IT_CC2 , ENABLE);
TIM_Cmd(TIM8, ENABLE);//打开定时器8,
TIM_CtrlPWMOutputs(TIM8, ENABLE); //关闭所有
TIM_CCxCmd(TIM8,TIM_Channel_1, ENABLE);//开启x轴
TIM_CCxCmd(TIM8,TIM_Channel_2, DISABLE);
movingstatus=1;
}
void Linear_move_pul(int32_t xendtemp,int32_t yendtemp,u16 speedtemp)
{
//判断当前是否在插补运动
if(movingstatus!=0)//如果正在运动,那么就退出,刚进来需要在停止状态
return;
//判断坐标正负,决定第几象限,然后决定每个轴的运动方向;
//第二第四象限
if(xendtemp<0)//
{
STEPMOTOR1_DIR=CCW;//远离电机
xendtemp= -xendtemp;
printf("xdir=ccw----ccw\r\n");
}
else
{
STEPMOTOR1_DIR=CW;
printf("xdir=cw----cw\r\n");
}
//第二第四象限
if(yendtemp<0)//
{
STEPMOTOR2_DIR=CCW;
printf("ydir=ccw----ccw\r\n");
yendtemp= -yendtemp;
}
else
{
printf("ydir=cw------cw\r\n");
STEPMOTOR2_DIR=CW;
}
printf("xendtemp=%d, yendtemp=%d。\r\n",xendtemp,yendtemp);
xspeed=speedtemp;
yspeed=speedtemp;
printf("xs=%d, ys=%d。\r\n",xspeed,yspeed);
Interpolation_move_pul(xendtemp,yendtemp, speedtemp);
}
void TIM8_CC_IRQHandler(void)
{
static int xi=0,yi=0;
u8 last_axis=0;
static u8 ii=0;
static u8 calflag=0;
u16 counttemp;
static u8 tt=0;
switch(task_num)
{
case Home_TaskMode:
break;
case SingleAxisMoveLine_TaskMode:
break;
case SingleAxisMoveJog_TaskMode:
break;
case LineMove_TaskMode:
{
last_axis = moveaxisflag;//记录上一次进给的活动轴
if(TIM_GetFlagStatus(TIM8,TIM_FLAG_CC1)!=RESET)
{
TIM_ClearFlag(TIM8, TIM_FLAG_CC1);
ii=ii+1;
if(ii>=2)
{
//完整一个脉冲,两次反转
calflag=1;
ii=0;
}
}
if(TIM_GetFlagStatus(TIM8,TIM_FLAG_CC2)!=RESET)
{
TIM_ClearFlag(TIM8, TIM_FLAG_CC2);
ii=ii+1;
if(ii>=2)
{
//完整一个脉冲,两次反转,一个脉冲,进行一次fi
calflag=1;
ii=0;
}
}
if(calflag==1)
{
//根据上一步偏差,判断进给方向,计算下一步偏差
if(fi<0)//偏差xiao于0,在直线下方,进给y轴,计算偏差
{
moveaxisflag=1;
fi=fi+xend;
// if(STEPMOTOR2_DIR==CW)
// {yi=yi+1;}
// else
// yi=yi-1;
// xi=xi;
// printf("y轴运动,第%d步。fi=%d,xi=%d, yi=%d\r\n",steptotalnum,fi,xi,yi);
}
else //偏差大于0,在直线上方,进给x轴,计算偏差
{
moveaxisflag=0;
fi=fi-yend;
// if(STEPMOTOR1_DIR==CW)
// xi=xi+1;
// else
// xi=xi-1;
//
// yi=yi;
// printf("x轴运动,第%d步。fi=%d,xi=%d, yi=%d\r\n",steptotalnum,fi,xi,yi);
}
//下一步活动轴和上一步不一致,需要更换运动轴
//如果运动轴是x轴,上一次轴是y轴,不一致,更换成x轴
if(moveaxisflag==0)
{
TIM_CCxCmd(TIM8,TIM_Channel_1, ENABLE);//x轴开启
TIM_CCxCmd(TIM8,TIM_Channel_2, DISABLE);//y轴关闭
}
//上一个轴关闭
//如果运动轴是y轴,上一次轴是x轴,不一致,更换成y轴
else if(moveaxisflag==1)
{
TIM_CCxCmd(TIM8,TIM_Channel_1, DISABLE);//x轴关闭
TIM_CCxCmd(TIM8,TIM_Channel_2, ENABLE);//y轴开启
}
//进给步数-1
steptotalnum=steptotalnum-1;
//判断是否完成插补,完成之后,x/y都关闭
if(steptotalnum==1)
{
TIM_CCxCmd(TIM8,TIM_Channel_1, DISABLE);//x轴关闭
TIM_CCxCmd(TIM8,TIM_Channel_2, DISABLE);//y轴
movingstatus=0;
printf("***************结束运动************\r\n");
//中断
TIM_ITConfig(TIM8, TIM_IT_CC1 , DISABLE);
TIM_ITConfig(TIM8, TIM_IT_CC2 , DISABLE);
//关闭
TIM_CtrlPWMOutputs(TIM8, DISABLE); //关闭所有pwm
TIM_Cmd(TIM8, DISABLE);//打开定时器8,先不打开,后面需要的时候再打开,ENABLE
// xi=0;
// yi=0;
}
calflag=0;
}
}
break;
//********圆弧插补******************圆弧插补*********************圆弧插补*********************圆弧插补
case CircleMove_TaskMode:
{
//记录上一次的运动轴
last_axis=circular_para.active_axis;
//
// TIM_ITConfig(TIM8, TIM_IT_CC1 , DISABLE);
// TIM_ITConfig(TIM8, TIM_IT_CC2 , DISABLE);
if(TIM_GetFlagStatus(TIM8,TIM_FLAG_CC1)!=RESET)
{
TIM_ClearFlag(TIM8, TIM_FLAG_CC1);
ii=ii+1;
if(ii==2)
{
//完整一个脉冲,两次反转
calflag=1;
ii=0;
}
}
if(TIM_GetFlagStatus(TIM8,TIM_FLAG_CC2)!=RESET)
{
TIM_ClearFlag(TIM8, TIM_FLAG_CC2);
ii=ii+1;
if(ii==2)
{
//完整一个脉冲,两次反转,一个脉冲,进行一次fi
calflag=1;
ii=0;
}
}
if(calflag==1)
{
//根据进给方向刷新坐标
switch(last_axis)
{
case x_axis:
switch(circular_para.dir_x)
{
case CCW:
circular_para.startpoint_x--;
// xi=circular_para.startpoint_x;
// printf("第i=%d, xi= %d,yi= %d\r\n",circular_para.endpoint_pulse,xi,yi);
break;
case CW:
circular_para.startpoint_x++;
// xi=circular_para.startpoint_x;
//printf("第i=%d, xi= %d,yi= %d\r\n",circular_para.endpoint_pulse,xi,yi);
break;
}
break;
case y_axis:
switch(circular_para.dir_y)
{
case CCW:
circular_para.startpoint_y--;
// yi= circular_para.startpoint_y;
// printf("第i=%d, xi= %d,yi= %d\r\n",circular_para.endpoint_pulse,xi,yi);
break;
case CW:
circular_para.startpoint_y++;
// yi= circular_para.startpoint_y;
// printf("第i=%d, xi= %d,yi= %d\r\n",circular_para.endpoint_pulse,xi,yi);
break;
}
break;
}
//根据上一次的偏差,判断新的进给活动轴
if(circular_para.deviation >=0)
{
switch(circular_para.dir_interpo)
{
case CW://顺时针
switch(circular_para.crood_pos)
{
case quadrant_1st:circular_para.active_axis=y_axis;break;
case quadrant_3rd:
circular_para.active_axis=y_axis;
break;
case quadrant_2nd:circular_para.active_axis=x_axis;break;
case quadrant_4th:
circular_para.active_axis=x_axis;
break;
}
break;
case CCW:
{
switch(circular_para.crood_pos)
{
case quadrant_1st:
circular_para.active_axis=x_axis;
break;
case quadrant_3rd:
circular_para.active_axis=x_axis;
break;
case quadrant_2nd:
circular_para.active_axis=y_axis;
break;
case quadrant_4th:
circular_para.active_axis=y_axis;
break;
}
}
break;
}
}
//偏差小于0,向圆外进给
else
{
switch(circular_para.dir_interpo)
{
case CW://顺时针
switch(circular_para.crood_pos)
{
case quadrant_1st: circular_para.active_axis=x_axis;break;
case quadrant_3rd:
circular_para.active_axis=x_axis;
break;
case quadrant_2nd: circular_para.active_axis=y_axis;break;
case quadrant_4th:
circular_para.active_axis=y_axis;
break;
}
break;
case CCW:
{
switch(circular_para.crood_pos)
{
case quadrant_1st: circular_para.active_axis=y_axis;break;
case quadrant_3rd:
circular_para.active_axis=y_axis;
break;
case quadrant_2nd: circular_para.active_axis=x_axis;break;
case quadrant_4th:
circular_para.active_axis=x_axis;
break;
}
}
break;
}
}
//根据插补运动方向和进给方向计算新的偏差
if(circular_para.active_axis== x_axis)
circular_para.deviation += 2*circular_para.devi_sign[x_axis]
*circular_para.startpoint_x+1;
else if(circular_para.active_axis== y_axis)
circular_para.deviation += 2*circular_para.devi_sign[y_axis]
*circular_para.startpoint_y+1;
// printf("fi = %d\r\n",circular_para.deviation);
// //如果下一个活动轴与上一步的不一致,需要更换轴
if(last_axis != circular_para.active_axis)
{
//关闭上一个轴,开启新的轴
if(last_axis == x_axis)
{
TIM_CCxCmd(TIM8,TIM_Channel_1, DISABLE);//x轴关闭
TIM_CCxCmd(TIM8,TIM_Channel_2, ENABLE);//y轴开启
STEPMOTOR1_ENA=DISENA;
STEPMOTOR2_ENA=ENA;
}
else
{
TIM_CCxCmd(TIM8,TIM_Channel_1, ENABLE); //x轴开启
TIM_CCxCmd(TIM8,TIM_Channel_2, DISABLE);//y轴关闭
STEPMOTOR1_ENA=ENA;
STEPMOTOR2_ENA=DISENA;
}
}
//进给步数减1
// printf("N=%d\r\n",circular_para.endpoint_pulse);
circular_para.endpoint_pulse --;
// printf("N-1=%d\r\n",circular_para.endpoint_pulse);
//判断是否完成插补
if(circular_para.endpoint_pulse==0)
{
//中断
TIM_ITConfig(TIM8, TIM_IT_CC1 , DISABLE);
TIM_ITConfig(TIM8, TIM_IT_CC2 , DISABLE);
TIM_CCxCmd(TIM8,TIM_Channel_1, DISABLE);//x轴关闭
TIM_CCxCmd(TIM8,TIM_Channel_2, DISABLE);//y轴
//关闭
TIM_CtrlPWMOutputs(TIM8, DISABLE); //关闭所有pwm
TIM_Cmd(TIM8, DISABLE);//打开定时器8,先不打开,后面需要的时候再打开,ENABLE
// xi=0;
// yi=0;
circular_para.motionstatus=0;
// tt=0;
// printf("***************结束运动************\r\n");
// printf("***************结束运动************\r\n");
// printf("***************结束运动************\r\n");
}
calflag=0;
// TIM_ITConfig(TIM8, TIM_IT_CC1 , ENABLE);
// TIM_ITConfig(TIM8, TIM_IT_CC2 , ENABLE);
}//,一个完整脉冲,圆弧插补
break;
}
}
}
/*
----------------------------------------以下是圆弧插补函数
*/
static void CirCle_Set_Feed_Dir(int32_t coord_x, int32_t coord_y, u8 dirtemp)
{
//记录插补运动方向
circular_para.dir_interpo=dirtemp;
if(dirtemp == CW)
{
if(coord_x >0)//x轴正半轴
{
if(coord_y>0)//第一象限,x变大,y变小
{
circular_para.crood_pos =quadrant_1st;
circular_para.dir_x=CW;
circular_para.dir_y=CCW;
circular_para.devi_sign[x_axis]=1;
circular_para.devi_sign[y_axis]=-1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CW;
STEPMOTOR2_DIR=CCW;
printf("顺时针cw,,第1象限\r\n");
}
else //第四象限运动,x变小,y变小
{
circular_para.crood_pos =quadrant_4th;
circular_para.dir_x=CCW;
circular_para.dir_y=CCW;
circular_para.devi_sign[x_axis]=-1;
circular_para.devi_sign[y_axis]=-1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CCW;
STEPMOTOR2_DIR=CCW;
printf("顺时针cw,,第4象限\r\n");
}
}
else if(coord_x <0) //x轴负半轴
{
if(coord_y>=0)//第2象限
{
circular_para.crood_pos =quadrant_2nd;
circular_para.dir_x=CW;
circular_para.dir_y=CW;
circular_para.devi_sign[x_axis]=1;
circular_para.devi_sign[y_axis]=1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CW;
STEPMOTOR2_DIR=CW;
printf("顺时针cw,,第二象限\r\n");
}
else //第3象限运动
{
circular_para.crood_pos =quadrant_3rd;
circular_para.dir_x=CCW;
circular_para.dir_y=CW;
circular_para.devi_sign[x_axis]=-1;
circular_para.devi_sign[y_axis]= 1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CCW;
STEPMOTOR2_DIR=CW;
printf("顺时针cw,,第3象限\r\n");
}
}
else if(coord_x==0 )//x=0,当前点在Y轴上
{
if(coord_y >0)//第一象限
{
circular_para.crood_pos =quadrant_1st;
circular_para.dir_x=CW;
circular_para.dir_y=CCW;
circular_para.devi_sign[x_axis]=1;
circular_para.devi_sign[y_axis]= -1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CW;
STEPMOTOR2_DIR=CCW;
printf("顺时针cw,,第1象限 x=0 y>0 \r\n");
}
else if(coord_y<0)//第3象限
{
circular_para.crood_pos =quadrant_3rd;
circular_para.dir_x=CCW;
circular_para.dir_y=CW;
circular_para.devi_sign[x_axis]=-1;
circular_para.devi_sign[y_axis]= 1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CCW;
STEPMOTOR2_DIR=CW;
printf("顺时针cw,,第3象限 x=0 y<0 \r\n");
}
}
}
//if(dirtemp == CCW)
else
{
printf("dir=CCW\r\n");
if(coord_x >0)//x正半轴
{
if(coord_y >=0)//第一象限
{
circular_para.crood_pos =quadrant_1st;
circular_para.dir_x=CCW;
circular_para.dir_y=CW;
circular_para.devi_sign[x_axis]= -1;
circular_para.devi_sign[y_axis]= 1;
printf("start x=%d, y=%d\r\n",circular_para.startpoint_x,circular_para.startpoint_y);
printf("circular_para.devi xsign = %d, dev_ysign=%d\r\n",circular_para.devi_sign[x_axis], circular_para.devi_sign[y_axis]);
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CCW;
STEPMOTOR2_DIR=CW;
}
else//第4象限
{
circular_para.crood_pos =quadrant_4th;
circular_para.dir_x=CW;
circular_para.dir_y=CW;
circular_para.devi_sign[x_axis]= 1;
circular_para.devi_sign[y_axis]= 1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CW;
STEPMOTOR2_DIR=CW;
}
}
else if(coord_x <0)//x负半轴
{
if(coord_y >0)//第2象限
{
circular_para.crood_pos =quadrant_2nd;
circular_para.dir_x=CCW;
circular_para.dir_y=CCW;
circular_para.devi_sign[x_axis]= -1;
circular_para.devi_sign[y_axis]= -1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CCW;
STEPMOTOR2_DIR=CCW;
}
else//第3象限
{
circular_para.crood_pos =quadrant_3rd;
circular_para.dir_x=CW;
circular_para.dir_y=CCW;
circular_para.devi_sign[x_axis]=1;
circular_para.devi_sign[y_axis]= -1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CW;
STEPMOTOR2_DIR=CCW;
}
}
else if(coord_x ==0)//x=0,在y轴上面
{
if(coord_y >0)//第2象限
{
circular_para.crood_pos =quadrant_2nd;
circular_para.dir_x=CCW;
circular_para.dir_y=CCW;
circular_para.devi_sign[x_axis]=-1;
circular_para.devi_sign[y_axis]= -1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CCW;
STEPMOTOR2_DIR=CCW;
}
else if(coord_y <0)//第2象限
{
circular_para.crood_pos =quadrant_4th;
circular_para.dir_x=CW;
circular_para.dir_y=CW;
circular_para.devi_sign[x_axis]=1;
circular_para.devi_sign[y_axis]=1;
//x轴方向设置成CW,y轴CCW
STEPMOTOR1_DIR=CW;
STEPMOTOR2_DIR=CW;
}
}
}
}
//任意象限圆弧插补运动,起点x,起点y,终点x,终点y,进给速度,进给方向
void Circle_Interpolation(int32_t start_xtemp,int32_t start_ytemp, int32_t stop_xtemp, int32_t stop_ytemp, int32_t speedtemp, u8 dirtemp)
{
//判断当前是否正在做插补运动
if(circular_para.motionstatus !=0)
{
return;
}
//检查起点坐标和终点左边是不是在一个圆上面,这里不用等于0,因为会有计算误差,电脑计算,截断误差
if((((start_xtemp*start_xtemp)+(start_ytemp*start_ytemp))-((stop_xtemp*stop_xtemp)+(stop_ytemp*stop_ytemp)))>3)
return;
//偏差清零
circular_para.deviation=0;
//起点坐标和终点坐标更新
circular_para.startpoint_x = start_xtemp;
circular_para.startpoint_y = start_ytemp;
printf("第1个打印,sx=%d, sy=%d\r\n", circular_para.startpoint_x, circular_para.startpoint_y);
circular_para.endpoint_x=stop_xtemp;
circular_para.endpoint_y=stop_ytemp;
//所需脉冲数是从起点到终点坐标的脉冲数之和
circular_para.endpoint_pulse=abs(stop_xtemp-start_xtemp)+abs(stop_ytemp-start_ytemp);
printf("第2个打印,circular_para.endpoint_pulse= %d\r\n",circular_para.endpoint_pulse);
//根据坐标确定插补方向和x,y运动方向
CirCle_Set_Feed_Dir(circular_para.startpoint_x,circular_para.startpoint_y,dirtemp);
//起点坐标y=0,说明起点x轴上面,直接向y轴进给,可以减小误差
if(circular_para.startpoint_y==0)
{
//偏差方程,F=F+- 2*y +1
circular_para.active_axis=y_axis;
printf("第3个打印circular_para.active_axis=y_axis yyyyy\r\n");
circular_para.deviation +=2* circular_para.devi_sign[y_axis]
* circular_para.startpoint_y +1;
printf("第4个打印circular_para.deviation000= %d\r\n",circular_para.deviation);
}
else
{
//偏差方程,F=F+- 2*x +1
circular_para.active_axis=x_axis;
printf("第5个打印circular_para.active_axis=x_axis xxxxx\r\n");
circular_para.deviation +=2* circular_para.devi_sign[x_axis]
* circular_para.startpoint_x+1;
printf("第6个打印circular_para.deviation000= %d\r\n",circular_para.deviation);
}
printf("第7个打印,sx=%d, sy=%d\r\n", circular_para.startpoint_x, circular_para.startpoint_y);
//设置速度
//设置速度
//设置速度
TIM_SetCompare1(TIM8, speedtemp);//式1
TIM_SetCompare2(TIM8, speedtemp);//式2
TIM_SetAutoreload(TIM8, speedtemp);//式3
TIM_ARRPreloadConfig(TIM8, ENABLE);//式4,
TIM_ITConfig(TIM8, TIM_IT_CC1 | TIM_IT_CC2 , ENABLE);
TIM_Cmd(TIM8, ENABLE);//打开定时器8,
TIM_CtrlPWMOutputs(TIM8, ENABLE); //关闭所有
if( circular_para.active_axis== x_axis)
{
TIM_CCxCmd(TIM8,TIM_Channel_1, ENABLE);//开启x轴
TIM_CCxCmd(TIM8,TIM_Channel_2, DISABLE);
}
else
{
TIM_CCxCmd(TIM8,TIM_Channel_1, DISABLE);//开启y轴
TIM_CCxCmd(TIM8,TIM_Channel_2, ENABLE);
}
circular_para.motionstatus =1;
}
step.h
#ifndef __STEPMOTOR_H
#define __STEPMOTOR_H
#include "sys.h"
#include "stm32f4xx_tim.h"
#include "usart.h"
//使用定时器8 C6、C7/C8/C9
//端口定义
//xpul====c6
//xdir====g5
//xena====g6
//ypul====c7
//ydir====g7
//yena====g8
#define STEPMOTOR1_DIR PGout(5) // DS0
#define STEPMOTOR1_ENA PGout(6)// DS1
#define STEPMOTOR2_DIR PGout(7) // DS0
#define STEPMOTOR2_ENA PGout(8)// DS1
/*---------------------- 配置宏 ------------------------*/
//===========x电机
#define STEPMOTOR1_DIR_PIN GPIO_Pin_5 // KEY 引脚
#define STEPMOTOR1_DIR_PORT GPIOG // KEY GPIO端口
#define STEPMOTOR1_DIR_CLK RCC_AHB1Periph_GPIOG // KEY GPIO端口时钟
#define STEPMOTOR1_DIR_CLK_ENA() {RCC_AHB1PeriphClockCmd(STEPMOTOR1_DIR_CLK ,ENABLE);}//根据实际修改:时钟线,时钟使能
#define STEPMOTOR1_ENA_PIN GPIO_Pin_6 // KEY 引脚
#define STEPMOTOR1_ENA_PORT GPIOG // KEY GPIO端口
#define STEPMOTOR1_ENA_CLK RCC_AHB1Periph_GPIOG // KEY GPIO端口时钟
#define STEPMOTOR1_ENA_CLK_ENA() {RCC_AHB1PeriphClockCmd( STEPMOTOR1_ENA_CLK ,ENABLE);}//根据实际修改:时钟线,时钟使能
//=========y电机
#define STEPMOTOR2_DIR_PIN GPIO_Pin_7 // KEY 引脚
#define STEPMOTOR2_DIR_PORT GPIOG // KEY GPIO端口
#define STEPMOTOR2_DIR_CLK RCC_AHB1Periph_GPIOG // KEY GPIO端口时钟
#define STEPMOTOR2_DIR_CLK_ENA() {RCC_AHB1PeriphClockCmd( STEPMOTOR2_DIR_CLK ,ENABLE);}//根据实际修改:时钟线,时钟使能
#define STEPMOTOR2_ENA_PIN GPIO_Pin_8 // KEY 引脚
#define STEPMOTOR2_ENA_PORT GPIOG // KEY GPIO端口
#define STEPMOTOR2_ENA_CLK RCC_AHB1Periph_GPIOG // KEY GPIO端口时钟
#define STEPMOTOR2_ENA_CLK_ENA() {RCC_AHB1PeriphClockCmd( STEPMOTOR2_ENA_CLK ,ENABLE);}//根据实际修改:时钟线,时钟使能
//两个电机都是一样
#define CW 0 //正转 靠近电机
#define CCW 1 //反转 远离电机
#define ENA 0 //使能电机
#define DISENA 1 //脱机电机
//细分数
#define xifenx 16
#define xifeny 16
//导程
#define daochengx 4
#define daochengy 4
//电机转一圈,需要的脉冲数,电机步距角=1.8度,16细分下,1.8/16=0.1125度
//360/0.1125=3200个脉冲,一个脉冲,走多少度呢?一个脉冲走0.1125度。
#define kxcirpul 3200
#define kycirpul 3200
//+++++++++速度变量
extern u32 Toggle_Pulse[4];
extern u8 pwmflag;
/*坐标轴枚举*/
typedef enum{
x_axis=0U,
y_axis
}Axis_TypeDef;
/*任务模式*/
typedef enum{
Home_TaskMode=0U,//回0
SingleAxisMoveLine_TaskMode,//单轴连续运动
SingleAxisMoveJog_TaskMode,//单轴点动
LineMove_TaskMode,//直线插补
CircleMove_TaskMode//圆弧插补
}TaskMode_TypeDef;
/*象限枚举*/
typedef enum{
quadrant_1st=0U,
quadrant_2nd,
quadrant_3rd,
quadrant_4th
}Quadrant_TypeDef;
/*圆弧插补参数结构体*/
typedef struct{
int32_t startpoint_x;//起点坐标
int32_t startpoint_y;
int32_t endpoint_x;//终点坐标
int32_t endpoint_y;
uint32_t endpoint_pulse;//到达终点位置需要的脉冲数uint32_t
uint32_t active_axis;//当前运动轴
int32_t deviation;//偏差参数
int8_t devi_sign[2];
u8 motionstatus :1;//插补运动状态
u8 dir_x :1;//x轴运动方向
u8 dir_y :1;
u8 dir_interpo :1;//插补整体运动方向
u8 crood_pos:2;//起点坐标所在的象限
}Circle_Interpolation_TypeDef;
extern Circle_Interpolation_TypeDef circular_para;
extern TaskMode_TypeDef task_num;
void stepmotor1234_gpio_Init(void);//初始化
void stepmotor1234_timer8_Init(u32 arr,u32 psc);//初始化
void SM_MoveHome(u8 motornumtemp, u8 dirtemp);//回0,电机号,电机方向
//回0,这里的0是靠近电机那个传感器,用外部中断
//接线
void SM_MoveMM(u8 motornumtemp, u8 motordirtemp, u8 motorMM);//单轴运动mm
void SM_MoveAngle(u8 motornumtemp, u8 motordirtemp, u8 motorangletemp);//单轴角度
void Interpolation_move_pul(u32 xendtemp,u32 yendtemp,u16 speedtemp);//脉冲数,接C6(pul)G5(dir)//C7(pul)G7(dir)第一象限直线插补
void Linear_move_pul(int32_t xendtemp,int32_t yendtemp,u16 speedtemp);//接C6(pul)G5(dir)//C7(pul)G7(dir)第一二三四直线插补
static void CirCle_Set_Feed_Dir(int32_t coord_x, int32_t coord_y, u8 dirtemp);
void Circle_Interpolation(int32_t start_xtemp,int32_t start_ytemp, int32_t stop_xtemp, int32_t stop_ytemp, int32_t speedtemp, u8 dirtemp);
#endif