Rev Author Line No. Line
193 miho 1 // Firmware pro pripravek pro testovani slunecnich clanku CT01A
2 // (c) miho 2005
3 //
4 // 1.00 Zakladni verze
5  
6 #include <16F88.h>
7 #fuses INTRC_IO, NOWDT, NOPUT, NOPROTECT, NOBROWNOUT, MCLR, NOLVP, NOCPD, NODEBUG, CCPB3
8  
9 #use delay(clock=8000000) // interni RC oscilator
10  
11 #use RS232 (baud=9600, xmit=PIN_B5, rcv=PIN_B2)
12  
13 #include <eeprom.c> // Podpora zapisu promennych do EEPROM
14  
15 #define LCD_E PIN_A2
16 #define LCD_RS PIN_A7
17 #define LCD_D0 PIN_A3
18 #define LCD_D1 PIN_A4
19 #define LCD_D2 PIN_B7
20 #define LCD_D3 PIN_B6
21  
22 #include <LCD.C> // podpora LCD displeje
23  
24  
25 // Globalni nastaveni a globalni promenne
26 //
27 #define Ofset 5 // ofset PWM pro nulovy proud
28 float Vref; // konstanta voltmetru (napeti 1 LSB prevodniku)
29 int1 Xrs; // 1 znamena vystup na RS232
30 int1 Xlcd; // 1 znamena vystup na LCD displej
31  
32  
33 signed int16 Convert(int8 Chanel)
34 // Prevod AD prevodnikem ze zadaneho kanalu
35 // Vysledek je na 10 bitu, doba prevodu 1.8ms
36 {
37 unsigned int16 Data;
38 int i;
39  
40 // AD prevod s prumerovanim 32x
41 Data=0;
42 *ADCON0 = 0x41 | Chanel << 3; // frekvence f/16, zapnout, cislo kanalu
43 *ADCON1 = 0xC0; // right justify, Vdd a Vss jako reference
44 delay_us(100); // ustaleni vstupu
45 for(i=32;i!=0;i--)
46 {
47 *ADCON0 |= 4; // start prevodu
48 delay_us(50); // prevod
49 Data += (int16)*ADRESH<<8|*ADRESL; // vysledek se nascita
50 }
51 Data=Data>>5; // odcin prumerovani
52  
53 // Vysledek
54 return Data; // vysledek 0 az 1023
55 }
56  
57  
58 float GetVoltage()
59 // Provede nacteni dat z AD prevodniku a prevod na float napeti
60 {
61 float Data;
62 Data=(Convert(0)-Convert(1))*Vref;
63 return Data;
64 }
65  
66  
67 void SetPWM(int8 Data)
68 // Nastaveni dat do PWM vystupu
69 // Celych 8 bitu, doba behu 10ms
70 {
71 *CCPR1L = Data>>2; // hornich 6 bitu
72 *CCP1CON = *CCP1CON & 0x0F | (Data & 3)<<4; // spodni 2 bity
73 delay_ms(50); // doba na ustaleni
74 }
75  
76  
77 void GetString(char *s, int max)
78 // Nacte ze seriovky retezec,
79 // dela echo a hlida delku retezce
80 {
81 int len; // aktualni delka
82 char c; // nacteny znak
83  
84 max--;
85 len=0;
86 do {
87 c=getc();
88 if(c==8) { // Backspace
89 if(len>0) {
90 len--;
91 putc(c);
92 putc(' ');
93 putc(c);
94 }
95 } else if ((c>=' ')&&(c<='~'))
96 if(len<max) {
97 s[len++]=c;
98 putc(c);
99 }
100 } while(c!=13);
101 s[len]=0;
102 }
103  
104  
105 float atof(char *s)
106 // Prevod retezce na float
107 {
108 float pow10 = 1.0;
109 float result = 0.0;
110 int sign = 0;
111 char c;
112 int ptr = 0;
113  
114 c = s[ptr++];
115  
116 if ((c>='0' && c<='9') || c=='+' || c=='-' || c=='.') {
117 if(c == '-') {
118 sign = 1;
119 c = s[ptr++];
120 }
121 if(c == '+')
122 c = s[ptr++];
123  
124 while((c >= '0' && c <= '9')) {
125 result = 10*result + c - '0';
126 c = s[ptr++];
127 }
128  
129 if (c == '.') {
130 c = s[ptr++];
131 while((c >= '0' && c <= '9')) {
132 pow10 = pow10*10;
133 result += (c - '0')/pow10;
134 c = s[ptr++];
135 }
136 }
137  
138 }
139  
140 if (sign == 1)
141 result = -result;
142 return(result);
143 }
144  
145  
146 signed int atoi(char *s)
147 // Preved retezec na int (jen dekadicka cisla)
148 {
149 signed int result;
150 int sign, index;
151 char c;
152  
153 index = 0;
154 sign = 0;
155 result = 0;
156  
157 // Omit all preceeding alpha characters
158 if(s)
159 c = s[index++];
160  
161 // increase index if either positive or negative sign is detected
162 if (c == '-')
163 {
164 sign = 1; // Set the sign to negative
165 c = s[index++];
166 }
167 else if (c == '+')
168 {
169 c = s[index++];
170 }
171  
172 while (c >= '0' && c <= '9')
173 {
174 result = 10*result + (c - '0');
175 c = s[index++];
176 }
177  
178 if (sign == 1)
179 result = -result;
180  
181 return(result);
182 }
183  
184  
185 void Xputc(char c)
186 // Spolecna procedura pro vystup znaku na LCD a RS232
187 // dle stavu promennych Xrs a Xlcd
188 {
189 if (Xrs)
190 if(c!='\n') putc(c); // vystup na RS232 (neposilej LF)
191 if (Xlcd) lcd_putc(c); // vystup na LCD displej
192 }
193  
194  
195 void Calibrate()
196 // Procedura pro kalibraci
197 {
198 #define LINE_LEN 40 // delka retezce
199 char Line[LINE_LEN]; // retezec
200 int8 Data; // nacteny proud 0 az 250
201 float FData; // nactene rozdilove napeti
202  
203 lcd_clr();
204 printf(Xputc,"\n\rCalibration\r\n");
205 for(;1;)
206 {
207 Xrs=1;
208 Xlcd=1;
209 GetString(Line,LINE_LEN);
210 if (*Line=='q')
211 {
212 // Ukonceni procesu kalibrace
213 SetPWM(0); // vypni proud
214 printf("\n\r"); // odradkuj na terminalu
215 EE_WR(0,Vref); // uloz kalibraci do EEPROM
216 return; // navrat
217 }
218 else if (*Line=='v')
219 {
220 // Zadani nove hodnoty Vref
221 Vref=atof(Line+1)/1023; // referencni napeti na 1 LSB
222 printf("\r\n");
223 }
224 else if(*Line)
225 {
226 // Zadan novy proud
227 Data=atoi(Line); // preved retezec na cislo
228 printf(Xputc," Set %3umA\r\n",Data);
229 SetPWM(Data+Ofset); // nastav proud
230 delay_ms(100); // cas na ustaleni
231 }
232 // Jeden cyklus mereni
233 FData=GetVoltage();
234 printf(Xputc,"%1.2fV \r\n",FData);
235 }
236 lcd_clr(); // smaz displej
237 }
238  
239  
240 void AutoRun()
241 // AutoRun - automaticke mereni cele zatezovaci krivky
242 {
243 float FData; // zmerene napeti
244 int8 i; // promenna cyklu - proud v mA
245  
246 Xrs=0; // vystup neni na RS232
247 Xlcd=1; // vystup je na LCD
248 printf(Xputc,"\fAutoRun"); // napis na LCD
249 Xrs=1; // hlavika jen na RS232
250 Xlcd=0;
251 printf(Xputc,"\r\nI[mA] U[V] P[mW]");
252 Xlcd=1;
253  
254 SetPWM(0); // vypni proud
255 delay_ms(100); // klidova podminka
256 for(i=0;i<=250;i++) // cyklus pres proud 0 az 250mA
257 {
258 SetPWM(i+Ofset); // nastav proud
259 FData=GetVoltage(); // zmer napeti
260 if (FData>0) printf(Xputc,"\r\n%03u %1.2f %3.1f",i,FData,FData*i);
261 else i=250; // predcasne ukonceni
262 }
263 printf(Xputc,"\r\n"); // na konci odradkuj
264 SetPWM(0); // vypni proud
265 lcd_clr(); // smaz displej
266 }
267  
268  
269 void main()
270 {
271 // Hodiny
272 *0x8F = 0x72; // 8 MHz interni RC oscilator
273  
274 // Digitalni vystupy
275 output_low(PIN_B0); // nepouzity
276 output_low(PIN_B1); // nepouzity
277 output_low(PIN_B3); // PWM vystup
278 output_high(PIN_B5); // TX data
279 port_b_pullups(TRUE); // vstupy s pull up odporem
280  
281 // Analogove vstupy
282 *ANSEL = 0x03; // AN0 a AN1
283  
284 // Inicializace LCD
285 lcd_init();
286 Xrs=1;
287 Xlcd=1;
288 printf(Xputc,"\fSolar Cell\r\nTester 1.00\r");
289  
290 // Inicializace PWM 8 bitu
291 *PR2 = 0x3F; // perioda PWM casovace
292 *T2CON = 0x04; // povoleni casovace T2 bez preddelicu a postdelicu
293 *CCP1CON = 0x0C; // PWM mode, lsb bity nulove
294 *CCPR1L = 0; // na zacatku nulova data
295 output_low (PIN_B3); // PWM vystup
296  
297 // Kalibrace pri drzenem tlacitku
298 EE_RD(0,Vref); // vytahni kalibracni konstantu z EEPROM
299 if (input(PIN_B4)==0) // otestuj tlacitko
300 {
301 delay_ms(200);
302 Calibrate(); // pokud je stalceno spust kalibraci
303 }
304 else
305 {
306 delay_ms(1000); // jinak jen 1s spozdeni
307 }
308 lcd_clr(); // smaz displej
309  
310 // Hlavni smycka
311 {
312 int8 il,ih,im; // spodni a horni mez a maximum proudu
313 int8 i; // promenna cyklu
314 float Voltage,Power; // zmerene rozdilova napeti a vypocteny vykon
315 float MaxVoltage,MaxPower; // maximalni hodnoty
316  
317 // Cihej na stisk tlacitka
318 0==PORTB; // jen precti port B
319 RBIF=0; // nuluj priznak preruseni od zmeny
320  
321 // Pocatecni meze
322 il=0;
323 ih=10;
324  
325 // Trvale prohledavani
326 for(;1;)
327 {
328  
329 if (RBIF) // kdyz je tlacitko
330 {
331 AutoRun();
332 while (~input(PIN_B4)); // cti port B a cekej na uvolneni
333 RBIF=0;
334 }
335  
336 Xrs=0;
337 Xlcd=1;
338 printf(Xputc,"\rOpt. [mA V mW]"); // napis na LCD
339  
340 MaxVoltage=0; // inicializace maxim
341 MaxPower=0;
342 im=0;
343  
344 for(i=il;i<=ih;i++) // dilci cyklus hledani
345 {
346 SetPWM(i+Ofset); // nastav proud
347 Voltage=GetVoltage(); // precti rozdilove napeti
348 Power=Voltage*i; // vypocti vykon
349 if (Power>MaxPower) // zkontroluj maximu
350 {
351 MaxVoltage=Voltage; // zapamatuj si maximum
352 MaxPower=Power;
353 im=i;
354 }
355 }
356  
357 // Zobrazeni vysledku
358 Xrs=0;
359 Xlcd=1;
360 printf(Xputc,"\r\n%3u %1.2f %3.1f ", im, MaxVoltage, MaxPower);
361  
362 // Natav nove meze
363 if (im>5) il=im-5; else il=0;
364 if (il>240) il=240;
365 ih=il+10;
366 }
367 }
368 }