#include "plotter.h" const int SCALEX=2; const int SCALEY=3; template int sgn(T val) { int value = (T(0) < val) - (val < T(0)); return (value == 0) ? 1 : value; } Plotter::Plotter(volatile unsigned char *penPort, const char penPin, Serial* serial): _pwm( &TCCR1A, &TCCR1B, &OCR1A, &OCR1B, &ICR1, 0b00000001) { _serial = serial; _penPort=penPort; _penPin=penPin; basicposition(); } Point Plotter::getCurrentPos() { return currentPos; } void Plotter::demo() { moveto(65535,0); moveto(65535,42129); moveto(0,42129); moveto(0,0); pd(); pu(); } void Plotter::basicposition() { moveto(0, 0); } void Plotter::pd() { if(!readPin(_penPort, _penPin)) { _delay_us(200000); writePin(_penPort, _penPin, true); _delay_us(500); } } void Plotter::pu() { if(readPin(_penPort, _penPin)) { _delay_us(100000); writePin(_penPort, _penPin, false); _delay_us(500); } } void Plotter::moveto(Point *pt) { moveto((*pt).x,(*pt).y); } uint16_t Plotter::diamondAngle(int16_t y, int16_t x) //0 - 40000 { const int32_t scalar = 10000; if (y >= 0) return (x >= 0 ? ((int32_t)y*scalar)/(x+y) : 1*scalar-((int32_t)x*scalar)/(-x+y)); else return (x < 0 ? 2*scalar-((int32_t)y*scalar)/(-x-y) : 3*scalar+((int32_t)x*scalar)/(x-y)); } void Plotter::moveto(const uint16_t nx, const uint16_t ny) { int16_t deltaX = nx - currentPos.x; //117 units per mm int16_t deltaY = ny - currentPos.y; //121 units per mm /*_serial->write("deltaX: "); _serial->write(deltaX); _serial->write(" deltaY: "); _serial->write(deltaY);*/ uint16_t steps = 0; //one step is max 1.28205mm min 0.8547mm if(deltaX != 0 || deltaY != 0) { int32_t StepSizeX=0; int32_t StepSizeY=0; if( abs(deltaX) > abs(deltaY)) { StepSizeX = 100*sgn(deltaX);// -100 if(deltaY != 0) StepSizeY = ((int32_t)abs(deltaY)*100)/abs(deltaX)*sgn(deltaY); // 0 if(StepSizeX != 0) steps = deltaX/StepSizeX; } else { if(deltaX != 0) StepSizeX = ((int32_t)abs(deltaX)*100)/abs(deltaY)*sgn(deltaX); StepSizeY = 100*sgn(deltaY); if(StepSizeY != 0) steps = deltaY/StepSizeY; } uint16_t currentDiamondAngle = diamondAngle(deltaX,deltaY); uint16_t delayTime = abs(currentDiamondAngle - prevDiamondAngle); if ( delayTime > 20000) delayTime = delayTime - 20000; if( deltaX > 50 || deltaY > 50 ) { if( prevSteps > 4 || delayTime > 10000 ) for (uint16_t i = 0; i < delayTime; i++) _delay_us(50); else for(uint16_t j = 0; j < prevSteps+1; j++) for(uint16_t i = 0; i < delayTime; i++) _delay_us(5); } else if( deltaX > 20 || deltaY > 20 ) for (uint16_t i = 0; i < delayTime/4; i++) _delay_us(1); else _delay_us(100); /*_serial->write(" currentDiamondAngle: "); _serial->write(currentDiamondAngle); _serial->write(" delayTime: "); _serial->write(delayTime);*/ if( deltaX > 20 || deltaY > 20 ) { prevDiamondAngle = currentDiamondAngle; prevSteps = steps; } //_serial->putChar('\n'); for( uint16_t i = 0; i < steps; i++) { _pwm.setDutyA(65535-(currentPos.x+i*StepSizeX)*SCALEX); _pwm.setDutyB(65535-(currentPos.y+i*StepSizeY)*SCALEY); _delay_us(2000); } } _pwm.setDutyA(65535-nx*SCALEX); _pwm.setDutyB(65535-ny*SCALEY); currentPos.x = nx; currentPos.y = ny; }