CUER
/
charger_code
Code to run on the charger board (used to charge the car from the mains).
charger.cpp
- Committer:
- DasSidG
- Date:
- 2017-07-06
- Revision:
- 1:0c77e20b4d4c
- Parent:
- 0:6d930d0d13a1
- Child:
- 2:da91931184de
File content as of revision 1:0c77e20b4d4c:
#include "charger.h" #include "mbed.h" #include "CAN_Data.h" #include "CAN_IDs.h" #include "Data_types.h" #include "CANParserCharger.h" using namespace CAN_IDs; void car_interruptHandler(); void car_CANDataSentCallback(); void charger_interruptHandler(); void charger_CANDataSentCallback(); void init(); void get_CAN_data(); void calculate_current(float voltage_error, float temp_margin, float *current, float *voltage); void check_timeouts(); void update_LEDS(); bool idAccepted(int id); timeouts_t timeouts; //CAN stuff. Not that there are two sets because there are two separate CAN buses here; one to communicate with the charger, and one to communicate with the rest of the car (importantly the BMS). //The reason that there are two separate CAN buses is because the charger uses the extended CAN frame format, with a 29 bit ID, whereas the car uses the default 11 bit ID. CAN car_can(CAR_CAN_READ_PIN, CAR_CAN_WRITE_PIN); //Create a CAN object to handle CAN comms CANMessage car_buffer[CAN_BUFFER_SIZE]; //CAN receive buffer bool car_safe_to_write[CAN_BUFFER_SIZE]; //Semaphore bit indicating that it's safe to write to the software buffer bool car_CAN_data_sent = false; CAN charger_can(CHARGER_CAN_READ_PIN, CHARGER_CAN_WRITE_PIN); //Create a CAN object to handle CAN comms CANMessage charger_buffer[CAN_BUFFER_SIZE]; //CAN receive buffer bool charger_safe_to_write[CAN_BUFFER_SIZE]; //Semaphore bit indicating that it's safe to write to the software buffer bool charger_CAN_data_sent = false; int main() { init(); while(1) { //Reset error indicators comms_timeout = false; charger_failure = false; bms_error = false; //get the various data from the CAN packets get_CAN_data(); check_timeouts(); update_LEDS(); //TODO: add logic here to calculate current and then decide if charging should go ahead //send CAN data charger_can.write(generate_charger_control_msg(desired_voltage, desired_current, charger_control)); //control message to charger car_can.write(generate_charger_info_msg(charger_voltage, charger_current, charger_status)); //charger info message for rest of car //send charge_finished value to control bit. printf("Voltage Error = %f\n", voltage_error); printf("Temperature Margin = %f\n", temp_margin); printf("Desired Voltage = %f\n", desired_voltage); printf("Desired Current = %f\n", desired_current); printf("Voltage = %f\n", charger_voltage); printf("Current = %f\n", charger_current); printf("Min cell voltage = %f\n", min_cell_voltage); printf("Max cell voltage = %f\n", max_cell_voltage); } } void calculate_current(float voltage_error, float temp_margin, float *current, float *voltage){ float Idot, I; static bool balancing = false; I = *current; if (I < 0.8 && voltage_error < 0.1 || balancing) { balancing = true; printf("balancing\r\n"); Idot = voltage_error*KI_BALANCE; } else { Idot = voltage_error*KI_CHARGE; } I += Idot*TIME_STEP/1000.0; if(I > MAX_CURRENT) { I = MAX_CURRENT; } if(I < 0) { I = 0; } //Reduce current if temperature is too high if (temp_margin > TEMP_RAMP_START) { I = 1 - ((temp_margin - TEMP_RAMP_START) / (TEMP_RAMP_FINISH - TEMP_RAMP_START)); } if (temp_margin > TEMP_RAMP_FINISH) { I *= 0; } *current = I; *voltage = MAX_VOLTAGE; } void init() { for(int i=0; i<CAN_BUFFER_SIZE; i++) { car_buffer[i].id = BLANK_ID; //("%d",buffer[i].id); car_safe_to_write[i]= true; charger_buffer[i].id = BLANK_ID; //("%d",buffer[i].id); charger_safe_to_write[i]= true; } //Initialise CAN stuff, attach CAN interrupt handlers car_can.frequency(CAN_BIT_RATE); //set transmission rate to agreed bit rate car_can.reset(); car_can.attach(&car_interruptHandler, CAN::RxIrq); //receive interrupt handler car_can.attach(&car_CANDataSentCallback, CAN::TxIrq); //send interrupt handler charger_can.frequency(CHARGER_CAN_BIT_RATE); //set transmission rate to agreed bit rate charger_can.reset(); charger_can.attach(&charger_interruptHandler, CAN::RxIrq); //receive interrupt handler charger_can.attach(&charger_CANDataSentCallback, CAN::TxIrq); //send interrupt handler //Start comms timeout timers timeouts.BMS_timeout.start(); timeouts.charger_timeout.start(); } void car_CANDataSentCallback(void) { car_CAN_data_sent = true; } void charger_CANDataSentCallback(void) { charger_CAN_data_sent = true; } void car_interruptHandler() { CANMessage msg; car_can.read(msg); //if(DEBUG) printf("id %d incoming \r\n", msg.id); if(idAccepted(msg.id)) { for(int i=0; i<CAN_BUFFER_SIZE; i++) { if((car_buffer[i].id == msg.id || car_buffer[i].id==BLANK_ID) && car_safe_to_write[i]) { //("id %d added to buffer \r\n", msg.id); car_buffer[i] = msg; //return required so that only first blank buffer entry is converted to incoming message ID each time new message ID is encountered return; } } } } void charger_interruptHandler() { CANMessage msg; charger_can.read(msg); //if(DEBUG) printf("id %d incoming \r\n", msg.id); if(idAccepted(msg.id)) { for(int i=0; i<CAN_BUFFER_SIZE; i++) { if((charger_buffer[i].id == msg.id || charger_buffer[i].id==BLANK_ID) && charger_safe_to_write[i]) { //("id %d added to buffer \r\n", msg.id); charger_buffer[i] = msg; //return required so that only first blank buffer entry is converted to incoming message ID each time new message ID is encountered return; } } } } bool idAccepted(int id) { switch(id) { case BMS_BASE_ID: timeouts.BMS_timeout.reset(); return true; case BMS_BASE_ID + CHARGER_CONTROL_INFO_ID: return true; case BMS_BASE_ID + MAX_MIN_VOLTAGE: return true; case BMS_BASE_ID + BATTERY_STATUS_ID: return true; case CHARGER_VI_INFO_ID: timeouts.charger_timeout.reset(); return true; default: return false; } } void check_timeouts() //Check if it's been too long since any of the other devices in the car have communicated { if (timeouts.BMS_timeout.read_ms() > BMS_MSG_TIMEOUT_MS) { printf("Error: BMS comms timeout"); comms_timeout = true; } if (timeouts.charger_timeout.read_ms() > CHARGER_MSG_TIMEOUT_MS) { printf("Error: BMS comms timeout"); comms_timeout = true; } } void update_LEDS() { if (charger_failure || bms_error) { desired_current = 0; red_led = 1; } else if (comms_timeout) { desired_current = 0; yellow_led = 1; } else if (!charge_finished) { green_led = 1; } else { red_led = 0; yellow_led = 0; green_led = 0; } if (min_cell_voltage > RISING_BALANCE_THRESHOLD) { charge_finished = true; printf("Charge Finished\r\n"); //set charger control bit to finished charging } else { calculate_current(voltage_error, temp_margin, &desired_current, &desired_voltage); charge_finished = false; } } void get_CAN_data() { //Import the data from the buffer into a non-volatile, more usable format CAN_Data car_can_data[CAN_BUFFER_SIZE]; //container for all of the raw data CANMessage car_msgArray[CAN_BUFFER_SIZE]; //Same as above but some functions take message as their parameter int car_received_CAN_IDs[CAN_BUFFER_SIZE]; //needed to keep track of which IDs we've received so far for (int i = 0; i<CAN_BUFFER_SIZE; ++i) { car_safe_to_write[i] = false; car_can_data[i].importCANData(car_buffer[i]); car_received_CAN_IDs[i] = car_buffer[i].id; car_msgArray[i] = car_buffer[i]; car_safe_to_write[i] = true; //Now actually import the data from the CAN packets into the global variables switch (car_received_CAN_IDs[i]) { case BMS_BASE_ID: break; case BMS_BASE_ID + CHARGER_CONTROL_INFO_ID: get_charger_control_info(car_msgArray[i], voltage_error, temp_margin, discharge_error, pack_capacity); break; case BMS_BASE_ID + MAX_MIN_VOLTAGE: get_max_min_voltage(car_msgArray[i], min_cell_voltage, max_cell_voltage); break; case BMS_BASE_ID + BATTERY_STATUS_ID: get_battery_status(car_msgArray[i], bms_error); break; case BLANK_ID: //This means we haven't received this type of message yet, so do nothing break; default: break; } } //Import the data from the buffer into a non-volatile, more usable format CAN_Data charger_can_data[CAN_BUFFER_SIZE]; //container for all of the raw data CANMessage charger_msgArray[CAN_BUFFER_SIZE]; //Same as above but some functions take message as their parameter int charger_received_CAN_IDs[CAN_BUFFER_SIZE]; //needed to keep track of which IDs we've received so far for (int i = 0; i<CAN_BUFFER_SIZE; ++i) { charger_safe_to_write[i] = false; charger_can_data[i].importCANData(charger_buffer[i]); charger_received_CAN_IDs[i] = charger_buffer[i].id; charger_msgArray[i] = charger_buffer[i]; charger_safe_to_write[i] = true; //Now actually import the data from the CAN packets into the global variables switch (charger_received_CAN_IDs[i]) { case CHARGER_VI_INFO_ID: get_charger_VI_info(charger_msgArray[i], charger_voltage, charger_current, charger_status); if(charger_status bitand 1 == 1) { printf("Charger status: Hardware Failure\r\n"); charger_failure = true; } if(charger_status bitand 2 == 2) { printf("Charger status: Over Temperature\r\n"); charger_failure = true; } if(charger_status bitand 4 == 4) { printf("Charger status: Input Voltage Wrong\r\n"); charger_failure = true; } if(charger_status bitand 8 == 8) { printf("Charger status: Reverse Polarity\r\n"); charger_failure = true; } if(charger_status bitand 16 == 16) { printf("Charger status: communication timeout\r\n"); charger_failure = true; } break; case BLANK_ID: //This means we haven't received this type of message yet, so do nothing break; default: break; } } }