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

2020-01-12 17:18发布

本帖最后由 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循环队列,运动时程序就傻等着,先跑起来增加点信心:
2.jpg (132.19 KB, 下载次数: 0) 下载附件 2018-11-11 13:32 上传
C语言实现Bresenham线段插补算法,较DDA算法Bresenham避免了浮点运算:
  1. void plan_buffer_line(u16 x, u16 y){ //(x,y)为当前点的绝对坐标
  2.         static u16 step_event_count=0;//总步数
  3.         static u16 counter_x=0; static u16 counter_y=0; static u16 step_events_completed=0;//循环计数器       
  4.         if(x>=last_x){   //当前点在上一点的右边,(last_x,last_y)为上一点的绝对坐标
  5.                 X_DIRECTION_BIT=0;//第一四象限X电机旋转方向
  6.                 target_x= (x-last_x);//求相对坐标的绝对值
  7.         }else {  //当前点在上一点的左边
  8.                 X_DIRECTION_BIT=1;//第二三象限X电机旋转方向
  9.                 target_x= (last_x-x);//求相对坐标的绝对值
  10.         }//以上一点为原点的直角坐标系中,判断当前点在哪个象限从而决定xy电机的旋转方向
  11.         if(y>=last_y) {    //当前点在上一点的上边
  12.                 Y_DIRECTION_BIT=1;//第一四象限电机Y旋转方向
  13.                 target_y= (y-last_y);
  14.         }else {  //当前点在上一点的下边
  15.                 Y_DIRECTION_BIT=0;//第二三象限Y电机旋转方向
  16.                 target_y= (last_y-y);
  17.         }       
  18.         //DDA/Bresenham直线插补算法
  19.         if(target_x>=target_y)   step_event_count=target_x;
  20.                 else  step_event_count=target_y;//比较起点到终点xy坐标差,取最大坐标作为步进电机总运转步数
  21.         counter_x=step_event_count/2; counter_y=step_event_count/2;//右移1位,没有四舍五入
  22.         X_STEPPER_DISABLE_BIT=0;  Y_STEPPER_DISABLE_BIT=0;   //使能电机运转
  23.         last_x=x; last_y=y;  //保存当前点坐标,作为下一点的原点
  24.         for(step_events_completed=0;step_events_completed<step_event_count;step_events_completed++){
  25.                 counter_x+=target_x; counter_y+=target_y;
  26.                 if(counter_x>=step_event_count){
  27.                         x_steper_out_flag=1;        //X步进电机走一步标记
  28.                         counter_x-=step_event_count;
  29.                 }
  30.                 if(counter_y>=step_event_count){
  31.                         y_steper_out_flag=1;        //Y步进电机走一步标记
  32.                         counter_y-=step_event_count;
  33.                 }
  34.                 while(x_steper_out_flag);//等待步进电机脉冲输出完成,没有用环形队列FIFO,在这里傻等
  35.                 while(y_steper_out_flag);
  36.          }//循环直到线段的所有步数完成
  37.         X_STEPPER_DISABLE_BIT=1; Y_STEPPER_DISABLE_BIT=1; //禁止运转
  38. }
复制代码
舵机驱动用定时器2完成:
舵机的使用可参照贴子:https://www.amobbs.com/thread-5687693-1-1.html
  1. void write_Angle(unsigned char Channel,unsigned char value)
  2.         //舵机驱动函数,channel=通道,value=角度(0-180)
  3. {       
  4.         AUXR |= 0x10;                //定时器2开始计时
  5.         PWM_Value[Channel]=(value*27+1200);
  6. }

  7. ////定时器2,12T模式时钟24MHz ,输出1路高电平脉冲,剩下的时间为低电平补足20ms
  8. void timer2(void) interrupt 12
  9. {
  10.         AUXR &= B1110_1111;                //定时器2开始停止计时
  11.         switch(order)
  12.         {
  13.                 case 1:   
  14.                         SERVO_BIT=1; //开第0路
  15.                         TL2=(-PWM_Value[0])%256;
  16.                                 //(-PWM_Value[0])=(65536-PWM_Value[0]) 定时时间会更精准
  17.                         TH2=(-PWM_Value[0])/256; //赋值高电平时间
  18.                         break;
  19.                 case 2:
  20.                         SERVO_BIT=0;//关第0路
  21.                         TL2=(25536+PWM_Value[0])%256;
  22.                                 //1路脉冲输出完毕,凑足20ms剩下的低电平时间
  23.                         TH2=(25536+PWM_Value[0])/256;   
  24.                         order=0;
  25.                         break;
  26.         }
  27.                 AUXR |= 0x10;        //定时器2开始计时
  28.                 order++;
  29.                 AUXR |= 0x10;        //定时器2开始计时                       
  30. }
复制代码
下面是函数调用方法,点的坐标是手工算出的,傻瓜力大,是吧
画圆弧函数可参照帖子https://www.amobbs.com/thread-5687693-1-1.html
  1.   switch(ucKeySec) //按键服务状态切换
  2.   {       
  3.     case 1:// K1_Start键
  4.                 write_Angle(0,SERVO_put_value);        //落笔
  5.                 delay_ms(120);       
  6.                 plan_buffer_line(0,30*53.5);
  7.                 //53.5是丝杆的参数,4988 设置:MS1=1,MS2=1,MS3悬空,8分频
  8.                 plan_buffer_line(30*53.5,30*53.5);
  9.                 plan_buffer_line(30*53.5,0);
  10.                 plan_buffer_line(0,0);
  11.                 write_Angle(0,SERVO_lift_value);//抬笔       
  12.                 plan_buffer_line(0,15*53.5);
  13.                 write_Angle(0,SERVO_put_value);        //落笔
  14.                 delay_ms(120);
  15.                 bogenGZS(15*53.5, 15*53.5, 14.5*53.5, 3.14,  0);//画圆                       
  16.                 bogenGZS(15*53.5, 15*53.5, 14.5*53.5, 6.28,  3.14);       
  17.                 write_Angle(0,SERVO_lift_value);//抬起               
  18.                 plan_buffer_line(0.87*53.5,19.59*53.5);        //E               
  19.                 write_Angle(0,SERVO_put_value);        //落笔
  20.                 delay_ms(120);                                       
  21.                 plan_buffer_line(29.13*53.5,19.59*53.5);//C                                                       
  22.                 plan_buffer_line(6.27*53.5,2.98*53.5);//A                               
  23.                 plan_buffer_line(15*53.5,30*53.5);//D                                               
  24.                 plan_buffer_line(23.73*53.5,2.98*53.5);//B                                                       
  25.                 plan_buffer_line(0.87*53.5,19.59*53.5);        //E                       
  26.                 write_Angle(0,SERVO_lift_value);//抬起                               
  27.                 plan_buffer_line(0,0);                       
  28.                 ucKeySec=0;  
  29.         break;   
  30.     case 2:// K2_Stop键
  31.                 ip=~ip;
  32.                 if(ip==0)
  33.                         write_Angle(0,SERVO_put_value);        //落笔       
  34.                 else
  35.                         write_Angle(0,SERVO_lift_value);//抬笔
  36.                 ucKeySec=0;  
  37.         break;  
  38.   }   
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。