XTXB 发表于 2018-11-11 14:39:19

用stc15w和旧光驱移植arduino写字机GRBL之三:Bresenham算法

本帖最后由 XTXB 于 2018-11-12 11:42 编辑

用stc15w4k32s4和旧光驱移植arduino写字机GRBL连载:
用stc15w和旧光驱移植arduino写字机GRBL之一:机架搭建
https://www.amobbs.com/thread-5701202-1-1.html

用stc15w和旧光驱移植arduino写字机GRBL之二:PCB制作
https://www.amobbs.com/thread-5701573-1-1.html

用stc15w和旧光驱移植arduino写字机GRBL之三:Bresenham算法
写了一个测试程序验证Bresenham算法,没有加减速,没有FIFO循环队列,运动时程序就傻等着,先跑起来增加点信心:

GRBL软件框架图:

步进电机驱动用定时器0完成,没有加减速,意外地,4988电机模块的step脉冲竟然用一句代码就搞定了:

/***************************************************
定时器0溢出中断处理函数 步进电机step脉冲产生
***************************************************/
void Insert_ISR_Timer0_Code(void)
{
        if(x_steper_out_flag==1)//如果有x轴输出请求
        {
                x_steper_out_flag=0;//清x轴输出请求标记
                X_STEP_BIT=0;//驱动4988竟然只需极短的低电平脉冲
                if((K3_UP==1)&(K4_DOWN==1))X_STEP_BIT=1;
                        //按键未按下才有Xstep脉冲输出                       
        }
        if(y_steper_out_flag==1) //如果有y轴输出请求
        {               
                y_steper_out_flag=0;//清y轴输出请求标记
                Y_STEP_BIT=0;                       
                if((K1_LEFT==1)&(K2_RIGHT==1))Y_STEP_BIT=1;
                        //按键未按下才有 Ystep脉冲输出       
        }       
                TL0=0x0F; //步进电机以固定速度运行,24M时钟
                TH0=0xA1;
}
//
Bresenham线段插补算法详解,下图是第一象限,其他象限改变步进电机方向即可获得:

C语言实现Bresenham线段插补算法,较DDA算法Bresenham避免了浮点运算:
void plan_buffer_line(u16 x, u16 y){ //(x,y)为当前点的绝对坐标
        static u16 step_event_count=0;//总步数
        static u16 counter_x=0; static u16 counter_y=0; static u16 step_events_completed=0;//循环计数器       
        if(x>=last_x){   //当前点在上一点的右边,(last_x,last_y)为上一点的绝对坐标
                X_DIRECTION_BIT=0;//第一四象限X电机旋转方向
                target_x= (x-last_x);//求相对坐标的绝对值
        }else {//当前点在上一点的左边
                X_DIRECTION_BIT=1;//第二三象限X电机旋转方向
                target_x= (last_x-x);//求相对坐标的绝对值
        }//以上一点为原点的直角坐标系中,判断当前点在哪个象限从而决定xy电机的旋转方向
        if(y>=last_y) {    //当前点在上一点的上边
                Y_DIRECTION_BIT=1;//第一四象限电机Y旋转方向
                target_y= (y-last_y);
        }else {//当前点在上一点的下边
                Y_DIRECTION_BIT=0;//第二三象限Y电机旋转方向
                target_y= (last_y-y);
        }       
        //DDA/Bresenham直线插补算法
        if(target_x>=target_y)   step_event_count=target_x;
                elsestep_event_count=target_y;//比较起点到终点xy坐标差,取最大坐标作为步进电机总运转步数
        counter_x=step_event_count/2; counter_y=step_event_count/2;//右移1位,没有四舍五入
        X_STEPPER_DISABLE_BIT=0;Y_STEPPER_DISABLE_BIT=0;   //使能电机运转
        last_x=x; last_y=y;//保存当前点坐标,作为下一点的原点
        for(step_events_completed=0;step_events_completed<step_event_count;step_events_completed++){
                counter_x+=target_x; counter_y+=target_y;
                if(counter_x>=step_event_count){
                        x_steper_out_flag=1;        //X步进电机走一步标记
                        counter_x-=step_event_count;
                }
                if(counter_y>=step_event_count){
                        y_steper_out_flag=1;        //Y步进电机走一步标记
                        counter_y-=step_event_count;
                }
                while(x_steper_out_flag);//等待步进电机脉冲输出完成,没有用环形队列FIFO,在这里傻等
                while(y_steper_out_flag);
       }//循环直到线段的所有步数完成
        X_STEPPER_DISABLE_BIT=1; Y_STEPPER_DISABLE_BIT=1; //禁止运转
}
舵机驱动用定时器2完成:
舵机的使用可参照贴子:https://www.amobbs.com/thread-5687693-1-1.html
void write_Angle(unsigned char Channel,unsigned char value)
        //舵机驱动函数,channel=通道,value=角度(0-180)
{       
        AUXR |= 0x10;                //定时器2开始计时
        PWM_Value=(value*27+1200);
}

