// Adam Davenport - goWeather #include // PIC header #include // delays header #include // Portb utilities #include // timer header #include // ADC header #include "xlcd.h" // XLCD header must modify the following two lines in header file #define BAR_1 8 // Define for bar characters #define BAR_2 9 // Define for bar characters #define BAR_3 10 // Define for bar characters #define BAR_4 11 // Define for bar characters #define BAR_5 12 // Define for bar characters #define BAR_6 13 // Define for bar characters #define BAR_7 14 // Define for bar characters #define Button PORTAbits.RA2 // Define for button tact switch #define LCD PORTAbits.RA3 // Define for LCD transistor switch #define Pressure PORTAbits.RA1 // Define for Pressure transistor switch #define LED PORTAbits.RA5 // Define for the Red LED void MakeBars(void); // MakeBars prototype to make bar characters int Find_Slope(void); // calculate slope of data prototype void timer1_isr(void); // timer1 interupt service routine //////////////////////////////////////////////////////////////////////////////// // The following declarations create the special bar characters for the display // each bit corresponds to a single pixel of a particular character on the LCD // a 1 is a dark pixel and a 0 is no pixel //////////////////////////////////////////////////////////////////////////////// unsigned char rom bar1[] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b00000 }; unsigned char rom bar2[] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000 }; unsigned char rom bar3[] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000 }; unsigned char rom bar4[] = { 0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000 }; unsigned char rom bar5[] = { 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 }; unsigned char rom bar6[] = { 0b00000, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 }; unsigned char rom bar7[] = { 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Global Variables //////////////////////////////////////////////////////////////////////////////// ram int dat[8]; // pressure data int counter; // keep time unsigned char topmsg[]={"GoWeathr"}; unsigned char scroll_msg[]{" "}; unsigned char bars[]=(" "); unsigned char pressure[]={"Pressure"}; unsigned char pressure_data[]={" . mb"}; unsigned char weather_msg1[]={"ALERT: A Storm is Coming "}; unsigned char weather_msg2[]={"Weather is Stable "}; unsigned char weather_msg3[]={"Weather Should Improve "}; unsigned char *weather_msg; unsigned char lcdweather[]={" "}; int t_min; int t_max; int step; int t; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// #pragma code high_vector=0x08 // put ISR code at vector 0x08 void high_interupt(void) // code for ISR direction { _asm // use assembly language code GOTO timer1_isr // goto timer1_isr _endasm // end assembly language code } #pragma code // return to normal code area #pragma interrupt timer1_isr // Put timer1 ISR at interrupt location void timer1_isr (void) // timer1 ISR { int weather,i; // local declarations PIR1bits.TMR1IF = 0; // clear timer1 flag counter++; // increment counter weather = Find_Slope(); // calculate slope of data if(Button == 0) // Turn on the display if the button is pushed { LCD=1; // apply power to the LCD Delay10KTCYx(10); // small delay to allow LCD to power up OpenXLCD (FOUR_BIT & LINES_5X7); // Initialize LCD while(BusyXLCD()); // wait while LCD finishes last operation MakeBars(); // Add the bar characters to the LCD while(BusyXLCD()); // wait while LCD finishes last operation WriteCmdXLCD(DON); // Turn the Display ON WriteTimer1(0); // Reset Timer1 back to 0 t_min=15000; t_max=0; step=0; for(i=0;i<8;i++) { if(dat[i] > t_max & dat[i] !=0) t_max=dat[i]; if(dat[i] < t_min & dat[i] !=0) t_min=dat[i]; } WriteTimer1(0); // Reset Timer1 to 0 if((t_max-t_min)/6 <= 3) { step=3; t_min=t_max-20; } if((t_max-t_min)/6 > 3) { step=(t_max-t_min)/6; } WriteTimer1(0); // Reset Timer1 to 0 for(i=0;i<8;i++) // This for loop creates the bottom history of pressure from the data in dat[] { if(dat[i] < t_min) // If the pressure is less than 9700mb turn only the first bar on bars[i]=BAR_1; if(dat[i] >=t_min & dat[i] =t_min+1*step & dat[i] < t_min+2*step) // If the pressure is between XXXXmb and XXXXmb turn third bar on bars[i]=BAR_3; if(dat[i] >=t_min+2*step & dat[i] =t_min+3*step & dat[i] =t_min+4*step & dat[i] =t_min+5*step) // If the pressure is between XXXXmb and XXXXmb turn seventh bar on bars[i]=BAR_7; if(dat[i] == 0) bars[i]='0'; } WriteTimer1(0); // Reset Timer1 to 0 // // Weather Info // weather = Find_Slope(); if( (weather*10)/2< (-10)) // If slope is less than -1mb weather_msg=weather_msg1; // A Storm is Coming if( (weather*10)/2>=(-10)&(weather*10)/2<= 10) // If slope is between -1mb and 1mb weather_msg=weather_msg2; // Weather is Stable if( (weather*10)/2>10) // If slope is greater than 1mb weather_msg=weather_msg3; // Weather Should Improve // clear stuff before scroll loop while(BusyXLCD()); // wait until LCD finishes last operation WriteTimer1(0); // Reset Timer1 to 0 WriteCmdXLCD(CLS); // Clear the LCD (ZOMG NOEZ!) // Scrolling for(t=0;t<20;t++) { while(BusyXLCD()); WriteCmdXLCD(CLS); while(BusyXLCD()); WriteCmdXLCD(HOME); while(BusyXLCD()); for(i=0;i<8;i++) { lcdweather[i]=*(weather_msg+i+t); } putsXLCD(lcdweather); WriteTimer1(0); if(t == 0) Delay10KTCYx(25); while(BusyXLCD()); SetDDRamAddr(0x28); while(BusyXLCD()); putsXLCD(bars); Delay10KTCYx(15); } // // Pressure Info // temp=dat[7]; // Put dat[7] into array pressure_data [0] = (temp/1000 + '0'); pressure_data [1] = ((temp/1000) - (10*(temp/10000)) + '0'); pressure_data [2] = ((temp/100) - (10*(temp/1000)) + '0'); pressure_data [3] = ((temp/10) - (10*(temp/100)) + '0'); pressure_data [5] = ((temp%10) + '0'); WriteTimer1(0); // Reset Timer1 to 0 // // Display weather info to LCD // while(BusyXLCD()); // wait while LCD completes last operation WriteCmdXLCD(CLS); // clear the LCD while(BusyXLCD()); // wait while LCD completes last operation WriteCmdXLCD(HOME);; // return cursor to home position while(BusyXLCD()); // wait while LCD completes last operation putsXLCD(pressure); // display pressure message WriteTimer1(0); // Reset Timer1 to 0 while(BusyXLCD()); // wait while LCD completes last operation SetDDRamAddr(0x28); // put cursor on second line WriteTimer1(0); // Reset Timer1 to 0 putsXLCD(pressure_data); // display pressure_data message Delay10KTCYx(100); // delay so that user can see it WriteTimer1(0); // Reset Timer1 to 0 while(BusyXLCD()); // wait while LCD completes last operation WriteCmdXLCD(CLS); // clear the LCD while(BusyXLCD()); // wait while LCD completes last operation SetDDRamAddr(0x28); // put cursor on second line //putsXLCD(bars); // put bar graph on LCDs bottom line Delay10KTCYx(100); // delay so that user can see it WriteCmdXLCD(DOFF); // turn the LCD OFF LCD=0; // switch power off of LCD } } void main(void) // main function { int i,j; // local variable declaration unsigned char current; // local variable declaration TRISA = 0b00000101; // PORTA all outputs 0-ADC(input) 3-LCD(output) 1-Pressure(output) 2-switch(input) TRISC = 0b00000010; // PORTC all outputs except C1 for timer1 xtl DisablePullups(); // turn PORTB pullups off counter=0; // make sure counter is 0 to begin with OpenTimer1( TIMER_INT_ON & // configure Timer1 with interrupts on T1_16BIT_RW & // 16-bit operation 0 to 65536 T1_PS_1_2 & // post scaler = 1:X use x=1 for 2sec x=2 for 4sec x=8 for 16sec T1_OSC1EN_ON & // Select external clock T1_SYNC_EXT_OFF); // syncronize timer1 to external clock INTCONbits.GIE = 1; // enable global interrupts INTCONbits.PEIE = 1; // enable peripheral interrupts Pressure=1; // turn the power on the ADC OpenADC(ADC_FOSC_4 & ADC_RIGHT_JUST & ADC_1ANA_0REF, ADC_CH0 & ADC_INT_OFF); //open ADC LCD=1; // turn power on the LCD Delay10KTCYx(10); // small delay to let LCD turn on OpenXLCD (FOUR_BIT & LINES_5X7); //Initialize LCD while(BusyXLCD()); // wait while LCD completes last operation WriteCmdXLCD(CLS); // clear the LCD while(BusyXLCD()); // wait while LCD completes last operation WriteCmdXLCD(HOME);; // return cursor to home position putsXLCD(topmsg); // display turn on message Delay10KTCYx(100); // delay to let user see it WriteCmdXLCD(DOFF); // turn the LCD off LCD=0; // Turn the LCD power off while(1) // This is the main event loop that will continue indefinately { if(counter == 2) // if timer scaler is 1_2 then 15 minutes will be counter=225 // you will want to use counter=2 during debuging or else // you will have to wait for ever to get data { WriteTimer1(0); // Reset Timer1 to 0 for(i=1;i<8;i++) // This for loop shifts all of the data by one index // this way new data comes into the right most position (on the display) // the last data point is lost { dat[i-1] = dat[i]; // shift the data } data_ave = 0; // reset data_ave to 0 for(i=0;i<10;i++) // acquire and average 10 pressure readings { ConvertADC(); // make ADC conversion while( BusyADC() ); // wait until ADC is finished result = ADRESH; // get high ADC 8-bits result = result << 8; // shift bits to left 8-bits result = result | ADRESL; // get low ADC 8-bits result = ((result * 15) + 2200); // convert volts to psi x 1000 data_ave = data_ave + result; // sum for average } data_ave=data_ave/10; // divide by the number of samples=10 data_ave=((data_ave*69)/100)+1168; // convert the data to milli-bars 1168 is an approximate value dat[7] = data_ave; // set dat[7] (the rightmost data point on the LCD) to the current data measurement WriteTimer1(0); // Reset Timer1 to 0 ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// } Sleep(); // sleep to conserve power Nop(); // no operation when returning from sleep } } int Find_Slope(void) // linear regression { // this routine is a common way to calculate the slope of a line // it assumes that there are 8 data points (the contents of dat[]) // it also assumes that the x values are 1,2,...8 // see Numerical Recipes book for FIT routine int i; float t,sx,st2,sxoss,b; int slope; sx=0; st2=0; slope=0; for (i=0;i<8;i++) { sx = sx + i; } sxoss = sx/8; // calculate linear increase in x for (i=0;i<8;i++) { t = i - sxoss; // calculate change along x st2 = st2 + t*t; // sum the square of the change along x b = b + t*dat[i]; // use sum x dat to calculate slope } b = b/st2; // divide st2 slope = (int)b; // cast to integer value return(slope); // return slope } void MakeBars(void) // This function loads the special bar characters into the LCD { int i; while(BusyXLCD()); // wait while LCD is completing last operation SetCGRamAddr(0); // set CharacterRam address to starting position 0 for(i=0;i<8;i++) { while(BusyXLCD()); // wait while LCD is completing last operation WriteDataXLCD(bar1[i]); // Write each byte of bar into CharacterRam } //////////////////////////////////////////////////////////// // Repeat first operation for each bar //////////////////////////////////////////////////////////// while(BusyXLCD()); SetCGRamAddr(8); for(i=0;i<8;i++) { while(BusyXLCD()); WriteDataXLCD(bar2[i]); } while(BusyXLCD()); SetCGRamAddr(16); for(i=0;i<8;i++) { while(BusyXLCD()); WriteDataXLCD(bar3[i]); } SetCGRamAddr(24); for(i=0;i<8;i++) { while(BusyXLCD()); WriteDataXLCD(bar4[i]); } SetCGRamAddr(32); for(i=0;i<8;i++) { while(BusyXLCD()); WriteDataXLCD(bar5[i]); } SetCGRamAddr(40); for(i=0;i<8;i++) { while(BusyXLCD()); WriteDataXLCD(bar6[i]); } SetCGRamAddr(48); for(i=0;i<8;i++) { while(BusyXLCD()); WriteDataXLCD(bar7[i]); } }