// 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 proud
float Vref; // konstanta voltmetru (napeti 1 LSB prevodniku)
int1 Xrs; // 1 znamena vystup na RS232
int1 Xlcd; // 1 znamena vystup na LCD displej
signed 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 32x
Data=0;
*ADCON0 = 0x41 | Chanel << 3; // frekvence f/16, zapnout, cislo kanalu
*ADCON1 = 0xC0; // right justify, Vdd a Vss jako reference
delay_us(100); // ustaleni vstupu
for(i=32;i!=0;i--)
{
*ADCON0 |= 4; // start prevodu
delay_us(50); // prevod
Data += (int16)*ADRESH<<8|*ADRESL; // vysledek se nascita
}
Data=Data>>5; // odcin prumerovani
// Vysledek
return 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 bity
delay_ms(50); // doba na ustaleni
}
void GetString(char *s, int max)
// Nacte ze seriovky retezec,
// dela echo a hlida delku retezce
{
int len; // aktualni delka
char c; // nacteny znak
max--;
len=0;
do {
c=getc();
if(c==8) { // Backspace
if(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 characters
if(s)
c = s[index++];
// increase index if either positive or negative sign is detected
if (c == '-')
{
sign = 1; // Set the sign to negative
c = 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 retezce
char Line[LINE_LEN]; // retezec
int8 Data; // nacteny proud 0 az 250
float FData; // nactene rozdilove napeti
lcd_clr();
printf(Xputc,"\n\rCalibration\r\n");
for(;1;)
{
Xrs=1;
Xlcd=1;
GetString(Line,LINE_LEN);
if (*Line=='q')
{
// Ukonceni procesu kalibrace
SetPWM(0); // vypni proud
printf("\n\r"); // odradkuj na terminalu
EE_WR(0,Vref); // uloz kalibraci do EEPROM
return; // navrat
}
else if (*Line=='v')
{
// Zadani nove hodnoty Vref
Vref=atof(Line+1)/1023; // referencni napeti na 1 LSB
printf("\r\n");
}
else if(*Line)
{
// Zadan novy proud
Data=atoi(Line); // preved retezec na cislo
printf(Xputc," Set %3umA\r\n",Data);
SetPWM(Data+Ofset); // nastav proud
delay_ms(100); // cas na ustaleni
}
// Jeden cyklus mereni
FData=GetVoltage();
printf(Xputc,"%1.2fV \r\n",FData);
}
lcd_clr(); // smaz displej
}
void AutoRun()
// AutoRun - automaticke mereni cele zatezovaci krivky
{
float FData; // zmerene napeti
int8 i; // promenna cyklu - proud v mA
Xrs=0; // vystup neni na RS232
Xlcd=1; // vystup je na LCD
printf(Xputc,"\fAutoRun"); // napis na LCD
Xrs=1; // hlavika jen na RS232
Xlcd=0;
printf(Xputc,"\r\nI[mA] U[V] P[mW]");
Xlcd=1;
SetPWM(0); // vypni proud
delay_ms(100); // klidova podminka
for(i=0;i<=250;i++) // cyklus pres proud 0 az 250mA
{
SetPWM(i+Ofset); // nastav proud
FData=GetVoltage(); // zmer napeti
if (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 odradkuj
SetPWM(0); // vypni proud
lcd_clr(); // smaz displej
}
void main()
{
// Hodiny
*0x8F = 0x72; // 8 MHz interni RC oscilator
// Digitalni vystupy
output_low(PIN_B0); // nepouzity
output_low(PIN_B1); // nepouzity
output_low(PIN_B3); // PWM vystup
output_high(PIN_B5); // TX data
port_b_pullups(TRUE); // vstupy s pull up odporem
// Analogove vstupy
*ANSEL = 0x03; // AN0 a AN1
// Inicializace LCD
lcd_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 data
output_low (PIN_B3); // PWM vystup
// Kalibrace pri drzenem tlacitku
EE_RD(0,Vref); // vytahni kalibracni konstantu z EEPROM
if (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 proudu
int8 i; // promenna cyklu
float Voltage,Power; // zmerene rozdilova napeti a vypocteny vykon
float MaxVoltage,MaxPower; // maximalni hodnoty
// Cihej na stisk tlacitka
0==PORTB; // jen precti port B
RBIF=0; // nuluj priznak preruseni od zmeny
// Pocatecni meze
il=0;
ih=10;
// Trvale prohledavani
for(;1;)
{
if (RBIF) // kdyz je tlacitko
{
AutoRun();
while (~input(PIN_B4)); // cti port B a cekej na uvolneni
RBIF=0;
}
Xrs=0;
Xlcd=1;
printf(Xputc,"\rOpt. [mA V mW]"); // napis na LCD
MaxVoltage=0; // inicializace maxim
MaxPower=0;
im=0;
for(i=il;i<=ih;i++) // dilci cyklus hledani
{
SetPWM(i+Ofset); // nastav proud
Voltage=GetVoltage(); // precti rozdilove napeti
Power=Voltage*i; // vypocti vykon
if (Power>MaxPower) // zkontroluj maximu
{
MaxVoltage=Voltage; // zapamatuj si maximum
MaxPower=Power;
im=i;
}
}
// Zobrazeni vysledku
Xrs=0;
Xlcd=1;
printf(Xputc,"\r\n%3u %1.2f %3.1f ", im, MaxVoltage, MaxPower);
// Natav nove meze
if (im>5) il=im-5; else il=0;
if (il>240) il=240;
ih=il+10;
}
}
}