#include #include #include #include #include //#include //I like these definitions #define begin { #define end } //stepper motor states (Azimuth) #define ACOIL1 1 #define ACOIL2 2 #define ACOIL3 3 #define ACOIL4 4 // half step states (Azimuth) #define HACOIL13 6 #define HACOIL23 7 #define HACOIL24 8 #define HACOIL41 9 #define HACOIL1 10 #define HACOIL2 11 #define HACOIL3 12 #define HACOIL4 13 #define maxkeys 16 //timing definitions #define KEYCMDTIME 30 #define USERTIME 15 //keycmd state variables #define RELEASE 1 //the keycmd state variables #define DEBOUNCE 2 //keycmd debounces the keypad and reads a single character from the keypad #define STILLSAME 3 //using the function keypad() #define DEBOUNCERELEASE 4 #define DONE 5 #define TERMINATOR 6 #define TERMINATEDEBOUNCE 7 #define STILLSAMETERMINATE 8 #define STARkey 11 //keypad * key (used for - sign) #define ENTERkey 12 //keypad # key #define DECIMALkey 13 //keypad button A #define BACKkey 14 //keypad button B #define UPkey 15 //keypad button C #define DOWNkey 16 //keypad button D //userinput state variables #define START 1 #define IN_ITHACA 2 #define REQUEST_LAT 3 #define REQUEST_LONG 4 #define KEEP_LATLONG 5 #define REQUEST_DATE 6 #define REQUEST_TIME 7 #define REQUEST_TIMEZONE 8 #define REQUEST_DST 10 #define KEEP_STAR 11 #define SELECT_STAR 12 #define REQUEST_DEC 13 #define REQUEST_RASC 14 #define FAST_ROTATE 15 #define CALIBRATE 16 #define AUTO_TRACKING 17 #define ADJUST 18 #define MANUAL_TRACKING 19 #define MANUAL10_TRACKING 20 #define AUTO10_TRACKING 21 #define HALFSTEPANGLE 0.01125 #define FULLSTEPANGLE 0.0225 //calculate these later based on the pulley reduction #define ANGLE_TOLERANCE 0.5 #define FAST_ROTATE_SPEED 10 #define ADJUST_SPEED 25 //lower numbers are faster #define TRACKING_SPEED 2 //every 2.5 sidereal seconds #define ADJUST_ANGLE 0.5 #define pi 3.14159265 #define LCDwidth 16 #asm .equ __lcd_port=0x15 #endasm #include //LCD driver routines void motorControl(void); void keypad(void); void keycmd(void); void resetkeycmd(void); void userinput(void); void calclst(void); //float calcelev(float,float); float calcazim(float,float); //calcs the azim in the equatorial plane //int solartosidereal(char,char,char,char,char,char); void initialize(void); // global time variables unsigned long lst, lstq; //in seconds //add 365/366 = 0.99726775956284153005464480874317 for every (solar) second after this epoch //round result to the nearest second //alternatively, for every hour, we subtract 236 seconds //my calculations indicate that 1 year from the epoch, a float will have a //2 second accuracy (+/- 1 sec) //1/2 year is fine though... //A long (4 bytes) would be able to hold 4.29e9 seconds, or 136 years char trackingcount; // And yes, I know that our epoch *should* be the vernial equinox, because right ascension is taken from the // First Point of Aries at the Vernial Equinox, but the star chart I used had Nov 20, 8PM int mth,dd,yyyy,hh,mm,ss,ms; //local time variables - need this to compute LST int timezone; //-14 to +14 char leap, daysinmth; char dst; //1 if DST on, 0 if DST off //motor controls //unsigned int amotorclk; //timer for motor test unsigned char amotorstate, amotor; //state for motor test unsigned char amotordirection; //1 = CCW, 0= CW signed int amotorstepdur; // how often the motor position is updated unsigned char amotorhalfstep; //I/O variables unsigned int keyclk; //timing counters keycmd() unsigned int userclk; //timing counter for userinput() signed int motorclk; //timing counter for motorcontrol() char lcd_buffer[17]; // LCD display buffer //user input state variables unsigned char userstate; //user state machine state unsigned char retain; //flag for user retaining prev data unsigned char prevdata; //if there is any previous data stored unsigned char yesno; //1 if yes, 0 if no signed int star; //star number signed int scroll; //how much to scroll the star coordinates signed int scroll_star; //scrolled star number (what to print) flash char *starlist[18]; //star calculation variables float starlistrasc[18]; //right ascension of the star float starlistdec[18]; //declination of the star float rasc, dec; //right ascension (in hours) and declination (in degrees) of the selected star // global position variables float latitude, longitude, current_elev, current_azim, desired_azim, real_elev; //in equatorial plane. reals are in viewer's plane signed int numsteps, numhalfsteps; unsigned char stepcalculated; signed int calstep; // unsigned char noprevlat, noprevlong, noprevstar, noprevtime; //flags for individual previous data set // unsigned char keeplat, keeplong, keepstar, keeptime; //flags to determine if prev data should be kept // //parameters set by the user for lat, long, elev, azi // //these are used to calculate the delME and delMA for which the motor is stepped through // float latitude, longitude, lst, elev, azi, MotorE, MotorA, delME, delMA; // //azimuth and elevation wrt equatorial? // float azim_equat, elev_equat; // //X,Y,Z coordinate arrays // float S[3],Sequat[3]; // //right acension and declination of Star // float rtasc,dec; // //change in elevation and azimuth that has to be stepped through // float deltaelev, deltaazim; // int scroll; //********************** keypad variables ******************************* unsigned char key, butnum; //key: the signal of the key pressed; butnum: the value of the key pressed unsigned char keycmdstate; //used to determine the state of the keypad unsigned char maybe; //used to store debouncing information for the key press unsigned char keycount; //position in the character string char keystr[16]; //character string unsigned char decimal; unsigned char keyready; //flag for keycmd() to tell query() that a string has been read flash unsigned char keytbl[16]= {0x7d, 0xee, 0xed, 0xeb, 0xde, 0xdd, 0xdb, 0xbe, 0xbd, 0xbb, 0x7e, 0x7b, 0xe7, 0xd7, 0xb7, 0x77}; interrupt [TIM0_COMP] void timer0_compare(void) //counts every ms { //Decrement the time if it is not already zero if (motorclk>0) --motorclk; if (keyclk>0) --keyclk; if (userclk>0) --userclk; ms++; if (ms == 1000) begin ms = 0; ss++; if (ss == 60) begin ss = 0; mm++; if (mm == 60) begin mm = 0; hh++; if (hh == 24) begin hh = 0; dd++; if (((dd==32) && (mth%2 == 1) && (mth<8)) || ((dd==29) && (mth==2) && (leap==0)) || ((dd==30) && (mth==2) && (leap==1)) || ((dd==32) && (mth%2 == 0) && (mth>7)) || ((dd==31) && (mth%2 == 0) && (mth<8)) || ((dd==31) && (mth%2 == 1) && (mth>7))) begin //jan, mar, may, jul //feb //feb (leap) //aug,oct,dec //feb is out alr, so apr,jun //sep,nov dd = 0; mth++; if (mth == 13) begin mth = 0; yyyy++; end //yr end //mth end //day end //hr end //min end //sec } interrupt [TIM1_COMPA] void timer1a_compare(void) //counts every 1/1000 sidereal second { lstq++; if(lstq==1000) begin lst++; lstq=0; end if (lst == 86400) lst = 0; if (((lst*1000 + lstq)%2699 == 0) && ((userstate == AUTO_TRACKING) || (userstate == MANUAL_TRACKING))) begin motorControl(); //moves the motor once every 2.7 sidereal seconds (we should be doing once every 2.69999 sidereal seconds end if (((lst*1000 + lstq)%270 == 0) && ((userstate == AUTO10_TRACKING) || (userstate == MANUAL10_TRACKING))) motorControl(); //moves the motor 3.7 steps every sidereal second (1 step every 0.27 sec) } void main(void) begin initialize(); //main task scheduler loop while(1) { if((motorclk==0) && ((userstate == ADJUST) || (userstate == FAST_ROTATE))) begin if (numsteps < 0) begin amotorhalfstep = 0; amotordirection = 1; //CCW motorControl(); numsteps++; end else if (numsteps > 0) begin amotorhalfstep = 0; amotordirection = 0; //CW motorControl(); numsteps--; end end if(keyclk == 0) keycmd(); if(userclk==0) userinput(); //the clock ticks to 0 (which is every 1ms) //set motor timers (amotorstepdur), set motorclk. speed up, slow down //calc the speed the motor needs to turn to reach the final dest. //How the motor control works: //The ADJUST and FAST ROTATE states will set desired_azim at some offset away from current_azim //if we are in these states, the while loop will calculate the number of steps required to move //to the final destination. //We then call the motorControl() numsteps times, at the amotorstepdur interval, decrementing //numsteps at each call (or incrementing if CCW). //In ADJUST mode, we recalculate numsteps everyting the user adjusts the desired azimuth if((userstate == ADJUST) || (userstate == FAST_ROTATE)) begin //numsteps < 0 => move CCW //numsteps > 0 => move CW if (fabs(desired_azim - current_azim) < 180) begin if ((desired_azim - current_azim) >= ANGLE_TOLERANCE) begin //there may be a bug if we cross 360 deg... //calculate leftover number of steps if (stepcalculated == 0) begin //if we havent already calculated the number of steps numsteps = (int)((float)(desired_azim - current_azim)/FULLSTEPANGLE); stepcalculated = 1; end end else if ((current_azim - desired_azim) >= ANGLE_TOLERANCE) begin //calculate leftover number of steps if (stepcalculated == 0) begin numsteps = (int)((float)(desired_azim - current_azim)/FULLSTEPANGLE); //this will be a negative number (move CCW) stepcalculated = 1; end end end else begin //360 = 0 deg //for eg if desired = 358 deg, and current is 1 deg, we cant to move CCW 3 deg not CW 357 deg if ((desired_azim > current_azim) && ((360 - desired_azim + current_azim) >= ANGLE_TOLERANCE)) begin //there may be a bug if we cross 360 deg... //calculate leftover number of steps if (stepcalculated == 0) begin //if we havent already calculated the number of steps numsteps = (int)((float)(desired_azim - 360 - current_azim)/FULLSTEPANGLE); //negative number (move CCW) stepcalculated = 1; end end //for eg if desired = 1 deg, and current is 358 deg, we cant to move CW 3 deg not CCW 357 deg else if ((desired_azim < current_azim) && ((360 - current_azim + desired_azim) >= ANGLE_TOLERANCE)) begin //calculate leftover number of steps if (stepcalculated == 0) begin numsteps = (int)((float)(desired_azim + 360 - current_azim)/FULLSTEPANGLE); stepcalculated = 1; end end end end if (userstate == CALIBRATE) begin //disable the motor control by setting amotorstepdur = -1 and motorclk = -1 //use the userstate to call motorControl end if ((userstate == AUTO_TRACKING) || (userstate == MANUAL_TRACKING)) begin //disable the motor control by setting amotorstepdur = -1 and motorclk = -1 //use the interrupt to call the motor control end } end void motorControl(void) { motorclk = amotorstepdur; PORTD.0 = 1; //enable motor control // full step: 1->3->2->4->1 (CW) or 1->4->2->3->1 (CCW) // half step: 1->13->3->23->2->24->4->41->1 (CW) or 1->41->4->24->2->23->3->13->1 if (userstate != CALIBRATE) begin //adjust azim variables if not in CALIBRATE mode if (amotorhalfstep == 0) begin //full steps if (amotordirection == 0) begin //CW current_azim = current_azim + FULLSTEPANGLE; if (current_azim >= 360) current_azim = current_azim - 360; end else begin //CCW current_azim = current_azim - FULLSTEPANGLE; if (current_azim < 0) current_azim = current_azim + 360; end end else begin //half steps if (amotordirection == 0) begin //CW current_azim = current_azim + HALFSTEPANGLE; if (current_azim >= 360) current_azim = current_azim - 360; end else begin //CCW current_azim = current_azim - HALFSTEPANGLE; if (current_azim < 0) current_azim = current_azim + 360; end end end switch(amotorstate) begin case ACOIL1: amotor = 0x3 ; if (amotorhalfstep == 0) begin if (amotordirection == 0) amotorstate = ACOIL3; else amotorstate = ACOIL4; end else begin if (amotordirection == 0) amotorstate = HACOIL13; //change this!!! else amotorstate = HACOIL41; //change this!!...see dir end break; case ACOIL2: amotor = 0x5; if(amotorhalfstep == 0) begin if (amotordirection == 0) amotorstate = ACOIL4; else amotorstate = ACOIL3; end else begin if (amotordirection == 0) amotorstate = HACOIL24; //change this!!! else amotorstate = HACOIL23; //change this!!...see dir end break; case ACOIL3: amotor = 0x9; if(amotorhalfstep == 0) begin if (amotordirection == 0) amotorstate = ACOIL2; else amotorstate = ACOIL1; end else begin if (amotordirection == 0) amotorstate = HACOIL23; //change this!!! else amotorstate = HACOIL13; //change this!!...see dir end break; case ACOIL4: amotor= 0x11; if(amotorhalfstep == 0)begin if (amotordirection == 0) amotorstate = ACOIL1; else amotorstate = ACOIL2; end else begin if (amotordirection == 0) amotorstate = HACOIL41; //change this!!! else amotorstate = HACOIL24; //change this!!...see dir end break; case HACOIL1: amotor = 0x3; if(amotorhalfstep == 0) begin if(amotordirection == 0) amotorstate = ACOIL3; else amotorstate = ACOIL4; end else begin if(amotordirection == 0) amotorstate = HACOIL13; else amotorstate = HACOIL41; end break; case HACOIL13: amotor = 0xb; // 11 -> 1011 -> b if(amotorhalfstep == 0) begin if(amotordirection == 0) amotorstate = ACOIL3; else amotorstate = ACOIL1; end else begin if(amotordirection == 0) amotorstate = HACOIL3; else amotorstate = HACOIL1; end break; case HACOIL2: amotor = 0x5; if(amotorhalfstep == 0) begin if (amotordirection == 0) amotorstate = ACOIL4; else amotorstate = ACOIL3; end else begin if (amotordirection == 0) amotorstate = HACOIL24; else amotorstate = HACOIL23; end break; case HACOIL23: amotor = 0xd; // 11 -> 1101 -> d if(amotorhalfstep == 0) begin if(amotordirection == 0) amotorstate = ACOIL2; else amotorstate = ACOIL3; end else begin if(amotordirection == 0) amotorstate = HACOIL2; else amotorstate = HACOIL3; end break; case HACOIL3: amotor = 0x9; if(amotorhalfstep == 0) begin if (amotordirection == 0) amotorstate = ACOIL2; else amotorstate = ACOIL1; end else begin if (amotordirection == 0) amotorstate = HACOIL23; else amotorstate = HACOIL13; end break; case HACOIL24: amotor = 0x15; // 11 -> 10101 -> 15 if(amotorhalfstep == 0) begin if(amotordirection == 0) amotorstate = ACOIL4; else amotorstate = ACOIL2; end else begin if(amotordirection == 0) amotorstate = HACOIL4; else amotorstate = HACOIL2; end break; case HACOIL4: amotor= 0x11; if(amotorhalfstep == 0)begin if (amotordirection == 0) amotorstate = ACOIL1; else amotorstate = ACOIL2; end else begin if (amotordirection == 0) amotorstate = HACOIL41; else amotorstate = HACOIL24; end break; case HACOIL41: amotor = 0x13; // 11 -> 10011 -> 13 if(amotorhalfstep == 0) begin if(amotordirection == 0) amotorstate = ACOIL1; else amotorstate = ACOIL4; end else begin if(amotordirection == 0) amotorstate = HACOIL1; else amotorstate = HACOIL4; end break; end PORTD = amotor; } void keypad(void) { //get lower nibble DDRA = 0x0f; // use PORTA as the input for the keypad PORTA = 0xf0; delay_us(5); key = PINA; //get upper nibble DDRA = 0xf0; PORTA = 0x0f; delay_us(5); key = key | PINA; //find matching keycode in keytbl if (key != 0xff){ for (butnum=0; butnum= 360) desired_azim = desired_azim - 360; lcd_gotoxy(0,1); sprintf(lcd_buffer,"C%5.2f,%5.2f",desired_azim,current_azim); lcd_puts(lcd_buffer); stepcalculated = 0; end else if (scroll == -1) begin scroll = 0; desired_azim = desired_azim - ADJUST_ANGLE; if (desired_azim < 0) desired_azim = desired_azim + 360; lcd_gotoxy(0,1); sprintf(lcd_buffer,"A%5.2f,%5.2f",desired_azim,current_azim); lcd_puts(lcd_buffer); stepcalculated = 0; end else if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = MANUAL_TRACKING; amotorstepdur = -1; //disable motor motorclk = -1; amotorhalfstep = 1; amotordirection = 0; //CW - opposite to earth's rotation end else userstate = ADJUST; end lcd_gotoxy(0,1); sprintf(lcd_buffer," %5.2f,%5.2f",desired_azim,current_azim); lcd_puts(lcd_buffer); break; case IN_ITHACA: lcd_gotoxy(0,0); lcd_putsf("In Ithaca?(1,0)"); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = REQUEST_DATE; latitude = 42.44; longitude = -76.48; end else if (yesno == 0) begin userstate = REQUEST_LAT; end else userstate = IN_ITHACA; end break; case REQUEST_LAT: lcd_gotoxy(0,0); lcd_putsf("Enter Latitude: "); if (keyready == 1) begin latitude = atof(keystr); resetkeycmd(); if ((latitude < -90.0) || (latitude > 90.0)) begin userstate = REQUEST_LAT; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin userstate = REQUEST_LONG; lcd_gotoxy(0,1); lcd_putsf("Lat="); sprintf(lcd_buffer,"%5.2f",latitude); lcd_puts(lcd_buffer); end end break; case REQUEST_LONG: lcd_gotoxy(0,0); lcd_putsf("Enter Longitude:"); if (keyready == 1) begin longitude = atof(keystr); resetkeycmd(); if ((latitude < -180.0) || (latitude > 180.0)) begin userstate = REQUEST_LONG; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin userstate = REQUEST_DATE; lcd_gotoxy(0,1); lcd_putsf("Long="); sprintf(lcd_buffer,"%5.2f",longitude); lcd_puts(lcd_buffer); end end break; case KEEP_LATLONG: lcd_gotoxy(0,0); lcd_putsf("KeepLatLong? 1,0"); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = KEEP_STAR; end else if (yesno == 0) begin userstate = IN_ITHACA; end else userstate = KEEP_LATLONG; end break; case REQUEST_DATE: lcd_gotoxy(0,0); lcd_putsf("Date in MMDDYYYY"); if (keyready == 1) begin sscanf(keystr,"%2d%2d%4d",&mth, &dd, &yyyy); resetkeycmd(); if (yyyy%4==0) begin //calc if yr is leap if (yyyy%100==0 && yyyy%400==0) leap = 1; else if (yyyy%100==0 && yyyy%400!=0) leap = 0; else leap = 1; end else leap = 0; if ((mth%2 == 1) && (mth<8)) daysinmth = 31; //jan,mar,may,jul else if ((mth==2) && (leap==0)) daysinmth = 28; //feb else if ((mth==2) && (leap==1)) daysinmth = 29; //feb (leap yr) else if ((mth%2 == 0) && (mth>7)) daysinmth = 31; //aug,oct,dec else if ((mth%2 == 0) && (mth<8)) daysinmth = 30; //feb is out alr, so apr,jun else if ((mth%2 == 1) && (mth>7)) daysinmth = 31; //sep,nov if ((dd < 1) || (dd > daysinmth) || (mth < 1) || (mth > 12) || (yyyy < 2007) || (yyyy > 2010)) begin userstate = REQUEST_DATE; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin userstate = REQUEST_TIME; lcd_gotoxy(0,1); lcd_putsf("Date="); sprintf(lcd_buffer,"%2d,%2d,%4d",mth,dd,yyyy); lcd_puts(lcd_buffer); end end break; case REQUEST_TIME: lcd_gotoxy(0,0); lcd_putsf("Time in HHMMSS "); if (keyready == 1) begin sscanf(keystr,"%2d%2d%2d",&hh, &mm, &ss); resetkeycmd(); if ((hh < 0) || (hh > 23) || (mm < 0) || (mm > 59) || (ss < 0) || (ss > 59)) begin userstate = REQUEST_TIME; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin userstate = REQUEST_TIMEZONE; lcd_gotoxy(0,1); lcd_putsf("Time="); sprintf(lcd_buffer,"%2d:%2d:%2d",hh,mm,ss); lcd_puts(lcd_buffer); end end break; case REQUEST_TIMEZONE: lcd_gotoxy(0,0); lcd_putsf("Timezone[-14,14]"); if (keyready == 1) begin sscanf(keystr,"%d",&timezone); resetkeycmd(); if ((timezone<-14) || (timezone>14)) begin userstate = REQUEST_TIMEZONE; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin userstate = REQUEST_DST; lcd_gotoxy(0,1); lcd_putsf("Timezone="); if (timezone>0) sprintf(lcd_buffer,"+%d",timezone); else sprintf(lcd_buffer,"%d",timezone); lcd_puts(lcd_buffer); end end break; case REQUEST_DST: lcd_gotoxy(0,0); lcd_putsf("DST On=1 Off=0 "); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = SELECT_STAR; //timezone++; hh--; if (hh<0){ dd--; hh = 23; if (dd<0){ mth--; if ((mth%2 == 1) && (mth<8)) daysinmth = 31; //jan,mar,may,jul else if ((mth==2) && (leap==0)) daysinmth = 28; //feb else if ((mth==2) && (leap==1)) daysinmth = 29; //feb (leap yr) else if ((mth%2 == 0) && (mth>7)) daysinmth = 31; //aug,oct,dec else if ((mth%2 == 0) && (mth<8)) daysinmth = 30; //feb is out alr, so apr,jun else if ((mth%2 == 1) && (mth>7)) daysinmth = 31; //sep,nov dd = daysinmth; if (mth<0){ yyyy--; mth = 12; } } } calclst(); end else if (yesno == 0) begin userstate = SELECT_STAR; calclst(); end else userstate = REQUEST_DST; end break; case KEEP_STAR: lcd_gotoxy(0,0); lcd_putsf("KeepPrevStar?1,0"); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = CALIBRATE; calstep = 0; amotorstepdur = -1; motorclk = -1; //disable motor end else if (yesno == 0) begin userstate = SELECT_STAR; end else userstate = KEEP_STAR; end break; case SELECT_STAR: lcd_gotoxy(0,0); lcd_putsf("CD=scroll,0=user"); lcd_gotoxy(0,1); //sprintf(lcd_buffer,"%s",starlist[scroll_star]); //strcpy(lcd_buffer,starlist[scroll_star]); //lcd_putsf(starlist[scroll_star]); if (scroll == 1) begin scroll = 0; if(scroll_star<17) scroll_star++; lcd_gotoxy(0,1); //sprintf(lcd_buffer,"%s",starlist[scroll_star]); lcd_putsf(starlist[scroll_star]); end else if (scroll == -1) begin scroll = 0; if(scroll_star>0) scroll_star--; lcd_gotoxy(0,1); //sprintf(lcd_buffer,"%s",starlist[scroll_star]); lcd_putsf(starlist[scroll_star]); end else if (keyready == 1) begin sscanf(keystr,"%d",&star); resetkeycmd(); if (star == 0) begin userstate = REQUEST_DEC; end else if ((star > 18) || (star < 0)) begin userstate = SELECT_STAR; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin //load the declination and right ascension values rasc = starlistrasc[star-1]; dec = starlistdec[star-1]; lcd_gotoxy(0,1); //sprintf(lcd_buffer,"%s",starlist[star-1]); //this doesn't work //lcd_putsf(starlist[star-1]); //might want to try starlist[star-1] directly sprintf(lcd_buffer,"R=%5.2fD=%5.2f",rasc,dec); lcd_puts(lcd_buffer); //CALCULATE THE DESIRED ELEV AND AZIM desired_azim = calcazim(dec,rasc); if (real_elev < 0) begin lcd_gotoxy(0,1); lcd_putsf("STAR NOT VISIBLE"); userstate = SELECT_STAR; end else begin lcd_gotoxy(0,1); lcd_putsf(" "); amotorstepdur = FAST_ROTATE_SPEED; motorclk = FAST_ROTATE_SPEED; //reset motor userstate = FAST_ROTATE; stepcalculated = 0; numsteps = 0; end end end break; case REQUEST_DEC: lcd_gotoxy(0,0); lcd_putsf("Declination(deg)"); if (keyready == 1) begin dec = atof(keystr); resetkeycmd(); if ((dec < -90.0) || (dec > 90.0)) begin userstate = REQUEST_DEC; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin userstate = REQUEST_RASC; lcd_gotoxy(0,1); lcd_putsf("Dec="); sprintf(lcd_buffer,"%5.2f",dec); lcd_puts(lcd_buffer); end end break; case REQUEST_RASC: lcd_gotoxy(0,0); lcd_putsf("Rt Ascension(hr)"); if (keyready == 1) begin rasc = atof(keystr); resetkeycmd(); if ((rasc < 0) || (rasc > 24)) begin userstate = REQUEST_RASC; lcd_gotoxy(0,1); lcd_putsf("Invalid. "); end else begin lcd_gotoxy(0,1); lcd_putsf("RtAsc="); sprintf(lcd_buffer,"%5.2f",rasc); lcd_puts(lcd_buffer); //CALCULATE THE DESIRED ELEV AND AZIM desired_azim = calcazim(dec,rasc); if (real_elev < 0) begin lcd_gotoxy(0,1); lcd_putsf("STAR NOT VISIBLE"); userstate = REQUEST_DEC; end else begin amotorstepdur = FAST_ROTATE_SPEED; motorclk = FAST_ROTATE_SPEED; userstate = FAST_ROTATE; stepcalculated = 0; numsteps = 0; end end end break; case FAST_ROTATE: lcd_gotoxy(0,0); lcd_putsf("WAIT... "); lcd_gotoxy(0,1); sprintf(lcd_buffer,"%5.2f,%5.2f",desired_azim,current_azim); lcd_puts(lcd_buffer); if ((fabs(desired_azim - current_azim) < ANGLE_TOLERANCE)) begin //MOD!! userstate = CALIBRATE; calstep = 0; amotorstepdur = -1; motorclk = -1; //disable motor end else userstate = FAST_ROTATE; if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = CALIBRATE; calstep = 0; amotorstepdur = -1; motorclk = -1; //disable motor end end break; case CALIBRATE: lcd_gotoxy(0,0); lcd_putsf("Move(C,D),1=Done"); if (scroll == 1) begin scroll = 0; //FIGURE OUT HOW TO CONTROL THE MOTOR!!!! calstep--; lcd_gotoxy(0,1); sprintf(lcd_buffer,"CCW-step=%d ",calstep); lcd_puts(lcd_buffer); amotorhalfstep = 1; amotordirection = 1; motorControl(); end else if (scroll == -1) begin scroll = 0; calstep++; lcd_gotoxy(0,1); sprintf(lcd_buffer,"CW-step=%d ",calstep); lcd_puts(lcd_buffer); amotorhalfstep = 1; amotordirection = 0; motorControl(); end else if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = AUTO_TRACKING; //motor already disabled... amotorhalfstep = 1; amotordirection = 0; //CW - opposite to earth's rotation end else userstate = CALIBRATE; end break; case AUTO_TRACKING: lcd_gotoxy(0,0); lcd_putsf("Aut 1=Stop 0=10x"); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = START; prevdata = 1; end else if (yesno == 0) userstate = AUTO10_TRACKING; else userstate = MANUAL_TRACKING; end break; case MANUAL_TRACKING: lcd_gotoxy(0,0); lcd_putsf("Man 1=Stop 0=10x"); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = START; //prevdata = 0; end else if (yesno == 0) userstate = MANUAL10_TRACKING; else userstate = MANUAL_TRACKING; end break; case AUTO10_TRACKING: lcd_gotoxy(0,0); lcd_putsf("Auto 1=1x "); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = AUTO_TRACKING; end else userstate = AUTO10_TRACKING; end break; case MANUAL10_TRACKING: lcd_gotoxy(0,0); lcd_putsf("Manual 1=1x "); if (keyready == 1) begin sscanf(keystr,"%d",&yesno); resetkeycmd(); if (yesno == 1) begin userstate = MANUAL_TRACKING; end else userstate = MANUAL10_TRACKING; end break; } } //userinput float calcazim(float de,float ra) { float elev, azim, elev_rad, azim_rad, de_rad, ra_rad; float second_angle, second_angle_rad; float S[3], S_eq[3]; float lengthS; second_angle = (float)lst - ra*240; //ra must be converted to seconds (of time - 15 deg to 1 hr) de_rad = de*pi/180; ra_rad = ra*pi/180; second_angle_rad = second_angle*pi/43200; //1 hr of time = 15 deg = 3600 sec *15/3600 to get degrees *pi/180 to get rad elev_rad = asin((sin(latitude*pi/180)*sin(de_rad)) + (cos(latitude*pi/180)*cos(de_rad)*cos(second_angle_rad))); azim_rad = atan2((-cos(de_rad)*sin(second_angle_rad)), (cos(latitude*pi/180)*sin(de_rad) - sin(latitude*pi/180)*cos(de_rad)*cos(second_angle_rad))); elev = elev_rad*180/pi; azim = azim_rad*180/pi; if (azim<0) azim = azim + 360; if (azim >= 360) azim = azim - 360; //printf("Elevation=%f\n",elev); // how do we check if the star is viewable? real_elev = elev; // perform coordinate rotation... (see proj proposal) S[0] = sin(azim*pi/180); S[1] = cos(azim*pi/180); S[2] = sin(elev*pi/180); lengthS = sqrt(S[0]*S[0] + S[1]*S[1] + S[2]*S[2]); S[0] = S[0]/lengthS; S[1] = S[1]/lengthS; S[2] = S[2]/lengthS; S_eq[0] = S[0]; S_eq[1] = cos(-latitude*pi/180)*S[1] + sin(-latitude*pi/180)*S[2]; S_eq[2] = -sin(-latitude*pi/180)*S[1] + cos(-latitude*pi/180)*S[2]; elev = 180*atan(S_eq[2])/pi; azim = 180*atan2(S_eq[0],S_eq[1])/pi; if (azim<0) azim = azim + 360; if (azim >= 360) azim = azim - 360; return azim; } //takes in the solar time variables and calculates the local sidereal time //the greenwich sidereal time at our 1 Jan 2007 12AM GMT epoch is 6:41:04.3 void calclst(void) { int n; //loop variable int numleap = 0; long numdays = 0; char currentyrleap = 0; float lsttemp = 0; long secondoffset; //calculate the number of sidereal seconds passed from the 1 Jan 2007 12AM GMT epoch //the greenwich sidereal time at our 1 Jan 2007 12AM GMT epoch is 6:38:18.1 //For each additional day, add 00:03:56. (that is, 236 seconds) as a reasonable approximation. //Add the time from midnight of your local time, add 10 seconds for each hour //(240 seconds for each 24 hours). This is the Greenwich Sidereal Time. //======== calculate number of days since Jan 1, 2007 ========== // calculate the number of leap years for the years in between 2007 and the curent yr // not including 2007 and the current year if (yyyy > 2008) begin //2009 or later add number of days in the years 2008...yyyy-1 for (n=2008; n 2007) begin //2008 and later add the 365 days in 2007 numdays += 365; end //for all years 2007 or later add the days in the year up to the current date if (((yyyy%4==0) && (yyyy%100!=0)) || ((yyyy%400==0))) currentyrleap = 1; numdays += dd; if (mth > 1) numdays += 31; if ((mth > 2) && (currentyrleap == 1)) numdays += 29; if ((mth > 2) && (currentyrleap == 0)) numdays += 28; if (mth > 3) numdays += 31; if (mth > 4) numdays += 30; if (mth > 5) numdays += 31; if (mth > 6) numdays += 30; if (mth > 7) numdays += 31; if (mth > 8) numdays += 31; if (mth > 9) numdays += 30; if (mth > 10) numdays += 31; if (mth > 11) numdays += 30; //if the mth is dec, we will enter every single if statement // convert this number of days to sidereal seconds // each solar day is 366.25/365.25*24*60*60 sidereal seconds = 86636.55031 sidereal seconds lsttemp = 86636.55031*numdays; lsttemp += 3609.856263*(hh - timezone); lsttemp += 60.16427105*mm; lsttemp += 1.002737851*ss; secondoffset = (long)(longitude*240); //offset greenwich sidereal time to the local longitude lst = (long)(fmod(23898.1 + lsttemp + secondoffset,86400)); // 6:38:18.1 = 23898.1 sec } void initialize(void) { int i; DDRD = 0xff; //PORTD = Motor output DDRA = 0x00; //PORTA = keypad input DDRC = 0xff; //PORTC = LCD output //TIMSK = 0x2; TIMSK = 0x12; //turn on timer 0 output compare match ISR (bit 1 - Manual p80) //turn on timer 1 output compare match A OCR0 = 249; //set the compare to 250 time ticks. (1ms) TCCR0 = 0b00001011; //prescalar to 64 (clk/64: count every 4us) and turn on clear-on-match // 1 sidereal second = 0.99726 seconds // 1 sidereal ms = 0.0009972677 sec = 15956.28415 counts at 62.5ns per count (prescalar = clk/1) OCR1AH = 0x3e; OCR1AL = 0x53; //reset every 15956 counts - i.e, 1/1000 sidereal second. //We gain 0.28415*62.5ns every tick, or 0.63934s every 10 hours TCCR1A = 0; TCCR1B = 0b00001001; //prescalar to 1 - increment every 62.5 ns //init the LCD lcd_init(LCDwidth); //initialize the LCD display lcd_clear(); lcd_putsf("Hi"); //keypad initialization butnum=0; keycmdstate=RELEASE; keycount=0; for (i=0;i<16;i++) keystr[i]=0; keyready=0; //init keycmd variables keyclk = KEYCMDTIME; scroll = 0; decimal = 0; star = -1; scroll_star = 0; //polaris //init motor variables amotorstepdur = 25; //start at 200 ms per step first motorclk = -1; //so that the motor does not move at all amotorstate = HACOIL1; amotorhalfstep = 1; amotordirection = 0; //init userinput variables userstate = START; userclk = USERTIME; // global positioning variables latitude = 42.44; longitude = -76.48; current_elev = 0; real_elev = 0; current_azim = 0; desired_azim = 0; numsteps = 0; numhalfsteps = 0; stepcalculated = 0; calstep=0; //runtime = -1; //so that the motor does not move yet // global timing variables lst = 0; //in seconds from the Nov 20, 2006, 8PM local standard time epoch //add 365/366 = 0.99726775956284153005464480874317 for every (solar) second after this epoch //round result to the nearest second //alternatively, for every hour, we subtract 236 seconds //my calculations indicate that 1 year from the epoch, a float will have a //2 second accuracy (+/- 1 sec) //1/2 year is fine though... lstq=0; trackingcount = 0; mth = 11; //init to Nov 11, 2006, 8PM EST dd = 20; yyyy = 2006; hh = 20; mm = 0; ss = 0; //local time variables - need this to compute LST ms = 0; daysinmth = 30; //november timezone = -5; //-14 to +14 dst = 0; //1 if DST on, 0 if DST off leap = 0; // star list starlist[0] = "1.Polaris \0"; starlist[1] = "2.Alcor-Ursa Maj\0"; starlist[2] = "3.Algol-Perseus \0"; starlist[3] = "4.Arcturus \0"; starlist[4] = "5.A-Aquarius \0"; starlist[5] = "6.Betelgeuse \0"; starlist[6] = "7.Capella-Auriga\0"; starlist[7] = "8.Dubhe-Ursa Maj\0"; starlist[8] = "9.Eltanin-Draco \0"; starlist[9] = "10.E-Sagittarius\0"; starlist[10] = "11.Markab-Pegsus\0"; starlist[11] = "12.Mirach-Androm\0"; starlist[12] = "13.Pleiades-Leo \0"; starlist[13] = "14.Pollux-Gemini\0"; starlist[14] = "15.Regulus-Leo \0"; starlist[15] = "16.Rigel-Orion \0"; starlist[16] = "17.Sirius \0"; starlist[17] = "18.Vega-Lyra \0"; //star variables //declination of the star (deg) starlistdec[0] = 90; starlistdec[1] = 55; starlistdec[2] = 41; starlistdec[3] = 19; starlistdec[4] = 0; starlistdec[5] = 7; starlistdec[6] = 46; starlistdec[7] = 62; starlistdec[8] = 51; starlistdec[9] = -35; starlistdec[10] = 15; starlistdec[11] = 36; starlistdec[12] = 24; starlistdec[13] = 28; starlistdec[14] = 12; starlistdec[15] = -9; starlistdec[16] = -17; starlistdec[17] = 39; //right ascension of the star (degrees) starlistrasc[0] = 37.25; starlistrasc[1] = 201.25; starlistrasc[2] = 47; starlistrasc[3] = 213.75; starlistrasc[4] = 331.25; starlistrasc[5] = 88.75; starlistrasc[6] = 79; starlistrasc[7] = 165.75; starlistrasc[8] = 268.75; starlistrasc[9] = 376.25; starlistrasc[10] = 346; starlistrasc[11] = 17.25; starlistrasc[12] = 56.25; starlistrasc[13] = 116.25; starlistrasc[14] = 152; starlistrasc[15] = 78.5; starlistrasc[16] = 101.25; starlistrasc[17] = 279; //right ascension (in degrees) and declination (in degrees) of the selected star rasc = 37.25; dec = 90; // noprevlat = 1; // noprevlong = 1; // noprevtime = 1; // noprevstar = 1; // keeplat = 0; // keeplong = 0; // keeptime = 0; // keepstar = 0; // elev_equat = 0; // azim_equat = 0; // latitude = 0; // longitude = 0; // lst = 0; // elev = 0; // azi = 0; // MotorE = 0; // MotorA = 0; // delME = 0; // delMA = 0; // rtasc = 0; // dec = 0; // for (i=0;i<3;i++){ // S[i]=0; // Sequat[i]= 0; // } #asm sei #endasm }