· 7 years ago · Sep 20, 2018, 06:08 PM
1#include <BoolField.h>
2#include <DegreeField.h>
3#include <Field.h>
4#include <Form.h>
5#include <IntField.h>
6#include <LCD.h>
7#include <ListField.h>
8#include <TextField.h>
9#include <TimeField.h>
10#include <GetIntField.h>
11#include <GetMicroField.h>
12#include <TimerOne.h>
13#include <EEPROM.h>
14#include <avr/wdt.h>
15#include <avr/pgmspace.h>
16#include "EEPROMAnything.h"
17
18void goDivide(long gAngle);
19void goJog(void);
20void enterDegrees(void);
21void enterDivisions(void);
22void goSetSpeed(void);
23void goHome(void);
24void goSetJogStep(void);
25void setSpeed(int spdPct);
26void goConTurn(void);
27void doTravel(long dist);
28void enterDistance(void);
29long HzToTimeDelay(long iHz);
30long TimeDelayToHz(long tDelay);
31int getGlobals(int gDevice);
32int putGlobals(void);
33void doSetupMenu(void);
34void setSteps(long sSteps, int sWait); // If sWait is true, it will wait until steps are complete
35void rampDown(void);
36void doConfigMenu(void);
37void eraseEeprom(char *sPrompt);
38void addDevice(char *pPrompt);
39void setdeviceType(int dType);
40void printDistanceVals(long DistToTravel, int step);
41
42void doTravel(long idistance);
43
44
45#define STEP_PIN 1
46#define DIR_PIN 2
47#define MINUTES_IN_CIRCLE 1296000 // Number od seconds in a 360 degree circle
48#define MAX_LONG 2147483646 // The biggest number we can use with a long
49#define CONFIG_VERSION "RT4" // The Sigature to tell us we've saved stuff in the EEPROM
50#define NO_DEVICE_SIG "XXX" // The Sigature to tell us we've got nothing in the EEPROM
51#define DEV_ROTARY 0 // Device Type - Rotary Table
52#define DEV_LINEAR 1 // Device Type - Linear device mm
53
54#define SUB_VER 1 // Change on each version
55#define STEPPER_STEPS_REV 200 // The number of steps per stepper
56#define MICRO_STEPS 10 // set to 1 if not not using a micostepper driver, otherwise set to # microsteps
57#define DIVIDE_RATIO 90 // The Dividing table ratio (eg 40 or 90)
58#define MM_PER_REV 2 // Travel per mm
59#define MAX_STEPPER_HZ 10000 // Maximum frequency for this stepper
60#define MIN_STEPPER_HZ 5000 // Minimum frequency for this stepper
61#define TIMER_DELAY 80 // 80 MIcroseconds between interrupt ticks
62#define JOG_STEP_ANGLE 1800L // 0.5 degrees (30 seconds)
63
64struct globals_t // Size = 40 bytes
65{
66
67 int devType;
68 int DirPin;
69 int StepPin;
70 long stepperStepsPerRev;
71 int microSteps;
72 int divideRatio;
73 long maxStepperHz;
74 long minStepperHz;
75 long stepsPerRev;
76 long JogStepAngle;
77 long TravelDistRev;
78 long JogStepCount;
79 int dir;
80 long timerDelay;
81} globals={
82 DEV_ROTARY,
83 DIR_PIN,
84 STEP_PIN,
85 (long)STEPPER_STEPS_REV,
86 MICRO_STEPS,
87 DIVIDE_RATIO,
88 (long)MAX_STEPPER_HZ,
89 (long)MIN_STEPPER_HZ,
90 ((long)STEPPER_STEPS_REV * (long)MICRO_STEPS * (long)DIVIDE_RATIO),
91 (long)JOG_STEP_ANGLE,
92 2000L, //
93 (long)(((float)STEPPER_STEPS_REV * (float)MICRO_STEPS * (float)DIVIDE_RATIO) *((float)JOG_STEP_ANGLE/(float)MINUTES_IN_CIRCLE)),
94 0,
95 TIMER_DELAY
96};
97
98struct config_t // Size = 10 bytes
99{
100 char version[4];
101 int subVer; // Change this each release
102 int currDevice;
103 int numDevices;
104}configuration;
105
106LCD lcd;
107int CLOCKWISE = 0;
108int ANTICLOCKWISE = 1;
109volatile int state = CLOCKWISE;
110volatile long steps = 0L; // Number of steps to process
111volatile long stepcount = 0; // Number of steps done;
112long rampSteps;
113volatile int stepmod=0;
114
115volatile long endRampUp; // Steps to stop ramping up
116volatile long startRampDown; // Steps to start ramping down
117static long startDelay; // Start delay - slow speed stepper start pulse delay in microseconds
118static long targetDelay; // Target delay - Full speed stepper pulse delay in microseconds
119static long sDelay; // Current delay for stepper movement
120
121volatile long homePos = 0L; // Remember the home position
122long divisions=3;
123long distance =10000L;
124long stepsPerDiv=0;
125long mAngle = 0L;
126int goinghome = 0; // True if Table is going home
127long Operating_Hz; // The frequency the steper is operating at
128
129const char item_Start[] PROGMEM = "UP/DWN Starts";
130 ListItem const TopMenu[] PROGMEM = {
131 item_Start,
132 0
133 };
134const char yStr[] = "Yes";
135const char nStr[] = "No";
136const char item_DeviceRot[] PROGMEM = "Rotary";
137const char item_DeviceMM[] PROGMEM = "Linear";
138
139 ListItem const iDevType[] PROGMEM = {
140 item_DeviceRot,
141 item_DeviceMM,
142 0
143 };
144 Form mainForm(lcd);
145 ListField goDivideField(mainForm, "<Divide #>" , TopMenu);
146 ListField goAngleField(mainForm, "<Div Angle>" , TopMenu);
147 ListField goTravelField_mm(mainForm, "<Travel>" , TopMenu);
148 ListField goJogField(mainForm,"<Jog>" , TopMenu);
149 ListField goHomeField(mainForm, "<Home>" ,TopMenu);
150 ListField goConTurnField(mainForm,"<Contin>",TopMenu);
151 ListField goConfigField(mainForm,"<Config>" ,TopMenu);
152
153
154void setup()
155{
156 const char welcome1[] PROGMEM = "VMN Ctrl";
157 const char welcome2[] PROGMEM = "V:";
158 const char welcome3[] PROGMEM = "D=";
159 const char rotStr[] PROGMEM = "Rot";
160 const char linStr[] PROGMEM = "Lin";
161
162 long previousMillis = 0;
163 unsigned long currentMillis;
164 long interval = 2000L;
165 int event = LCD_BUTTON_NONE;
166
167 MCUSR = 0; // clear out any flags of prior resets so we can reboot
168 //read the config from EEPROM
169 startDelay = HzToTimeDelay(globals.minStepperHz);
170 targetDelay = HzToTimeDelay(globals.maxStepperHz);
171 sDelay = targetDelay;
172 EEPROM_readAnything(0, configuration);
173 {
174 const char sig[] PROGMEM = CONFIG_VERSION;
175 int ok = 1;
176 int cs = sizeof(configuration);
177 char *s = (char *)sig;
178 char *p= (char *)&configuration;
179 while(*s){
180 if(*s != *p){
181 ok = 0;
182 break;
183 }
184 s++; p++;
185 }
186 if(!ok){
187 // No data in EEprom, so set the data
188 strcpy(configuration.version,sig);
189 configuration.subVer = SUB_VER;
190 configuration.currDevice = 0;
191 configuration.numDevices = 0; //First device in C++ = 0
192 EEPROM_writeAnything(0, configuration); // write to EEProm
193 globals.timerDelay = sDelay;
194 EEPROM_writeAnything(cs,globals); // Write the defaults to EEprom starting at the first byte after configuration
195 }
196 else{
197 getGlobals(configuration.currDevice);
198 }
199 }
200 // We've read everything from EEPROM, so set the defaults
201 mAngle =(long)((float)MINUTES_IN_CIRCLE / (float)divisions);
202 float tmpSteps = (float) globals.stepsPerRev; // (float)STEPS_PER_REV
203 stepsPerDiv = (long)(tmpSteps *((float)mAngle/(float)MINUTES_IN_CIRCLE));
204 globals.JogStepCount = (long)(tmpSteps *((float)globals.JogStepAngle/(float)MINUTES_IN_CIRCLE)) * 2L;
205 startDelay = HzToTimeDelay(globals.minStepperHz);
206 targetDelay = HzToTimeDelay(globals.maxStepperHz);
207 sDelay = targetDelay;
208 if(globals.dir){
209 CLOCKWISE = 1;
210 ANTICLOCKWISE = 0;
211 }
212 else{
213 CLOCKWISE = 0;
214 ANTICLOCKWISE = 1;
215 }
216 pinMode(globals.StepPin, OUTPUT);
217 pinMode(globals.DirPin, OUTPUT);
218 Timer1.initialize(sDelay); // set a timer of length in microseconds (or 0.1 sec - or 10Hz)
219 Timer1.attachInterrupt( timerIsr ); // attach the service routine here
220 // Enable the screen saver, which will automatically blank the screen after 30 seconds. You may wish to comment this line out if it annoys you
221 lcd.enableScreenSaver(30);
222 Operating_Hz = globals.maxStepperHz;
223 //globals.stepsPerRev = 180000L; // RJW Check deleting this does not break stuff, shouldn't be hardocding stuff, probably from debugging
224 setdeviceType(globals.devType);
225 // Print a welcome message
226 lcd.clear();
227 lcd.setCursor(0,0);
228 lcd.print(welcome1);
229 lcd.setCursor(0,1);
230 lcd.print(welcome2);
231 lcd.print(configuration.version);
232 lcd.print(".");
233 lcd.print(configuration.subVer);
234 lcd.setCursor(8,1);
235 lcd.print(welcome3);
236 lcd.print(configuration.currDevice);
237 lcd.setCursor(13,1);
238 if(globals.devType == DEV_ROTARY){
239 lcd.print(rotStr);
240 }
241 else{
242 lcd.print(linStr);
243 globals.stepsPerRev = (long)((float)globals.stepperStepsPerRev * (float)globals.microSteps * ((float)globals.divideRatio/1000.0)); // Calculate linear stes per rev
244 }
245 while(1){ // Delay 2 seconds without using delay();
246 currentMillis = millis();
247 if(currentMillis - previousMillis > interval) {
248 previousMillis = currentMillis;
249 break;
250 }
251 event = lcd.getButton();
252 }
253 lcd.clear();
254
255 // Show the main form for the first time.
256 mainForm.show();
257}
258
259void loop()
260{
261 int i;
262
263 // Dispatch button events to the main form.
264 int event = lcd.getButton();
265 if (mainForm.dispatch(event) == FORM_CHANGED) {
266 if (mainForm.isCurrent(goDivideField)) {
267 enterDivisions();
268 mainForm.setCurrentField(&goDivideField);
269 }
270 if (mainForm.isCurrent(goJogField)) {
271 goJog();
272 mainForm.setCurrentField(&goJogField);
273 }
274 if (mainForm.isCurrent(goAngleField)) {
275 enterDegrees();
276 mainForm.setCurrentField(&goAngleField);
277 }
278 if (mainForm.isCurrent(goHomeField)) {
279 goHome();
280 mainForm.setCurrentField(&goHomeField);
281 }
282 if (mainForm.isCurrent(goConTurnField)) {
283 goConTurn();
284 mainForm.setCurrentField(&goConTurnField);
285 }
286 if (mainForm.isCurrent(goConfigField)) {
287 doConfigMenu();
288 mainForm.setCurrentField(&goConfigField);
289 }
290 if (mainForm.isCurrent(goTravelField_mm)) {
291 enterDistance();
292 mainForm.setCurrentField(&goTravelField_mm);
293 }
294
295 }
296}
297
298void printDivideVals(int iDiv,long iAngle)
299{
300 Form tempForm(lcd);
301 DegreeField tempField(tempForm, "", 360, DEGREEFIELD_READ_WRITE); // Just using this to convert to degrees
302
303 lcd.clear();
304 lcd.setCursor(0,0);
305 lcd.print("Div: ");
306 lcd.print(iDiv);
307 lcd.print(" of ");
308 lcd.print(divisions);
309 tempField.setValue(iAngle);
310 tempField.printDegrees();
311 lcd.setCursor(10,1);
312 lcd.print(" / Div");
313 tempForm.removeField(&tempField);
314}
315
316
317void goDivide(long gAngle)
318{
319 long thisDiv = 1;
320 int event = LCD_BUTTON_NONE;
321 float tmpSTEPS_PER_REV = (float)globals.stepsPerRev;
322
323 stepsPerDiv = (long)(tmpSTEPS_PER_REV *((float)gAngle/(float)MINUTES_IN_CIRCLE));
324 divisions = (long)((float) MINUTES_IN_CIRCLE / (float) gAngle);
325 printDivideVals(thisDiv,gAngle);
326 while(event != LCD_BUTTON_SELECT){
327 event = lcd.getButton();
328 switch(event){
329 case LCD_BUTTON_LEFT:
330 thisDiv--;
331 if(thisDiv < 1)
332 thisDiv = divisions;
333 digitalWrite( globals.DirPin, ANTICLOCKWISE );
334 setSteps(stepsPerDiv * 2, 1);
335 printDivideVals(thisDiv,gAngle);
336 break;
337 case LCD_BUTTON_RIGHT:
338 thisDiv++;
339 if(thisDiv > divisions)
340 thisDiv = 1;
341 digitalWrite( globals.DirPin, CLOCKWISE );
342 setSteps(stepsPerDiv * 2,1);
343 printDivideVals(thisDiv, gAngle);
344 break;
345 }
346 }
347}
348
349void goJog(void)
350{
351 int event,event2 = LCD_BUTTON_NONE;
352 const char jog1[] PROGMEM = "CONT: Left/Right";
353 const char jog2[] PROGMEM = "STEP: Up/Down";
354
355 lcd.clear();
356 lcd.setCursor(0,0);
357 lcd.print(jog1);
358 lcd.setCursor(0,1);
359 lcd.print(jog2);
360
361 while(event != LCD_BUTTON_SELECT){
362 event = lcd.getButton();
363 if(sDelay < HzToTimeDelay(globals.maxStepperHz))
364 sDelay = HzToTimeDelay(globals.maxStepperHz);
365 switch(event){
366 case LCD_BUTTON_LEFT:
367 digitalWrite( globals.DirPin, ANTICLOCKWISE );
368 setSteps(MAX_LONG, 0);
369 break;
370 case LCD_BUTTON_RIGHT:
371 digitalWrite( globals.DirPin, CLOCKWISE );
372 setSteps(MAX_LONG,0);
373 break;
374 case LCD_BUTTON_UP:
375 digitalWrite( globals.DirPin, CLOCKWISE );
376 setSteps(globals.JogStepCount, 1);
377 break;
378 case LCD_BUTTON_DOWN:
379 digitalWrite( globals.DirPin, ANTICLOCKWISE );
380 setSteps(globals.JogStepCount, 1);
381 break;
382 case LCD_BUTTON_LEFT_RELEASED:
383 case LCD_BUTTON_RIGHT_RELEASED:
384 steps = 0;
385 rampDown(); // Need to add enough steps to slow down
386 break;
387 }
388 }
389 steps = 0L;
390}
391
392void enterDegrees(void)
393{
394
395 Form angleForm(lcd);
396 DegreeField angleField(angleForm,"Set Ang" , 360, DEGREEFIELD_READ_WRITE);
397
398 int event = LCD_BUTTON_NONE;
399
400 angleField.setValue(mAngle);
401 angleForm.defaultField();
402 angleForm.show();
403 while(event!= LCD_BUTTON_SELECT){
404 event = lcd.getButton();
405 if(event == LCD_BUTTON_SELECT)
406 break;
407 if (angleForm.dispatch(event) == FORM_CHANGED) {
408 if (angleForm.isCurrent(angleField)) {
409 mAngle = angleField.value();
410 float tmpSteps = (float) globals.stepsPerRev; // (float)STEPS_PER_REV
411 divisions = (long)(tmpSteps *((float)mAngle/(float)MINUTES_IN_CIRCLE));
412 }
413 }
414 }
415 if(mAngle)
416 goDivide(mAngle);
417}
418
419void enterDivisions(void)
420{
421 Form divideForm(lcd);
422 GetIntField divfField(divideForm,"Divs" , 9999, GETINTFIELD_READ_WRITE);
423
424 int event = LCD_BUTTON_NONE;
425 divfField.setValue(divisions);
426 divideForm.defaultField();
427 divideForm.show();
428 while(event != LCD_BUTTON_SELECT){
429 event = lcd.getButton();
430 if (divideForm.dispatch(event) == FORM_CHANGED) {
431 if (divideForm.isCurrent(divfField)) {
432 divisions = divfField.value();
433 mAngle=(long)((float)MINUTES_IN_CIRCLE / (float)divisions);
434 }
435 }
436 }
437 if(divisions)
438 goDivide(mAngle);
439 divideForm.removeField(&divfField);
440}
441
442void goSetSpeed(void)
443{
444 Form speedForm(lcd);
445 IntField speedField(speedForm,"Spd" , 0, 100, 5, 100, "%");
446 int speedPct = (int)((((float)((float)globals.maxStepperHz - (float)globals.minStepperHz) / (float)(Operating_Hz - globals.minStepperHz)))*100.0);
447 int event = LCD_BUTTON_NONE;
448 lcd.clear();
449 speedField.setValue(speedPct);
450 speedForm.defaultField();
451 speedForm.show();
452 while(event != LCD_BUTTON_SELECT ){
453 event = lcd.getButton();
454 if (speedForm.dispatch(event) == FORM_CHANGED) {
455 if (speedForm.isCurrent(speedField)) {
456 speedPct = speedField.value();
457 }
458 }
459 }
460 setSpeed(speedPct);
461}
462
463void setSpeed(int spdPct)
464{
465 globals.maxStepperHz = (long)((float)( Operating_Hz - globals.minStepperHz) * (float)spdPct/100.0) + globals.minStepperHz;
466 globals.timerDelay = HzToTimeDelay(globals.maxStepperHz);
467 Timer1.setPeriod(globals.timerDelay); // set a timer of length in microseconds
468}
469
470void goHome(void)
471{
472 int event = LCD_BUTTON_NONE;
473 long tmpSteps = (long)globals.stepsPerRev;
474
475 const char home1[] PROGMEM = "SET: Left/Right";
476 const char home2[] PROGMEM = "GOTO: Up/Down";
477 const char home3[] PROGMEM = "HOME Set ";
478 const char home4[] PROGMEM = "Going HOME";
479
480 lcd.clear();
481 lcd.setCursor(0,0);
482 lcd.print(home1);
483 lcd.setCursor(0,1);
484 lcd.print(home2);
485
486 while(1){
487 event = lcd.getButton();
488 if(event == LCD_BUTTON_SELECT)
489 break;
490 switch(event){
491 //set home
492 case LCD_BUTTON_LEFT:
493 case LCD_BUTTON_RIGHT:
494 lcd.setCursor(6,0);
495 lcd.print(home3);
496 while(steps){
497 ;
498 }
499 homePos = 0;
500 break;
501 case LCD_BUTTON_UP:
502 case LCD_BUTTON_DOWN:
503 // Goto home
504 lcd.setCursor(6,1);
505 lcd.print(home4);
506 goinghome++;
507 if(globals.devType == DEV_ROTARY){ // Rotary Device, do the original code
508 if(homePos <= (tmpSteps / 2L)){
509 digitalWrite( globals.DirPin, ANTICLOCKWISE );
510 setSteps(homePos * 2,1);
511 }
512 else{
513 digitalWrite( globals.DirPin, CLOCKWISE );
514 setSteps((tmpSteps - homePos) * 2, 1);
515 }
516 }
517 else{ // Linear device, check if we re to the left or right of home and set the direction
518 if(homePos > 0)
519 digitalWrite( globals.DirPin, ANTICLOCKWISE );
520 else
521 digitalWrite( globals.DirPin, CLOCKWISE );
522 setSteps(abs(homePos) * 2,1);
523 }
524 while(steps){
525 ;
526 }
527 homePos = 0;
528 goinghome = 0;
529 break;
530 default:
531 break;
532 }
533 }
534}
535
536void goSetJogStep(void)
537{
538 Form jogStepForm(lcd);
539 DegreeField jogStepField(jogStepForm,"Jog Angle" , 10, DEGREEFIELD_READ_WRITE);
540
541 int event = LCD_BUTTON_NONE;
542 float tmpSteps = (float) globals.stepsPerRev; // (float)STEPS_PER_REV
543
544 lcd.clear();
545 jogStepField.setValue(globals.JogStepAngle);
546 jogStepForm.defaultField();
547 jogStepForm.show();
548 while(event != LCD_BUTTON_SELECT ){
549 event = lcd.getButton();
550 if (jogStepForm.dispatch(event) == FORM_CHANGED) {
551 if (jogStepForm.isCurrent(jogStepField)) {
552 globals.JogStepAngle = jogStepField.value() * 2;
553 globals.JogStepCount = (long)(tmpSteps *((float)globals.JogStepAngle/(float)MINUTES_IN_CIRCLE));
554 }
555 }
556 }
557}
558
559
560void goConTurn(void)
561{
562
563 Form conTurnForm(lcd);
564 TextField conTurnField(conTurnForm,"Cont", "SEL Stop" );
565 int direction = digitalRead(globals.DirPin);
566 int event = LCD_BUTTON_NONE;
567 lcd.clear();
568 conTurnForm.defaultField();
569 conTurnForm.show();
570 rampUp();
571 steps = MAX_LONG;
572 while(event != LCD_BUTTON_SELECT ){
573 if(sDelay < HzToTimeDelay(globals.maxStepperHz ))
574 sDelay = HzToTimeDelay(globals.maxStepperHz );
575 event = lcd.getButton();
576 switch(event){
577 case LCD_BUTTON_LEFT:
578 if( direction != ANTICLOCKWISE){
579 rampDown();
580 while(steps){
581 ;
582 }
583 direction = ANTICLOCKWISE;
584 digitalWrite(globals.DirPin, direction );
585 rampUp();
586 steps = MAX_LONG;
587 }
588 break;
589 case LCD_BUTTON_RIGHT:
590 if(direction != CLOCKWISE){
591 rampDown();
592 while(steps){
593 ;
594 }
595 direction = CLOCKWISE;
596 digitalWrite( globals.DirPin, CLOCKWISE );
597 rampUp();
598 steps = MAX_LONG;
599 }
600 break;
601 }
602 if (conTurnForm.dispatch(event) == FORM_CHANGED) {
603 if (conTurnForm.isCurrent(conTurnField)) {
604 }
605 }
606 }
607 rampDown();
608 while(steps){
609 ;
610 }
611}
612
613int getGlobals(int gDevice)
614{
615 // Get the configuraton data
616 EEPROM_readAnything(gDevice * sizeof(globals) + sizeof(configuration),globals); // configuraaton exists, so read the curent setup.
617 // DO any further setup for this device
618 setdeviceType(globals.devType);
619 if(globals.dir){
620 CLOCKWISE = 1;
621 ANTICLOCKWISE = 0;
622 }
623 else{
624 CLOCKWISE = 0;
625 ANTICLOCKWISE = 1;
626 }
627 return 0;
628}
629
630int putGlobals(void)
631{
632 int offset = configuration.currDevice * sizeof(globals) + sizeof(configuration); // calculate the offset based on setup number
633 EEPROM_writeAnything(offset,globals); // Write the defaults to EEprom starting at the first byte after configuration
634
635 return 0;
636}
637
638void doSetupMenu(void)
639{
640
641 Form setupForm(lcd);
642 int saveSetup = false;
643 ListField sTypeField(setupForm, "DevTyp",iDevType);
644 GetMicroField sJogStepDistField(setupForm, "JgMM", 999999, GETINTFIELD_READ_WRITE);
645 DegreeField sJogStepAngleField(setupForm, "JgAn",360, DEGREEFIELD_READ_WRITE);
646 IntField sDirPinField (setupForm, "DirP",0,20,1,2," ");
647 IntField sStepPinField (setupForm,"StpP",0,20,1,1," ");
648 GetIntField sStepperStepsRevField(setupForm,"Stp/Rv" , 9999, GETINTFIELD_READ_WRITE);
649 IntField sMicroStepsField (setupForm,"M/Stp",0,99,1,10,":1");
650 IntField sDivideRatioField (setupForm,"D/Rat",0,9999,1,globals.divideRatio,":1");
651 GetMicroField sTravelRatioField (setupForm,"T/Rat",999999, GETINTFIELD_READ_WRITE);
652 GetMicroField sTravelMMField (setupForm,"Dis/Rv",999999, GETINTFIELD_READ_WRITE);
653 GetIntField sMaxStepperHzField(setupForm, "MaxHz", 999999, GETINTFIELD_READ_WRITE);
654 GetIntField sMinStepperHzField(setupForm, "MinHz", 999999, GETINTFIELD_READ_WRITE);
655 BoolField sDirField(setupForm, "SwapD?", yStr,nStr, false);
656 BoolField sSaveField(setupForm, "Save?", yStr, nStr, false);
657
658 int event = LCD_BUTTON_NONE;
659 sDirPinField.setValue(globals.DirPin);
660 sStepPinField.setValue(globals.StepPin);
661 sStepperStepsRevField.setValue(globals.stepperStepsPerRev);
662 sTravelMMField.setValue(globals.TravelDistRev);
663 sMicroStepsField.setValue(globals.microSteps);
664 sDivideRatioField.setValue(globals.divideRatio);
665 sMaxStepperHzField.setValue(globals.maxStepperHz);
666 sMinStepperHzField.setValue(globals.minStepperHz);
667 sJogStepAngleField.setValue(globals.JogStepAngle);
668 sJogStepDistField.setValue(globals.JogStepAngle);
669 //sDirField.setValue(globals.dir);
670 sTypeField.setValue(globals.devType);
671 switch(globals.devType){
672 case DEV_ROTARY:
673 setupForm.removeField(&sTravelMMField);
674 setupForm.removeField(&sJogStepDistField);
675 setupForm.removeField(&sTravelRatioField);
676 break;
677 case DEV_LINEAR:
678 setupForm.removeField(&sDivideRatioField);
679 setupForm.removeField(&sJogStepAngleField);
680 break;
681 }
682
683 lcd.clear();
684 setupForm.defaultField();
685 setupForm.show();
686 while(event != LCD_BUTTON_SELECT){
687 event = lcd.getButton();
688 if (setupForm.dispatch(event) == FORM_CHANGED) {
689 if (setupForm.isCurrent(sDirPinField)) {
690 globals.StepPin = sStepPinField.value();
691 }
692 if (setupForm.isCurrent(sDirPinField)) {
693 globals.DirPin = sDirPinField.value();
694 }
695 if (setupForm.isCurrent(sMicroStepsField)) {
696 globals.microSteps = sMicroStepsField.value();
697 globals.stepsPerRev = globals.stepperStepsPerRev * globals.microSteps * globals.divideRatio;
698 }
699 if (setupForm.isCurrent(sStepperStepsRevField)) {
700 globals.stepperStepsPerRev = sStepperStepsRevField.value();
701 globals.stepsPerRev = globals.stepperStepsPerRev * globals.microSteps * globals.divideRatio;
702 }
703 if (setupForm.isCurrent(sDivideRatioField)) {
704 globals.divideRatio = sDivideRatioField.value();
705 globals.stepsPerRev = globals.stepperStepsPerRev * globals.microSteps * globals.divideRatio;
706 }
707 if (setupForm.isCurrent(sTravelRatioField)) {
708 globals.divideRatio = sTravelRatioField.value();
709 globals.stepsPerRev = (long)((float)globals.stepperStepsPerRev * (float)globals.microSteps * ((float)globals.divideRatio/1000.0));
710 }
711
712 if (setupForm.isCurrent(sMaxStepperHzField)) {
713 globals.maxStepperHz = sMaxStepperHzField.value();
714 }
715 if (setupForm.isCurrent(sMinStepperHzField)) {
716 globals.minStepperHz = sMinStepperHzField.value();
717 }
718 if (setupForm.isCurrent(sJogStepAngleField)) {
719 globals.JogStepAngle = sJogStepAngleField.value();
720 float tmpSteps = (float) globals.stepsPerRev;
721 globals.JogStepCount = (long)(tmpSteps *((float)globals.JogStepAngle/(float)MINUTES_IN_CIRCLE)) * 2L;
722 }
723 if (setupForm.isCurrent(sDirField)) {
724 if(sDirField.value()){
725 globals.dir ^= globals.dir;
726 if(globals.dir){
727 CLOCKWISE = 1;
728 ANTICLOCKWISE = 0;
729 }
730 else{
731 CLOCKWISE = 0;
732 ANTICLOCKWISE = 1;
733 }
734 } \
735 }
736 if (setupForm.isCurrent(sTypeField)) {
737 globals.devType = sTypeField.value();
738 setdeviceType(globals.devType);
739 }
740 if (setupForm.isCurrent(sSaveField)) {
741 saveSetup = sSaveField.value();
742 }
743 }
744 }
745 if(saveSetup){
746 int retval = putGlobals();
747 wdt_enable(WDTO_15MS); // REBOOT - turn on the WatchDog and don't stroke it.
748 for(;;) {
749 // do nothing and wait for the eventual... REBOOT
750 }
751 }
752}
753
754
755long HzToTimeDelay(long iHz)
756{
757 long retval = 0L;
758 retval = (long)((1000000.0 /(float)iHz) / 2.0);
759 return(retval);
760}
761
762long TimeDelayToHz(long tDelay)
763{
764 long retval = 0L;
765 retval = (long)(((1000000.0 /(float)tDelay)) / 2.0);
766 return(retval);
767}
768
769void rampDown(void)
770{
771 startDelay = HzToTimeDelay(globals.minStepperHz);
772 targetDelay = HzToTimeDelay(globals.maxStepperHz);
773 rampSteps = ((startDelay-targetDelay) * globals.microSteps);
774 startRampDown = rampSteps - 3L; // Steps to start ramping down - steps count down so we start at a high #
775 endRampUp = rampSteps -1L; // We don't want to Ramp Up as we are supposed to be moving
776 sDelay = targetDelay;
777 steps = rampSteps + 1L; // Run enough steps to stop gracefully
778}
779
780void rampUp(void)
781{
782 startDelay = HzToTimeDelay(globals.minStepperHz);
783 targetDelay = HzToTimeDelay(globals.maxStepperHz);
784 rampSteps = ((startDelay-targetDelay) * globals.microSteps);
785 startRampDown = 101L; // Steps to start ramping down - steps count down so we start at a high #
786 endRampUp = 103L; // We don't want to Ramp Up as we are supposed to be moving
787 sDelay = startDelay;
788 steps = rampSteps +100L;
789}
790
791void setSteps(long sSteps, int sWait)
792{
793int oldSpeed;
794
795 rampSteps = (long)(((float)sSteps / 2.0)); // the number of on/off cycles
796 startDelay = HzToTimeDelay(globals.minStepperHz);
797 targetDelay = HzToTimeDelay(globals.maxStepperHz);
798 if(((startDelay-targetDelay) * globals.microSteps) < rampSteps) // Don't go faster than the max stepper speed
799 rampSteps = ((startDelay-targetDelay) * globals.microSteps);
800 startRampDown = rampSteps; // Steps to start ramping down - steps count down so we start at a high #
801 endRampUp = (sSteps - rampSteps); // Steps to stop ramping up -- steps count down so we start at a high #
802 oldSpeed = sDelay; // save the old speed
803 sDelay = startDelay; // set starting delay
804 Timer1.initialize(sDelay); // set the interrupt timer
805 stepcount = 0L; // Zero the step counter
806 steps = sSteps; // GO for it
807 if(sWait){
808 while(steps){
809 ; // Wait until done
810 }
811 }
812 sDelay = oldSpeed;
813}
814
815void addDevice(char *pPrompt)
816{
817 const char noDevSig[] PROGMEM = NO_DEVICE_SIG; // clear the signature
818 Form addDeviceForm(lcd);
819 BoolField aConfirmField(addDeviceForm, pPrompt, yStr, nStr, false);
820 int event = LCD_BUTTON_NONE;
821 lcd.clear();
822 addDeviceForm.defaultField();
823 addDeviceForm.show();
824 while(event != LCD_BUTTON_SELECT){
825 event = lcd.getButton();
826 if (addDeviceForm.dispatch(event) == FORM_CHANGED) {
827 if (addDeviceForm.isCurrent(aConfirmField)) {
828 }
829 }
830 }
831 if (aConfirmField.value()){
832 int eOffset = sizeof(configuration) + (sizeof(globals) * configuration.numDevices);
833 if((eOffset + sizeof(globals))< 2048){ // Is there enough room in the EEPROM
834 configuration.currDevice = configuration.numDevices + 1; // Increment the device we are using
835 configuration.numDevices++; // Increment the Number of devices
836 eOffset += sizeof(globals);
837 EEPROM_writeAnything(0, configuration); // then update configuration in EEPROM
838 EEPROM_writeAnything(eOffset, globals); // then write new device to EEPROM
839 wdt_enable(WDTO_15MS); // REBOOT - turn on the WatchDog and don't stroke it.
840 for(;;) {
841 // do nothing and wait for the eventual... REBOOT
842 }
843 }
844 }
845}
846
847void eraseEeprom(char *sPrompt)
848{
849 const char noDevSig[] PROGMEM = NO_DEVICE_SIG; // clear the signature
850 Form eraseForm(lcd);
851 BoolField ConfirmField(eraseForm, sPrompt, yStr, nStr, false);
852 int event = LCD_BUTTON_NONE;
853 lcd.clear();
854 eraseForm.defaultField();
855 eraseForm.show();
856 while(event != LCD_BUTTON_SELECT){
857 event = lcd.getButton();
858 if (eraseForm.dispatch(event) == FORM_CHANGED) {
859 if (eraseForm.isCurrent(ConfirmField)) {
860 }
861 }
862 }
863 if (ConfirmField.value()){
864 EEPROM_writeAnything(0, noDevSig); // then write it to EEPROM we think there is no data there
865 wdt_enable(WDTO_15MS); // REBOOT - turn on the WatchDog and don't stroke it.
866 for(;;) {
867 // do nothing and wait for the eventual... REBOOT
868 }
869 }
870}
871void loadDevice(char *lPrompt)
872{
873 Form loadForm(lcd);
874 IntField devField(loadForm,"Device" , 0, (configuration.numDevices), 1, configuration.currDevice, "");
875 int event = LCD_BUTTON_NONE;
876 lcd.clear();
877 loadForm.defaultField();
878 loadForm.show();
879 //ConfirmField.setValue(0);
880 while(event != LCD_BUTTON_SELECT){
881 event = lcd.getButton();
882 if (loadForm.dispatch(event) == FORM_CHANGED) {
883 if (loadForm.isCurrent(devField)) {
884
885 }
886 }
887 }
888 if (devField.value() != configuration.currDevice){ // We changed the device
889 configuration.currDevice = devField.value(); // So set the current device
890 EEPROM_writeAnything(0, configuration); // then write it to EEPROM we think there is no data there
891 wdt_enable(WDTO_15MS); // REBOOT - turn on the WatchDog and don't stroke it.
892 for(;;) {
893 // do nothing and wait for the eventual... REBOOT
894 }
895 }
896}
897
898void doConfigMenu(void)
899{
900 int event = LCD_BUTTON_NONE;
901 Form configForm(lcd);
902 ListField goSpeedField(configForm,"<Set Speed>" ,TopMenu);
903 ListField goJogStepField(configForm,"<Jog Step>" ,TopMenu);
904 ListField goSetupField(configForm,"<Setup>" ,TopMenu);
905 ListField goDeviceField(configForm,"<Devices>",TopMenu);
906
907
908 lcd.clear();
909 configForm.defaultField();
910 configForm.show();
911 while(event != LCD_BUTTON_SELECT){
912 event = lcd.getButton();
913 if (configForm.dispatch(event) == FORM_CHANGED) {
914 if (configForm.isCurrent(goSpeedField)) {
915 goSetSpeed();
916 configForm.setCurrentField(&goSpeedField);
917 }
918 if (configForm.isCurrent(goJogStepField)) {
919 goSetJogStep();
920 configForm.setCurrentField(&goJogStepField);
921 }
922 if (configForm.isCurrent(goSetupField)) {
923 doSetupMenu();
924 configForm.setCurrentField(&goSetupField);
925 }
926 if (configForm.isCurrent(goDeviceField)) {
927 goDeviceMenu();
928 configForm.setCurrentField(&goDeviceField);
929 }
930 }
931 }
932}
933
934void goDeviceMenu(void)
935{
936
937 Form deviceForm(lcd);
938 BoolField cNewDevField(deviceForm, "New dev", yStr, nStr, false);
939 BoolField cLoadDevField(deviceForm, "Load dev", yStr, nStr, false);
940 BoolField cEraseDevField(deviceForm, "Erase all?", yStr, nStr, false);
941
942 int event = LCD_BUTTON_NONE;
943
944 lcd.clear();
945 deviceForm.defaultField();
946 deviceForm.show();
947 while(event != LCD_BUTTON_SELECT ){
948 event = lcd.getButton();
949 if (deviceForm.dispatch(event) == FORM_CHANGED) {
950 if (deviceForm.isCurrent(cNewDevField)) {
951 // New Device, create new globals,init it and use it
952 if (cNewDevField.value()){
953 addDevice("NEW Dev?");
954 deviceForm.setCurrentField(&cNewDevField);
955 cNewDevField.setValue(false);
956 }
957 }
958 if (deviceForm.isCurrent(cLoadDevField)) {
959 // Load Device and save it
960 loadDevice("LOAD Dev?");
961
962 deviceForm.setCurrentField(&cLoadDevField);
963 }
964 if (deviceForm.isCurrent(cEraseDevField)) {
965 // Erase Devicesand stat again
966 if (cEraseDevField.value()){
967 eraseEeprom("ERASE All?");
968 cEraseDevField.setValue(false);
969 deviceForm.setCurrentField(&cEraseDevField);
970 }
971 }
972 }
973 }
974}
975
976void setdeviceType(int dType)
977{
978 switch(dType){
979 case DEV_ROTARY:
980 mainForm.removeField(&goTravelField_mm);
981 break;
982 case DEV_LINEAR:
983 mainForm.removeField(&goAngleField);
984 mainForm.removeField(&goDivideField);
985 mainForm.removeField(&goConTurnField);
986
987 break;
988 }
989}
990
991String formatNumStr(long sNum)
992{
993 String numstr(sNum);
994 int slen = numstr.length();
995 String frac;
996 String whol;
997 if(slen <3){
998 switch(slen){
999 case 1:
1000 numstr = numstr +"00";
1001 break;
1002 case 2:
1003 numstr = numstr +"0";
1004 break;
1005 }
1006 numstr = "0." + numstr;
1007 }
1008 else{
1009 frac = numstr.substring(slen -3);
1010 whol = numstr.substring(0,slen -3);
1011 numstr =whol + "." + frac;
1012 }
1013 return numstr;
1014}
1015void printDistanceVals(long DistToTravel, int step)
1016{
1017 const char mmStr[] PROGMEM = "mm";
1018 const char stpStr[] PROGMEM = "Step:";
1019 const char posStr[] PROGMEM = "Pos :";
1020
1021 String dStr = formatNumStr(DistToTravel);
1022
1023 String mStr = formatNumStr(DistToTravel * (long) step);
1024 lcd.clear();
1025 lcd.setCursor(0,0);
1026 lcd.print(stpStr);
1027 lcd.print(step);
1028 lcd.print(" ");
1029 lcd.print(dStr);
1030 lcd.setCursor(0,1);
1031 lcd.print(posStr);
1032 lcd.print(mStr);
1033 lcd.print(mmStr);
1034}
1035
1036void doTravel(long idistance)
1037{
1038 int event = LCD_BUTTON_NONE;
1039 long tmpSteps = (long)((((float)idistance/1000.0 / (float)globals.TravelDistRev) * (float)globals.stepsPerRev)*1000.0);
1040 long moveCount = 0;
1041 printDistanceVals(idistance,moveCount);
1042 while(event != LCD_BUTTON_SELECT){
1043 event = lcd.getButton();
1044 if(event != LCD_BUTTON_NONE){
1045 switch(event){
1046 case LCD_BUTTON_LEFT:
1047 moveCount--;
1048 digitalWrite( globals.DirPin, ANTICLOCKWISE );
1049 setSteps(tmpSteps * 2, 1);
1050 printDistanceVals(idistance,moveCount);
1051 break;
1052 case LCD_BUTTON_RIGHT:
1053 moveCount++;
1054 digitalWrite( globals.DirPin, CLOCKWISE );
1055 setSteps(tmpSteps * 2, 1);
1056 printDistanceVals(idistance,moveCount);
1057 break;
1058 }
1059 }
1060 }
1061}
1062
1063void enterDistance(void)
1064{
1065 Form distanceForm(lcd);
1066 GetMicroField distField(distanceForm,"Dist" , 9999999, GETINTFIELD_READ_WRITE);
1067 int event = LCD_BUTTON_NONE;
1068 distField.setValue(distance);
1069 distanceForm.defaultField();
1070 distanceForm.show();
1071 while(event != LCD_BUTTON_SELECT){
1072 event = lcd.getButton();
1073 if (distanceForm.dispatch(event) == FORM_CHANGED) {
1074 if (distanceForm.isCurrent(distField)) {
1075 distance = distField.value();
1076 }
1077 }
1078 }
1079 if(distance)
1080 doTravel(distance);
1081 distanceForm.removeField(&distField);
1082}
1083
1084
1085/// --------------------------
1086/// Custom ISR Timer Routine
1087/// --------------------------
1088void timerIsr()
1089{
1090 // Toggle Stepper
1091 if(steps){
1092 state = state ^ 1;
1093 digitalWrite( globals.StepPin, state );
1094 if(!state){
1095 if(steps >= endRampUp){
1096 stepcount++; stepcount++;
1097 stepmod = (long)stepcount % (long)globals.microSteps;
1098 if(stepmod == 0){
1099 sDelay--;
1100 Timer1.initialize(sDelay); // set the interrupt timer 1 step slower (eg. increase the timer delay)
1101 }
1102 }
1103 else if(steps <= startRampDown){
1104 stepcount--; stepcount--;
1105 stepmod = ((long)stepcount % (long)globals.microSteps);
1106 if(stepmod == 0){
1107 sDelay++;
1108 Timer1.initialize(sDelay); // set the interrupt timer 1 step slower (eg. increase the timer delay)
1109 }
1110 }
1111 }
1112 steps--;
1113 if(!goinghome){
1114 if(state){
1115 if(digitalRead( globals.DirPin) == CLOCKWISE ){
1116 homePos++;
1117 if(globals.devType == DEV_ROTARY){ // Updated so as not to reset on a full revolution if a linear device
1118 if(homePos > (long)globals.stepsPerRev)
1119 homePos = 0L;
1120 }
1121 }
1122 else{
1123 homePos--;
1124 if(globals.devType == DEV_ROTARY){
1125 if(homePos < 0L)
1126 homePos = (long)globals.stepsPerRev;
1127 }
1128 }
1129 }
1130 }
1131 }
1132}