////定时器2,12T模式时钟24MHz ,输出1路高电平脉冲,剩下的时间为低电平补足20ms
void timer2(void) interrupt 12
{
        AUXR &= B1110_1111;                //定时器2开始停止计时
        switch(order)
        {
                case 1:   
                        SERVO_BIT=1; //开第0路
                        TL2=(-PWM_Value)%256;
                                //(-PWM_Value)=(65536-PWM_Value) 定时时间会更精准
                        TH2=(-PWM_Value)/256; //赋值高电平时间
                        break;
                case 2:
                        SERVO_BIT=0;//关第0路
                        TL2=(25536+PWM_Value)%256;
                                //1路脉冲输出完毕,凑足20ms剩下的低电平时间
                        TH2=(25536+PWM_Value)/256;   
                        order=0;
                        break;
        }
                AUXR |= 0x10;        //定时器2开始计时
                order++;
                AUXR |= 0x10;        //定时器2开始计时                       
}
下面是函数调用方法,点的坐标是手工算出的,傻瓜力大,是吧{:lol:}
画圆弧函数可参照帖子https://www.amobbs.com/thread-5687693-1-1.html
switch(ucKeySec) //按键服务状态切换
{       
    case 1:// K1_Start键
                write_Angle(0,SERVO_put_value);        //落笔
                delay_ms(120);       
                plan_buffer_line(0,30*53.5);
                //53.5是丝杆的参数,4988 设置:MS1=1,MS2=1,MS3悬空,8分频
                plan_buffer_line(30*53.5,30*53.5);
                plan_buffer_line(30*53.5,0);
                plan_buffer_line(0,0);
                write_Angle(0,SERVO_lift_value);//抬笔       
                plan_buffer_line(0,15*53.5);
                write_Angle(0,SERVO_put_value);        //落笔
                delay_ms(120);
                bogenGZS(15*53.5, 15*53.5, 14.5*53.5, 3.14,0);//画圆                       
                bogenGZS(15*53.5, 15*53.5, 14.5*53.5, 6.28,3.14);       
                write_Angle(0,SERVO_lift_value);//抬起               
                plan_buffer_line(0.87*53.5,19.59*53.5);        //E               
                write_Angle(0,SERVO_put_value);        //落笔
                delay_ms(120);                                       
                plan_buffer_line(29.13*53.5,19.59*53.5);//C                                                       
                plan_buffer_line(6.27*53.5,2.98*53.5);//A                               
                plan_buffer_line(15*53.5,30*53.5);//D                                               
                plan_buffer_line(23.73*53.5,2.98*53.5);//B                                                       
                plan_buffer_line(0.87*53.5,19.59*53.5);        //E                       
                write_Angle(0,SERVO_lift_value);//抬起                               
                plan_buffer_line(0,0);                       
                ucKeySec=0;
        break;   
    case 2:// K2_Stop键
                ip=~ip;
                if(ip==0)
                        write_Angle(0,SERVO_put_value);        //落笔       
                else
                        write_Angle(0,SERVO_lift_value);//抬笔
                ucKeySec=0;
        break;
}   

huangguimina4 发表于 2018-11-11 14:41:29

楼主厉害

我是谁712 发表于 2018-11-11 14:49:44

哇,感觉这个精度很好啊

XTXB 发表于 2018-11-11 15:04:07

贴子发错版块了,咋办?{:sweat:}

freemanw 发表于 2018-11-11 15:39:49

不错顶一个

大田 发表于 2018-11-11 15:52:56

顶一个,厉害

wthzack 发表于 2018-11-11 16:21:45

必须顶一下!

sunshulin 发表于 2018-11-11 16:30:16

不错 !!

xuboluan 发表于 2018-11-11 17:19:17

楼主相当厉害

lcw_swust 发表于 2018-11-11 19:43:39

不错哦                     

qiqirachel 发表于 2018-11-11 20:17:07

顶贴,好帖子

ZDHCKJS 发表于 2018-11-11 21:28:55

顶一个!!

ZJetWay 发表于 2018-11-11 22:25:47

顶楼主,做得真不错。

落叶知秋 发表于 2018-11-11 22:42:06

好帖,顶撸主一个 {:lol:}

sunbest80 发表于 2018-11-12 09:41:12

厉害,支持一下


didadida 发表于 2018-11-12 10:27:20

这个太溜了,顶楼主,期待更新~

wuzhpo720 发表于 2018-11-12 12:18:47

顶楼主,做得真不错。

ls81250 发表于 2018-11-21 10:05:53

楼主相当厉害。顶楼主!

kinsno 发表于 2018-11-25 18:39:16

厉害的楼主,这个框架也是给力的。。

huangqi412 发表于 2018-11-25 19:01:58

看着精度很好

foxpro2005 发表于 2018-11-26 08:16:41

手上还有好几个迷你DVD机的机芯组件, 没拆开看不知道能不能折腾

tarchen 发表于 2018-11-26 18:08:12

控制的很好,敬佩。

minicatcatcn 发表于 2018-11-26 21:11:10

厉害,顶起来

gonggu8181 发表于 2018-12-17 07:53:35

厉害,这个是高手{:lol:}

308594151 发表于 2018-12-18 00:10:09

不错,顶一个

ZJetWay 发表于 2019-10-12 16:29:18

楼主,能发整个工程文件?谢谢

XTXB 发表于 2019-10-16 09:02:09

ZJetWay 发表于 2019-10-12 16:29
楼主,能发整个工程文件?谢谢

我的代码太乱,只是实现了功能而已,拿不出手,GRBL是开源的,原版的代码更严谨,花时间啃原版更合算。

ZJetWay 发表于 2019-10-17 20:47:54

楼主谦虚了{:lol:}

光明星1号 发表于 2020-1-30 13:34:16

楼主算法是自己写的吧,GRBL好像用的不是Bresenham算法吧!

sql 发表于 2020-1-30 14:37:09

很厉害。

cyjkai 发表于 2020-2-7 21:01:03

谢谢分享

cjxu 发表于 2020-2-7 23:04:58

谢谢分享 值得学习

enwa 发表于 2020-6-22 09:16:55

太赞了,{:handshake:}

liang16888 发表于 2023-11-23 13:43:26

Thank you !!!
页: [1]
查看完整版本: 用stc15w和旧光驱移植arduino写字机GRBL之三:Bresenham算法