#include <16f876.h> #DEVICE *=16 ICD=TRUE #DEVICE ADC=10 #use Delay(Clock=20000000) #use RS232(Baud=9600,Xmit=PIN_C6,Rcv=PIN_C7,brgh1ok) //----------------------------------------------------------- // This function read the value from the PIC A/D channel. It reads the value // 32 times and averages it. The function is called with an A/D channel number and // returns a float value that is average of the A/D channel value. //----------------------------------------------------------- float average_ad(byte chan) { int i,avg_num = 32; float avg = 0, temp_avg = 0; set_adc_channel(chan); delay_us(100); for (i=1; i<=avg_num; ++i) { avg += read_adc(); delay_us(100); } return(avg/avg_num); } //----------------------------------------------------------- // This function is used to set the duty cycle of the PWM output. It uses the built // in C compiler function set_pwm1_duty to set the duty cycle. The function is called // with a pwm duty cycle percentage (0-100) and also with the maximum pwm value which // is function of the pwm frequency, see PIC data sheet for more information. //----------------------------------------------------------- void pwm1_duty100(long pwm_percent, long pwm_maximum) { set_pwm1_duty((pwm_maximum/100)*pwm_percent); // set PWM #1 duty cycle } // // Main code section. // For more information on the chip PIC16F876 see the data sheet 30292c.pdf. // main() { CONST float CHARGED = 14.4; // initialize constants and variables CONST long NDELTA = -1; CONST byte AMP_CHAN = 0, BAMP_CHAN = 3, BVOLT_CHAN = 2, VOLT_CHAN = 1; float current, voltage, watts = 0.0, old_watts = 0.0; float batamps, batvolts, batwatts; float temp_watts, watts100, amp100, volt100; long delta = 1, pwm_max, pwm100; long boost = 0, boost_counter; byte led_count = 0; // initialize hardware output_low(PIN_C3); // turn off FETs by clearing EN pin on FET driver setup_port_a(ALL_ANALOG); // set up A/D channels setup_adc(adc_clock_div_32); // start A/D clocks setup_timer_2(T2_DIV_BY_1, 49, 1); // pwm frequency 100kHz setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM pwm_max = 200; // maximum value for PWM based on frequency pwm100 = 85; // set pwm to 85% to start pwm1_duty100(pwm100, pwm_max); // set pwm duty cycle to pwm100 value output_high(PIN_C3); // set enable pin on FET driver output_high(PIN_C0); // turn on green led delay_ms(1000); // delay to get started while(TRUE) { // loop forever // check for max battery voltage, very simple battery // charge control algorithm if (batvolts > CHARGED) { // if batvolts is > charged then battery is charged so delta = NDELTA; // start rolling back current until batvolts < charged output_high(PIN_C5); // turn on red led if battery at maximum voltage } // start hill climbing algorithm for peak power tracking else if (old_watts > watts) { // else if battery not charged yet change the value of delta = -delta; // delta to make pwm increase of decrease to maximize watts output_low(PIN_C5); // turn off red led if battery not at maximum voltage } old_watts = watts; // load old_watts with current watts value for next time pwm100 += delta; // add delta to change PWM duty cycle for PPT algorithm if (pwm100 > 100) pwm100 = 100; // check limits of PWM duty cycle and set range to 0-100 else if (pwm100 < 0) pwm100 = 0; pwm1_duty100(pwm100, pwm_max); // call function to set PWM duty cycle in PIC hardware //current = average_ad(AMP_CHAN)/40.885; // read current and voltage from solar panel and going to //voltage = average_ad(VOLT_CHAN)/18.2887; // battery, use average_ad function return average value //batamps = average_ad(BAMP_CHAN)/41.3428; // as a float, divide by constant to scale into actual //batvolts = average_ad(BVOLT_CHAN)/20.4831; // volts and amps. These constants were measured in the // actual prototype hardware. current = average_ad(AMP_CHAN)/20.46; // These constants are calculated by the gain of the voltage = average_ad(VOLT_CHAN)/18.6; // hardware not actually measured. //They are commented out batamps = average_ad(BAMP_CHAN)/20.46; // if not used. If volt and amp constants not measured batvolts = average_ad(BVOLT_CHAN)/18.6; // then use this code watts = current * voltage; // do solar watts calculations using input current and volts batwatts = batamps * batvolts; // do battery watts calculation with batamps and batvolts if (voltage < batvolts + 0.2) { // test if panels have enough voltage. Turn off PPT turn on yellow led if not and shut down driver output_high(PIN_C4); // turn off PPT turn on yellow led output_low(PIN_C3); // turn off FETs by clearing EN pin on FET driver delay_ms(1000); // delay to shut down } // this will shut system down if no more solar current if ((++boost_counter % 20) == 0) { // This section calculates the boost or gain of the PPT pwm1_duty100(100, pwm_max); // set PWM duty cycle to 100% to give direct delay_ms(20); // connection between solar panel and battery amp100 = average_ad(AMP_CHAN)/20.46; // read solar amps and volts using measured constants volt100 = average_ad(VOLT_CHAN)/18.6; /* if (amp100 < 0.05) { // while PWM is set to 100% duty check to see if no more sun output_high(PIN_C4); // if current is < .05 then turn off PPT turn on yellow led output_low(PIN_C3); // turn off FETs by clearing EN pin on FET driver delay_ms(1000); // delay to shut down } // this will shut system down if no more solar current */ watts100 = amp100 * volt100; // if not shutting system down calculate watts at 100% PWM temp_watts = watts / watts100; // divide peak power watts by 100% watts, this is gain or boost boost = (long)((temp_watts * 100) - 100); // turn boost value into a percentage for output } //send all values out the serial port printf(" %lu %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %li %6.2f\r\n", pwm100, current, voltage, watts, batamps, batvolts, batwatts, boost, watts100); output_bit(PIN_C0, (++led_count & 0x01)); //blink green LED to show software running delay_ms(500); //delay before next loop } //end while forever //end main }