// Firmware pro pripravek pro testovani slunecnich clanku CT01A// (c) miho 2005//// 1.00 Zakladni verze#include <16F88.h>#fuses INTRC_IO, NOWDT, NOPUT, NOPROTECT, NOBROWNOUT, MCLR, NOLVP, NOCPD, NODEBUG, CCPB3#use delay(clock=8000000) // interni RC oscilator#use RS232 (baud=9600, xmit=PIN_B5, rcv=PIN_B2)#include <eeprom.c> // Podpora zapisu promennych do EEPROM#define LCD_E PIN_A2#define LCD_RS PIN_A7#define LCD_D0 PIN_A3#define LCD_D1 PIN_A4#define LCD_D2 PIN_B7#define LCD_D3 PIN_B6#include <LCD.C> // podpora LCD displeje// Globalni nastaveni a globalni promenne//#define Ofset 5 // ofset PWM pro nulovy proudfloat Vref; // konstanta voltmetru (napeti 1 LSB prevodniku)int1 Xrs; // 1 znamena vystup na RS232int1 Xlcd; // 1 znamena vystup na LCD displejsigned int16 Convert(int8 Chanel)// Prevod AD prevodnikem ze zadaneho kanalu// Vysledek je na 10 bitu, doba prevodu 1.8ms{unsigned int16 Data;int i;// AD prevod s prumerovanim 32xData=0;*ADCON0 = 0x41 | Chanel << 3; // frekvence f/16, zapnout, cislo kanalu*ADCON1 = 0xC0; // right justify, Vdd a Vss jako referencedelay_us(100); // ustaleni vstupufor(i=32;i!=0;i--){*ADCON0 |= 4; // start prevodudelay_us(50); // prevodData += (int16)*ADRESH<<8|*ADRESL; // vysledek se nascita}Data=Data>>5; // odcin prumerovani// Vysledekreturn Data; // vysledek 0 az 1023}float GetVoltage()// Provede nacteni dat z AD prevodniku a prevod na float napeti{float Data;Data=(Convert(0)-Convert(1))*Vref;return Data;}void SetPWM(int8 Data)// Nastaveni dat do PWM vystupu// Celych 8 bitu, doba behu 10ms{*CCPR1L = Data>>2; // hornich 6 bitu*CCP1CON = *CCP1CON & 0x0F | (Data & 3)<<4; // spodni 2 bitydelay_ms(50); // doba na ustaleni}void GetString(char *s, int max)// Nacte ze seriovky retezec,// dela echo a hlida delku retezce{int len; // aktualni delkachar c; // nacteny znakmax--;len=0;do {c=getc();if(c==8) { // Backspaceif(len>0) {len--;putc(c);putc(' ');putc(c);}} else if ((c>=' ')&&(c<='~'))if(len<max) {s[len++]=c;putc(c);}} while(c!=13);s[len]=0;}float atof(char *s)// Prevod retezce na float{float pow10 = 1.0;float result = 0.0;int sign = 0;char c;int ptr = 0;c = s[ptr++];if ((c>='0' && c<='9') || c=='+' || c=='-' || c=='.') {if(c == '-') {sign = 1;c = s[ptr++];}if(c == '+')c = s[ptr++];while((c >= '0' && c <= '9')) {result = 10*result + c - '0';c = s[ptr++];}if (c == '.') {c = s[ptr++];while((c >= '0' && c <= '9')) {pow10 = pow10*10;result += (c - '0')/pow10;c = s[ptr++];}}}if (sign == 1)result = -result;return(result);}signed int atoi(char *s)// Preved retezec na int (jen dekadicka cisla){signed int result;int sign, index;char c;index = 0;sign = 0;result = 0;// Omit all preceeding alpha charactersif(s)c = s[index++];// increase index if either positive or negative sign is detectedif (c == '-'){sign = 1; // Set the sign to negativec = s[index++];}else if (c == '+'){c = s[index++];}while (c >= '0' && c <= '9'){result = 10*result + (c - '0');c = s[index++];}if (sign == 1)result = -result;return(result);}void Xputc(char c)// Spolecna procedura pro vystup znaku na LCD a RS232// dle stavu promennych Xrs a Xlcd{if (Xrs)if(c!='\n') putc(c); // vystup na RS232 (neposilej LF)if (Xlcd) lcd_putc(c); // vystup na LCD displej}void Calibrate()// Procedura pro kalibraci{#define LINE_LEN 40 // delka retezcechar Line[LINE_LEN]; // retezecint8 Data; // nacteny proud 0 az 250float FData; // nactene rozdilove napetilcd_clr();printf(Xputc,"\n\rCalibration\r\n");for(;1;){Xrs=1;Xlcd=1;GetString(Line,LINE_LEN);if (*Line=='q'){// Ukonceni procesu kalibraceSetPWM(0); // vypni proudprintf("\n\r"); // odradkuj na terminaluEE_WR(0,Vref); // uloz kalibraci do EEPROMreturn; // navrat}else if (*Line=='v'){// Zadani nove hodnoty VrefVref=atof(Line+1)/1023; // referencni napeti na 1 LSBprintf("\r\n");}else if(*Line){// Zadan novy proudData=atoi(Line); // preved retezec na cisloprintf(Xputc," Set %3umA\r\n",Data);SetPWM(Data+Ofset); // nastav prouddelay_ms(100); // cas na ustaleni}// Jeden cyklus mereniFData=GetVoltage();printf(Xputc,"%1.2fV \r\n",FData);}lcd_clr(); // smaz displej}void AutoRun()// AutoRun - automaticke mereni cele zatezovaci krivky{float FData; // zmerene napetiint8 i; // promenna cyklu - proud v mAXrs=0; // vystup neni na RS232Xlcd=1; // vystup je na LCDprintf(Xputc,"\fAutoRun"); // napis na LCDXrs=1; // hlavika jen na RS232Xlcd=0;printf(Xputc,"\r\nI[mA] U[V] P[mW]");Xlcd=1;SetPWM(0); // vypni prouddelay_ms(100); // klidova podminkafor(i=0;i<=250;i++) // cyklus pres proud 0 az 250mA{SetPWM(i+Ofset); // nastav proudFData=GetVoltage(); // zmer napetiif (FData>0) printf(Xputc,"\r\n%03u %1.2f %3.1f",i,FData,FData*i);else i=250; // predcasne ukonceni}printf(Xputc,"\r\n"); // na konci odradkujSetPWM(0); // vypni proudlcd_clr(); // smaz displej}void main(){// Hodiny*0x8F = 0x72; // 8 MHz interni RC oscilator// Digitalni vystupyoutput_low(PIN_B0); // nepouzityoutput_low(PIN_B1); // nepouzityoutput_low(PIN_B3); // PWM vystupoutput_high(PIN_B5); // TX dataport_b_pullups(TRUE); // vstupy s pull up odporem// Analogove vstupy*ANSEL = 0x03; // AN0 a AN1// Inicializace LCDlcd_init();Xrs=1;Xlcd=1;printf(Xputc,"\fSolar Cell\r\nTester 1.00\r");// Inicializace PWM 8 bitu*PR2 = 0x3F; // perioda PWM casovace*T2CON = 0x04; // povoleni casovace T2 bez preddelicu a postdelicu*CCP1CON = 0x0C; // PWM mode, lsb bity nulove*CCPR1L = 0; // na zacatku nulova dataoutput_low (PIN_B3); // PWM vystup// Kalibrace pri drzenem tlacitkuEE_RD(0,Vref); // vytahni kalibracni konstantu z EEPROMif (input(PIN_B4)==0) // otestuj tlacitko{delay_ms(200);Calibrate(); // pokud je stalceno spust kalibraci}else{delay_ms(1000); // jinak jen 1s spozdeni}lcd_clr(); // smaz displej// Hlavni smycka{int8 il,ih,im; // spodni a horni mez a maximum prouduint8 i; // promenna cyklufloat Voltage,Power; // zmerene rozdilova napeti a vypocteny vykonfloat MaxVoltage,MaxPower; // maximalni hodnoty// Cihej na stisk tlacitka0==PORTB; // jen precti port BRBIF=0; // nuluj priznak preruseni od zmeny// Pocatecni mezeil=0;ih=10;// Trvale prohledavanifor(;1;){if (RBIF) // kdyz je tlacitko{AutoRun();while (~input(PIN_B4)); // cti port B a cekej na uvolneniRBIF=0;}Xrs=0;Xlcd=1;printf(Xputc,"\rOpt. [mA V mW]"); // napis na LCDMaxVoltage=0; // inicializace maximMaxPower=0;im=0;for(i=il;i<=ih;i++) // dilci cyklus hledani{SetPWM(i+Ofset); // nastav proudVoltage=GetVoltage(); // precti rozdilove napetiPower=Voltage*i; // vypocti vykonif (Power>MaxPower) // zkontroluj maximu{MaxVoltage=Voltage; // zapamatuj si maximumMaxPower=Power;im=i;}}// Zobrazeni vysledkuXrs=0;Xlcd=1;printf(Xputc,"\r\n%3u %1.2f %3.1f ", im, MaxVoltage, MaxPower);// Natav nove mezeif (im>5) il=im-5; else il=0;if (il>240) il=240;ih=il+10;}}}