// Insolation Server Project // The code for LTC2400 Sigma-Delta converter // Copyright (C) 2008 by Wichit Sirichote, kswichit@kmitl.ac.th /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define ADC_CS1 PORTC.F0 // output bit #define ADC_SDO PORTC.F1 // input bit #define ADC_SCK PORTC.F2 // output bit #define set_hour PORTA.F0 #define set_min PORTA.F2 #define tick LATA.F4 char *text = "SOLAR STATION 01"; unsigned long x1,x2,x3,x4,x5,x6,x7,x8,x9,x10; unsigned int sample=0; char timer5=0; char buffer[128]; int sec100=0; int sec=0; int hour,mins; char flag1=0; char command; int station; float offset=0.000000; // for zeroing the offset at 0 W/m^2 float temp; float now2; float sum=0; // integration variable float insolation; short set_hour_press=0; short set_min_press=0; short show_tick=0; float maximum=0; /* read 32-bit data from LTC2400 */ unsigned long read_ADC1(void) { char k; long n; n= 0; ADC_CS1 = 0; for(k=0; k<32; k++) { n<<= 1; ADC_SCK = 1; n |= ADC_SDO; ADC_SCK = 0; } ADC_CS1 = 1; n&=0x01fffffff; // maskout sign bit n>>=4; // get 24-bit conversion result return n; } /* 10-point moving average */ // return data that scaled with reference voltage in uV unit unsigned long filter_ADC(void) { x10 = x9; x9 = x8; x8 = x7; x7 = x6; x6 = x5; x5 = x4; x4 = x3; x3 = x2; x2 = x1; x1 = read_ADC1(); return ((((x1+x2+x3+x4+x5+x6+x7+x8+x9+x10)/10)*148)/100); // x 149 E-9 convert to 2.479V } char *print_terminal(char *str) { unsigned char i; for(i=0; str[i] != 0; i++) USART_Write(str[i]); return str; } // reset sample, sum at 20:00 everyday void reset_variables() { if(hour==20 && mins == 0 && sec==0) {sample = 0; sum=0; maximum =0; } } void print_time_now() { sprintf(buffer,"%03d,%05d,%02d:%02d",station,sample,hour,mins); Lcd_Cmd(LCD_FIRST_ROW); Lcd_Out_CP(buffer); } // run every minute void print_time() { if(flag1&2) { flag1&= ~2; sample++; sprintf(buffer,"%03d,%05d,%02d:%02d",station,sample,hour,mins); Lcd_Cmd(LCD_FIRST_ROW); Lcd_Out_CP(buffer); // print data to terminal 9600 every minute sprintf(buffer,"\n%d,%d,%02d:%02d,%0.6f,%0.1f,%0.1f,%0.0f",station,sample,hour,mins,temp,now2,maximum,sum/3600); print_terminal(buffer); } } void tick_tock() { show_tick ^=1; if(show_tick) Lcd_Chr(1, 20, '-'); else Lcd_Chr(1, 20, '_'); } // run every one second void send_reading() { static float d,now; Lcd_Cmd(Lcd_CURSOR_OFF); if(flag1&1) { flag1 &= ~1; tick_tock(); d=filter_ADC()*1E-7 - offset; temp=d; // for sending to terminal now=d*1E6/5.14; now2=now; // convert to W/m^2, Our CM11 has EMF output 5.14uV/W/m^2 sprintf(buffer,"EMF=%0.6fV %0.1f",d,now); Lcd_Cmd(LCD_SECOND_ROW); Lcd_Out_CP(buffer); if(now<1000 && now >=0) { sum += now; if (now>maximum) {maximum=now; sprintf(buffer,"MAX=%0.1f W/m^2",maximum); Lcd_Cmd(LCD_FOURTH_ROW); Lcd_Out_CP(buffer); } sprintf(buffer,"sum=%0.0f WH/m^2",sum/3600); Lcd_Cmd(LCD_THIRD_ROW); Lcd_Out_CP(buffer); } } } /* update real-time clock */ void time () { if (++sec100 >= 10) /* 100 * 10 ms = 1 s */ {sec100 = 0; flag1 |= 0x05; /* set bit 0, bit 2 */ if (++sec >= 60) {sec = 0; flag1 |= 0x02; /* set bit 1 */ if (++mins >= 60) {mins = 0; if (++hour >= 24) {hour = 0; } } } } } void get_command() { if(USART_Data_Ready()) { command = USART_Read(); } else command = -1; } void adjust_hour() { if(command == 'h'|| (set_hour==0 && set_hour_press ==0)) { set_hour_press=1; if(++hour >=24) hour =0; print_time_now(); } if(set_hour) set_hour_press=0; } void adjust_min() { if(command == 'm' || (set_min==0 && set_min_press==0)) { set_min_press=1; sec =0; if(++mins>59) mins =0; print_time_now(); } if(set_min) set_min_press=0; } // provide offset correction at 0 W/m^2 void zero_adjust() { if (command=='z') { offset=filter_ADC()*1E-7; } } // enter timer1 interrupt every 100ms void interrupt() { PIR1 =0; // clear interrupt flag //TMR1L = 0xF0; // reload 55536 to produce 100Hz interrupt //TMR1H = 0xD8; TMR1L = 0x2C; // reload 53036 to produce 10Hz interrupt TMR1H = 0xCF; tick^=1; time(); } void main() { Delay_ms(300); ADCON1 = 0x0F; // PORTA is digital I/O TRISA = 0xEF; // PORTA is digital input TRISB = 0; // PORTB is output PORTC = 0xFF; TRISC = 0x82; // PORTC.1 and PORTC.7 are input bit Delay_ms(200); //T1CON = 0x01; // run timer1 with Fosc/4 T1CON = 0x31; // run timer1 with Fosc/4/8 PIE1 = 0x01; // enable timer1 interrupt INTCON = 0xC0; // global interrupt PORTC.F7 =0; hour = 8; mins = 0; USART_init(9600); // initialize USART module // (8 bit, 9600 baud rate, no parity bit... station=Eeprom_Read(0); Lcd_Init(&PORTB); // Initialize LCD connected to PORTB maximum=0; flag1 =0; print_time_now(); while(1) { send_reading(); reset_variables(); get_command(); adjust_hour(); adjust_min(); zero_adjust(); print_time(); } }