本帖最后由 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避免了浮点运算:
- 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;
- else step_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[Channel]=(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[0])%256;
- //(-PWM_Value[0])=(65536-PWM_Value[0]) 定时时间会更精准
- TH2=(-PWM_Value[0])/256; //赋值高电平时间
- break;
- case 2:
- SERVO_BIT=0;//关第0路
- TL2=(25536+PWM_Value[0])%256;
- //1路脉冲输出完毕,凑足20ms剩下的低电平时间
- TH2=(25536+PWM_Value[0])/256;
- order=0;
- break;
- }
- AUXR |= 0x10; //定时器2开始计时
- order++;
- AUXR |= 0x10; //定时器2开始计时
- }
复制代码
下面是函数调用方法,点的坐标是手工算出的,傻瓜力大,是吧
画圆弧函数可参照帖子
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;
- }
复制代码
一周热门 更多>