SmartCharge
/
2017charger_16ampONLY
single current only
Diff: main.cpp
- Revision:
- 0:0ba5f6ec8fa5
- Child:
- 1:31e63b43238f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Jan 24 13:32:57 2017 +0000 @@ -0,0 +1,426 @@ +// Copyright (c) 2017 Smartcharge Ltd + + +#include "mbed.h" +#include "Watchdog.h" + +// ************************************************************ +// * Variables for capturing analog cp and pp values * +// ************************************************************ +AnalogIn cp_value(A1); //A1 – cp analog read. +AnalogIn pp_value(A2); //A2 - pp analog read. + +// ************************************************************ +// * Variables and constants for new cp acquisition routine * +// ************************************************************ +#define NUMBER_OF_SAMPLES 5000 // Size of ADC sample series for cp signal (default = 5000). +#define VOLTAGE_RENORMALISATION 4.5 // Renormalisation constant to correct cp measured voltages (default = 4.5). +#define VOLTAGE_THRESHOLD 4.0 // Threshold value for pwm edge detection (default = 4.0). +float cp_voltage; // Global variable to store the measured voltage of the cp signal. +float cp_duty_cycle; // Global variable to store the measured duty cycle of the cp signal. +float cp_frequency; // Global variable to store the the measured frequency of the cp signal. +Timer cp_timer; // Timer used to determine the frequency of the cp signal. +uint16_t cp_array[NUMBER_OF_SAMPLES]; // Array to store ADC sample series for cp signal. + +// ************************************************************ +// * Constant for voltage checking routine * +// ************************************************************ +#define ACCEPTABLE_VOLTAGE_RANGE 0.5 // Sets the acceptable range of measured cp voltages (default 0.5, i.e. +/-0.5 V around value of 12, 9, 6V) + +// ************************************************************ +// * Timers and variables for reset button * +// ************************************************************ +InterruptIn button(D8); // Interupt for button on pin D8. +Timer button_timer; // Timer used for reset button press. +Timeout button_timeout; // Timeout case for reset button press. +bool reset_down = false; // Flag used to determine whether reset button is held down. +bool reset_charger = false; // Flag used to determine whether charger is to be reset. +#define RESET_SECONDS 2 // Define length of time in seconds reset button needs to be held down before reset registered (default 3s). + +// ************************************************************ +// * Variables and constants to set the charging current * +// ************************************************************ +#define UPPER_CURRENT 32 // Sets the upper current value desired. +#define LOWER_CURRENT 16 // Sets the lower current value desired. +float pwm_duty_high = 1.0-((UPPER_CURRENT / 30.0) * 0.5); // Calculates the pwm duty cycle for the desired upper current. +float pwm_duty_low = 1.0-((LOWER_CURRENT / 30.0) * 0.5); // Calculates the pwm duty cycle for the desired lower current. +bool use_upper_current = false; + +// ************************************************************ +// * Variables and constants to allow state changes * +// ************************************************************ +unsigned char control_pilot; +#define PILOT_NOK 0 // Error state. +#define PILOT_12V 1 // Standby state. +#define PILOT_9V 2 // Vehicle detection state. +#define PILOT_6V 3 // Charging state. +#define PILOT_DIODE 4 // Charging state with ventilation (not currently implemented). +#define PILOT_RESET 5 // Reset state. +#define PWM_CHANGE 6 // New state added to allow change in PWM duty cycle and charging current. + +// ************************************************************ +// * Digital out definitions * +// ************************************************************ +PwmOut my_pwm(D5); // PWM out on pin D5. +DigitalOut lock(D7); // Cable lock on pin D7. +DigitalOut relay(D12); // Relay on pin D12. +DigitalOut contactor(D13); // Contactor on pin D13. +DigitalOut green(D9); // Green LED on pin D9. +DigitalOut red(D10); // Red LED on pin D10. +DigitalOut blue(D11); // Blue LED on pin D11. + +// ************************************************************ +// * Serial connections * +// ************************************************************ +Serial pc(USBTX, USBRX); // Serial output to PC. +int TESTCOUNTER = 0; // Variable to count number of cycles of main loop. Used to determine when to switch the pwm in this test version. + + +// ************************************************************ +// * New Acquisition Routine for Capturing CP Signal Data * +// ************************************************************ +void cp_acquire() +{ + int i; // Variable for loop counter. + float sample_value_current = 0; // Stores the current cp value obtained by ADC (A1). + float sample_value_previous = 0; // Stores the previous cp value obtained by ADC (A1). + float peak_counter; // Used to store the number of samples representing a peak of the pwm square wave. + float trough_counter; // Used to store the number of samples representing a trough of the pwm square wave. + float voltage_average; // Used to calculate the average peak voltage value. + float thres_cross_rise; // Used to store the number of times the pwm wave goes from low to high. + float thres_cross_fall; // Used to store the number of times the pwm wave goes from high to low. + float t; // Used to determine the time over which samples were acquired. + + cp_timer.start(); // Starts a timer before we begin sampling the cp signal. + for (i = 0; i < NUMBER_OF_SAMPLES; i++) // Starts a loop to take a certain number of samples as defined in NUMBER_OF_SAMPLES. + { + wait_us(30); // Waits 30 us. This sets the sample rate at approximately 33 KS/second. + cp_array[i] = cp_value.read_u16(); // Reads the ADC (A1) and stores the measured cp voltage as a 16 bit integer in cp_array. + } + cp_timer.stop(); // Stop the timer once the acqusition has finished. + t = cp_timer.read_us(); // Read the timer value in microseconds and store the result in t. + t = t / 1000000.0; // Divide t by 1000000 to convert from microseconds to seconds. + cp_timer.reset(); // Reset the timer. + + peak_counter = 0; // Set peak_counter to zero. + trough_counter = 0; // Set trough_counter to zero. + voltage_average = 0; // Set voltage_average to zero. + thres_cross_rise = 0; // Set thres_cross_rise to zero. + thres_cross_fall = 0; // Set thres_cross_fall to zero. + + // Having captured cp data, we now have to process each sample. This is done in a separate loop to maximize the ADC sampling rate. + for (i = 0; i < NUMBER_OF_SAMPLES; i++) + { + // The cp data was stored in cp_array as a 16 bit integer. To convert this into a voltage we divide by 65535 (16 bits is 0 - 65535) + // and multiply by 3.3 V. Because of the resistors and diode on the shield, we need to renormalise the values and scale them up + // by a factor of 4.5 (VOLTAGE_RENORMALISATION). + sample_value_current = (cp_array[i] * 3.3 * VOLTAGE_RENORMALISATION) / 65535.0; + + + if (sample_value_current > VOLTAGE_THRESHOLD) // We examine the cp voltage. If it is above the threshold then we assume it is at the peak of the pwm square wave. + { + peak_counter+=1; // Add one to the peak_counter. + voltage_average+=sample_value_current; // Add the cp_voltage to a running total (voltage_average) so we can work out the average voltage later. + } + else + { + trough_counter+=1; // If the cp voltage is less than the threshold then we assume it is at the trough of the pwm square wave and increment trough_counter. + } + + + if (i > 0) // If we've already processed the first sample then ... + { + if (sample_value_current > VOLTAGE_THRESHOLD && sample_value_previous < VOLTAGE_THRESHOLD) // ... we check if the cp voltage we're looking at is above the threshold and if the previous cp voltage + // is below the threshold. If this is the case then we've detected the rising edge of the pwm square wave. + { + thres_cross_rise+=1; // We increment thres_cross_rise if this is the case. + } + if (sample_value_current < VOLTAGE_THRESHOLD && sample_value_previous > VOLTAGE_THRESHOLD) // Alternatively, if the cp voltage we're looking at is below the theshold and the previous cp voltage + // is above the threshold then we've detected the falling edge of the pwm square wave. + { + thres_cross_fall+=1; // We increment thres_cross_fall is this is the case. + } + } + + sample_value_previous = sample_value_current; // Before we proces the next sample, we copy the current value into the previous value. + } + + + if(peak_counter == 0) // If, having processed each sample, the peak_counter is still zero, then every cp voltage we acquired was less than the threshold ... + { + cp_voltage = -12.0; // ... which implies that the cp is not at 6, 9, or 12V. In the current implementation, that means the cp is actually at -12 V. + } + else // On the other hand, if the peak_counter is greater than 0, then some (pwm is on) or all (DC, pwm is off) of the values were greater than the threshold ... + { + cp_voltage = voltage_average / peak_counter; // ... so determine the cp voltage by taking the running total (voltage_average) and dividing it by peak_counter. + } + + cp_duty_cycle = peak_counter / NUMBER_OF_SAMPLES; // The duty cycle is the number of peak samples of the pwm square waves divided by the total number of samples ... + cp_duty_cycle = cp_duty_cycle * 100.0; // ... but we need to convert it into a percentage. + cp_frequency = ((thres_cross_rise + thres_cross_fall) / 2.0) / t; // The frequency of the cp signal is the total number of crossings divided by 2, divided by the time. + + pc.printf("CP Measured Peak/DC Voltage (V): %f \r\n", cp_voltage); + pc.printf("CP Measured Duty Cycle (%%): %f \r\n", cp_duty_cycle); + pc.printf("CP Measured Frequency (Hz): %f \r\n", cp_frequency); +} + + + +// ************************************************************ +// * Routines for handling reset button press * +// ************************************************************ +void button_timed_out() +{ + reset_charger = true; + pc.printf("Reset button pressed for more than 3 sec! Charger reset! \r\n"); +} + +void reset_pressed() +{ + pc.printf("Reset button pressed ... starting timer. \r\n"); + button_timer.stop(); + button_timer.reset(); + button_timer.start(); + reset_down = true; + button_timeout.attach(&button_timed_out, RESET_SECONDS); +} + +void reset_released() +{ + int elapsed_seconds; + pc.printf("Reset button released. \r\n"); + elapsed_seconds = button_timer.read(); + button_timer.stop(); + button_timer.reset(); + if (elapsed_seconds > RESET_SECONDS) + { + reset_charger = true; + pc.printf("Reset button was pressed for more than 3 sec! \r\n"); + } + else + { + pc.printf("Reset button released before 3 seconds were up. \r\n"); + } + pc.printf("Detach the timeout and setup for the next time.\r\n"); + pc.printf("%u \r\n", elapsed_seconds); + button_timeout.detach(); +} + + + +// ************************************************************ +// * Routine for Checking CP Voltages * +// ************************************************************ +bool cp_check_voltage (float v) // Function accepts a voltage value (eg. 12V, 9V, 6V) ... +{ + bool voltage_in_range = false; // ... and initially sets a flag to false. + + // If the measured cp voltage is within a range of +/- ACCEPTABLE_VOLTAGE_RANGE around the + // value (12V, 9V, 6V) then we change the flag state to true. + if (cp_voltage < (v + ACCEPTABLE_VOLTAGE_RANGE) && cp_voltage > (v - ACCEPTABLE_VOLTAGE_RANGE)) voltage_in_range = true; + + return voltage_in_range; // The function then returns the value of the flag state. +} + + + +// ************************************************************ +// * Main * +// ************************************************************ +int main() +{ + button.fall(&reset_pressed); // Attach interupt to button when pressed. + button.rise(&reset_released); // Attach interupt to button when released. + + float reading_pp; // Create variable to store pp reading. + bool cable_32A = false; // Create boolean to flag whether a 32 or 16A cable is being used. Default is 16A cable (cable_32A = false). + bool cable_connected = false; // Create boolean to flag whether a cable is attached. + bool pwm_state = false; // Create boolean to flag current state of pwm (whether it is on or off). + float pwm_duty_cycle; // Create float to store the current pwm duty cycle. + + while(true) // Start of process loop. + { + // check the cable using pp value + reading_pp = pp_value.read(); // Read pp value and ... + reading_pp = reading_pp * 3300; // ... multiply it by 3300 to convert to mV. + + if(reading_pp > 3200) // If the pp value is 3.3 V (greater than 3200 mV) then ... + { + cable_connected = false; // ... the cable *isn't* connected to charger ... + pc.printf("Cable not connected. \r\n"); + } + else + { + cable_connected = true; // ... otherwise the cable *is* connected to charger. + pc.printf("Cable connected. \r\n"); + } + + if(reading_pp > 200 && reading_pp < 300) // If the pp reading is between 200 and 300 mV then ... + { + cable_32A = false; // ... a 16A cable is being used. + pc.printf("16A cable detected. \r\n"); + } + + if(reading_pp > 0 && reading_pp <100) // If the pp reading if between 0 and 100 mV then ... + { + cable_32A = true; // ... a 32A cable is being used. + pc.printf("32A cable detected. \r\n"); + } + + cp_acquire(); // Call the new acquisition routine (replaces the moving average in previous versions). + + if (cable_connected == false) + { + if (cp_check_voltage(12) == true) control_pilot = PILOT_12V; + + if (cp_check_voltage(-12) == true) + { + control_pilot = PILOT_12V; + reset_charger = false; + } + } + + if (cable_connected == true) + { + if (cp_check_voltage(9) == true) control_pilot = PILOT_9V; + if (cp_check_voltage(6) == true) control_pilot = PILOT_6V; + if (reset_charger == true) control_pilot = PILOT_RESET; + } +// ************************************************************ +// * Switching PWM Cycle & TEST Counter Timer * +// ************************************************************ +// if (use_upper_current == false) pwm_duty_cycle = pwm_duty_low; +// if (use_upper_current == true) pwm_duty_cycle = pwm_duty_high; +// +// if (TESTCOUNTER > 1800) control_pilot = PWM_CHANGE; // Each cycle takes approximately 1 second, so 1800 seconds is a change of pwm every 30 mins or so. +// * TESTERCOUNTER monitoring is switched of for the Smartcharge Home+ charger, PWN cycle based on a cable inserted +// +// ************************************************************ + +// ************************************************************ +// * PWM cycle basen on cable instered * +// ************************************************************ + if (cable_32A == false) pwm_duty_cycle = pwm_duty_low; + if (cable_32A == true) pwm_duty_cycle = pwm_duty_high; + + + + switch(control_pilot) + { + case PILOT_12V: + contactor = 0; + lock = 0; + red = 0; + green = 0; + blue = 1; + my_pwm = 0; + pwm_state = false; + pc.printf("Charger in STATE A. \r\n"); + pc.printf("PILOT_12V - Pilot at 12 V. \r\n"); + TESTCOUNTER = 0; + break; + + case PILOT_9V: + contactor = 0; + //relay=0; + lock = 1; + red = 1; + green = 1; + blue = 0; + if (pwm_state == false) + { + my_pwm.period_us(1000); + my_pwm.pulsewidth_us(1000); + my_pwm.write(pwm_duty_cycle); + pwm_state = true; + } + pc.printf("PWM duty cycle is at: %.1f %% \r\n", 100-pwm_duty_cycle*100); + pc.printf("Charger in STATE B. \r\n"); + pc.printf("PILOT_9V - Pilot at 9 V. \r\n"); + TESTCOUNTER = 0; + break; + + case PILOT_6V: + contactor = 1; + relay = 1; + lock = 1; + red = 0; + green = 1; + blue = 0; + if (pwm_state == false) + { + my_pwm.period_us(1000); + my_pwm.pulsewidth_us(1000); + my_pwm.write(pwm_duty_cycle); + pwm_state = true; + } + pc.printf("PWM duty cycle is at: %.1f %% \r\n", 100-pwm_duty_cycle*100); + pc.printf("Charger in STATE C. \r\n"); + pc.printf("PILOT_6V - Pilot at 6 V. \r\n"); +// TESTCOUNTER+=1; +// * TESTCOUNTER switched of + pc.printf("TESTCOUNTER timer: %u seconds \r\n", TESTCOUNTER); + break; + + case PILOT_NOK: + lock = 0; + red = 1; + green = 0; + blue = 0; + pc.printf("Error. \r\n"); + pc.printf("PILOT_NOK - Pilot ERROR. \r\n"); + TESTCOUNTER = 0; + break; + + case PILOT_RESET: + contactor = 0; + relay = 0; + lock = 0; + red = 0; + green = 0; + blue = 1; + my_pwm.period_ms(1); + my_pwm.pulsewidth_ms(1); + my_pwm.write(1); + pwm_state = false; + pc.printf("RESET IMPLEMENTED. \r\n"); + pc.printf("PILOT_RESET - Pilot at -12V. \r\n"); + wait(0.5); // 500 ms + red = 0; // LED is OFF + wait(0.2); // 200 ms + TESTCOUNTER = 0; + use_upper_current = false; + break; + + case PWM_CHANGE: + lock = 1; + contactor = 0; + red = 1; + green = 1; + blue = 1; + wait(0.1); + pc.printf("Charger changing PWM. \r\n"); + my_pwm.period_ms(1); + my_pwm.pulsewidth_ms(1); + my_pwm.write(1); + wait(1); + pc.printf("STOPPED PWM - Switching to -12 V. \r\n"); + my_pwm = 0; + pc.printf("STOPPED PWM - Switching to +12 V. \r\n"); + wait(1); + pwm_state = false; + TESTCOUNTER = 0; + if(use_upper_current == false) + { + use_upper_current = true; + } + else + { + use_upper_current = false; + } + break; + } + pc.printf("#################\r\n"); + //wait(1); // wait(); added to slow down the feed from nucleo for easier evaluation + } +} \ No newline at end of file