In: Electrical Engineering
arduino firmware coding for bidirectional closed loop buck boost converter pwm signal
Arduino Microcontroller Code
// IPFW Senior Engineering Design
// Fall 2013 & Spring 2014
// Group Members:
// David Spaulding
// Derek Krebs
// Steve Danielak
// John Haverstock
// Project Advisor: Dr. Eroglu
// This code was developed for control and interface with the
// bidirectional dcdc converter drive for an electric vehicle
// Written by Derek Krebs and David Spaulding
// Code developed for the Arduino Mega 2560
// Include the LCD library
#include <LiquidCrystal.h>
// Establish variable names for each I/O pin used
const int pwm_M = 9; // PWM for MOSFET Q4, inverted signal to Q9
const int pwm_B = 11; // PWM for MOSFET Q5, inverted signal to Q10
const int potPin = A0; // Connected to the potentiometer's output
const int TachPin = A1; // Connected to Tachometer Signal
const int MotorIsense = A2; // Connected to Motor Current Sense
const int MotorVsense = A3; // Connected to Motor Voltage Sense
const int BattIsense = A4; // Connected to Battery Current Sense
const int BattVsense = A5; // Connected to Battery Voltage Sense
const int directionSwitchPin = 22; // Connected to the switch for direction
const int brakeSwitchPin = 24; // Connected to the button for braking
const int LCDrs = 43; // LCD RS Connection //26
const int LCDen = 45; // LCD EN Connection
const int LCDd4 = 47; // LCD D4 Connection
const int LCDd5 = 49; // LCD D5 Connection
const int LCDd6 = 51; // LCD D6 Connection
const int LCDd7 = 53; // LCD D7 Connection //36
const int BLDCRotate = 38; // Rotation signal to BLDC Chip
const int enBLDC = 40; // Enable signal for BLDC Chip
const int sdConverterFETdrive = 42; // Enable signal to Converter FET Drivers
const int sdCommutatorFETdrive = 44; // Enable signal to Commutator FET Drivers
const int enLowSideFans = 26; // Enable Signal for Low Side Fan FET Gate
const int enHighSideFans = 28; // Enable Signal for High Side Fan FET Gate
// Establish values to be used for a moving average filter for each analog value being
read in
/*
Smoothing
Reads repeatedly from an analog input, calculating a running average
and printing it to the computer. Keeps ten readings in an array and
continually averages them.
*/
const int RPMnumReadings = 400;
long RPMreadings[RPMnumReadings]; // the readings from the analog input
int RPMindex = 0; // the index of the current reading
long RPMtotal = 0; // the running total
long RPMaverage = 0; // the average
const int POTnumReadings = 400;
int POTreadings[POTnumReadings]; // the readings from the analog input
int POTindex = 0; // the index of the current reading
long POTtotal = 0; // the running total
float POTaverage = 0; // the average
const int BVnumReadings = 400;
int BVreadings[BVnumReadings]; // the readings from the analog input
int BVindex = 0; // the index of the current reading
long BVtotal = 0; // the running total
float BVaverage = 0; // the average
const int MVnumReadings = 400;
int MVreadings[MVnumReadings]; // the readings from the analog input
int MVindex = 0; // the index of the current reading
long MVtotal = 0; // the running total
float MVaverage = 0; // the average
const int BInumReadings = 400;
int BIreadings[BInumReadings]; // the readings from the analog input
int BIindex = 0; // the index of the current reading
long BItotal = 0; // the running total
int BIaverage = 0; // the average
const int MInumReadings = 400;
int MIreadings[MInumReadings]; // the readings from the analog input
int MIindex = 0; // the index of the current reading
long MItotal = 0; // the running total
int MIaverage = 0; // the average
// Establish variables used within the program and initialize to zero
int brakeSwitch = 0; // State of the Brake switch
int directionSwitch = 0; // State of the direction switch
int dCycle = 0; // Integer value of duty cycle
int batteryVref = 0; // Battery Reference Voltage
float motorVref = 0; // Value of potentiometer input to a working voltage reference
float motorV = 0; // Value of motor voltage
float batteryV = 0; // Value of battery voltage
int motorI = 0; // Value of motor current
int batteryI = 0; // Value of battery current
int efficiency=0;
long rpm = 0; // Integer value of motor rotational speed
int startup = 0; // Variable used for startup check
int displaycounter=0;
// Initialize the LCD display with the numbers of the interface pins
// Pins are: (RS, EN, D4, D5, D6, D7)
LiquidCrystal lcd(LCDrs, LCDen, LCDd4, LCDd5, LCDd6, LCDd7);
void setup(){
// Establish PWM outputs to operate at 31.3kHz
TCCR1B = TCCR1B & B11111000 | B00000001;
TCCR2B = TCCR2B & B11111000 | B00000001;
// intialize the inputs and outputs
pinMode(directionSwitchPin, INPUT);
pinMode(brakeSwitchPin, INPUT);
pinMode(pwm_M, OUTPUT);
pinMode(pwm_B, OUTPUT);
pinMode(enBLDC, OUTPUT);
pinMode(BLDCRotate, OUTPUT);
pinMode(enLowSideFans, OUTPUT);
pinMode(enHighSideFans, OUTPUT);
pinMode(sdConverterFETdrive, OUTPUT);
pinMode(sdCommutatorFETdrive, OUTPUT);
// set up the LCD's number of columns and rows:
lcd.begin(20, 4);
// set all initial signals low to avoiding floating levels
digitalWrite(pwm_M, LOW);
digitalWrite(pwm_B, LOW);
digitalWrite(enBLDC, LOW);
digitalWrite(enLowSideFans, LOW);
digitalWrite(enHighSideFans, LOW);
digitalWrite(sdConverterFETdrive, HIGH);
digitalWrite(sdCommutatorFETdrive, HIGH);
// loops to establish the averaging functions of each analog input
for (int RPMthisReading = 0; RPMthisReading < RPMnumReadings; RPMthisReading++)
RPMreadings[RPMthisReading] = 0;
for (int POTthisReading = 0; POTthisReading < POTnumReadings; POTthisReading++)
POTreadings[POTthisReading] = 0;
for (int BVthisReading = 0; BVthisReading < BVnumReadings; BVthisReading++)
BVreadings[BVthisReading] = 0;
for (int MVthisReading = 0; MVthisReading < MVnumReadings; MVthisReading++)
MVreadings[MVthisReading] = 0;
for (int BIthisReading = 0; BIthisReading < BInumReadings; BIthisReading++)
BIreadings[BIthisReading] = 0;
for (int MIthisReading = 0; MIthisReading < MInumReadings; MIthisReading++)
MIreadings[MIthisReading] = 0;
}
void loop(){
// When the system is powered on with the throttle high, prompt user to
// turn throttle to zero to avoid large initial current surges
while(startup==0){
lcd.setCursor(0,0);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print("Set throttle to zero");
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(0,3);
lcd.print(" ");
motorVref = (analogRead(potPin)); // read in potentiometer output reference
delay(1);
motorVref = ((analogRead(potPin)*45.0)/1023); // read in potentiometer reference
if(motorVref<1){
startup=1;
}
}
// read the value of the brake switch
brakeSwitch = digitalRead(brakeSwitchPin);
// read the value of direction switch
directionSwitch = digitalRead(directionSwitchPin);
batteryVref = 55; //Battery charging level for regenerative mode
// Moving average calculation:
MVtotal= MVtotal - MVreadings[MVindex];
// read from the sensor:
MVreadings[MVindex] = analogRead(MotorVsense);
delay(0.5); // delay in between reads for
stability
MVreadings[MVindex] = analogRead(MotorVsense);
// add the reading to the total:
MVtotal= MVtotal + MVreadings[MVindex];
// advance to the next position in the array:
MVindex = MVindex + 1;
// if we're at the end of the array...
if (MVindex >= MVnumReadings)
// ...wrap around to the beginning:
MVindex = 0;
// Moving average calculation:
MVaverage = MVtotal / MVnumReadings;
motorV = (MVaverage*0.0775)+0.0473;
// subtract the last reading:
BVtotal= BVtotal - BVreadings[BVindex];
// read from the sensor:
BVreadings[BVindex] = analogRead(BattVsense);
delay(0.5); // delay in between reads for
stability
BVreadings[BVindex] = analogRead(BattVsense);
// add the reading to the total:
BVtotal= BVtotal + BVreadings[BVindex];
// advance to the next position in the array:
BVindex = BVindex + 1;
// if we're at the end of the array...
if (BVindex >= BVnumReadings)
// ...wrap around to the beginning:
BVindex = 0;
// calculate the average:
BVaverage = BVtotal / BVnumReadings;
batteryV = (BVaverage*0.0638)+0.223;
// Moving average calculation:
BItotal= BItotal - BIreadings[BIindex];
// read from the sensor:
BIreadings[BIindex] = analogRead(BattIsense);
delay(0.5); // delay in between reads for
stability
BIreadings[BIindex] = analogRead(BattIsense);
// add the reading to the total:
BItotal= BItotal + BIreadings[BIindex];
// advance to the next position in the array:
BIindex = BIindex + 1;
// if we're at the end of the array...
if (BIindex >= BInumReadings)
// ...wrap around to the beginning:
BIindex = 0;
// calculate the average:
BIaverage = BItotal / BInumReadings;
batteryI = ((BIaverage*3675L)-1902300L)/10000;
// Moving average calculation:
MItotal= MItotal - MIreadings[MIindex];
// read from the sensor:
MIreadings[MIindex] = analogRead(MotorIsense);
delay(0.5); // delay in between reads for
stability
MIreadings[MIindex] = analogRead(MotorIsense);
// add the reading to the total:
MItotal= MItotal + MIreadings[RPMindex];
// advance to the next position in the array:
MIindex = MIindex + 1;
// if we're at the end of the array...
if (MIindex >= MInumReadings)
// ...wrap around to the beginning:
MIindex = 0;
// calculate the average:
MIaverage = MItotal / MInumReadings;
motorI= ((MIaverage*3675L)-1894700L)/10000; //calibrated based on the current
sensor datasheet
// Moving average calculation:
POTtotal= POTtotal - POTreadings[POTindex];
// read from the sensor:
POTreadings[POTindex] = analogRead(potPin);
delay(0.5); // delay in between reads for
stability
POTreadings[POTindex] = analogRead(potPin);
// add the reading to the total:
POTtotal= POTtotal + POTreadings[POTindex];
// advance to the next position in the array:
POTindex = POTindex + 1;
// if we're at the end of the array...
if (POTindex >= POTnumReadings)
// ...wrap around to the beginning:
POTindex = 0;
// calculate the average:
POTaverage = POTtotal / POTnumReadings;
motorVref = (POTaverage*45)/1023; // read in potentiometer reference
// Moving average calculation:
RPMtotal= RPMtotal - RPMreadings[RPMindex];
// read from the sensor:
RPMreadings[RPMindex] = analogRead(TachPin);
delay(0.5); // delay in between reads for
stability
RPMreadings[RPMindex] = analogRead(TachPin);
// add the reading to the total:
RPMtotal= RPMtotal + RPMreadings[RPMindex];
// advance to the next position in the array:
RPMindex = RPMindex + 1;
// if we're at the end of the array...
if (RPMindex >= RPMnumReadings)
// ...wrap around to the beginning:
RPMindex = 0;
// calculate the average:
RPMaverage = RPMtotal / RPMnumReadings;
// send it to the computer as ASCII digits
rpm = RPMaverage;
if (rpm<1)
rpm=0;
else
rpm=(RPMaverage*57774L+184730L)/10000L;
// only allow motor to change direction if speed is low
if (rpm<60){
digitalWrite(BLDCRotate, directionSwitch);
}
//stop motor rotation for very low throttle references
if (motorVref<1){
digitalWrite(enBLDC, LOW);
}
digitalWrite(enHighSideFans, HIGH);
digitalWrite(enLowSideFans, HIGH);
if (brakeSwitch == 0){
// Drive mode
if (motorVref<1){
digitalWrite(enBLDC, LOW);
}
else{
digitalWrite(enBLDC, HIGH);
}
digitalWrite(sdConverterFETdrive, LOW);
digitalWrite(sdCommutatorFETdrive, LOW);
if (motorVref > batteryV) {
// Boost
dCycle = 255-(((1 - ((batteryV)/motorVref))*255));
if (dCycle>=250)
dCycle=250;
if (dCycle<=5)
dCycle=5;
analogWrite(pwm_M,dCycle);
analogWrite(pwm_B,250);
}
else {
// Buck
dCycle = ((((motorVref)/batteryV)*255));
if (dCycle>=250)
dCycle=250;
if (dCycle<=5)
dCycle=5;
analogWrite(pwm_M,250);
analogWrite(pwm_B,dCycle);
}
}
else {
//Regenerative Braking Mode
digitalWrite(enBLDC, LOW);
digitalWrite(sdConverterFETdrive, LOW);
digitalWrite(sdCommutatorFETdrive, LOW);
if (motorV > batteryVref) {
// Buck
dCycle = ((((batteryVref)/motorV)*255));
if (dCycle>=250)
dCycle=250;
if (dCycle<=5)
dCycle=5;
analogWrite(pwm_M,dCycle);
analogWrite(pwm_B,250);
}
else {
// Boost
dCycle = 255-(((1-((motorV)/batteryVref))*255));
if (dCycle>=250)
dCycle=250;
if (dCycle<=5)
dCycle=5;
analogWrite(pwm_M,250);
analogWrite(pwm_B,dCycle);
}
}
// Update the LCD display every 400 cycles
displaycounter = displaycounter+1;
if (displaycounter==400){
//Print characters on the screen
//Set cursor with setCursor(column,row)
lcd.setCursor(0,0);
lcd.print("Battery: V ");
lcd.setCursor(0,1);
lcd.print("Motor: V ");
lcd.setCursor(0,2);
lcd.print("Motor Speed: RPM");
lcd.setCursor(0,3);
lcd.print(" ");
lcd.setCursor(9,0);
lcd.print(batteryV);
lcd.setCursor(13,0);
lcd.print("V ");
lcd.setCursor(9,1);
lcd.print(motorV);
lcd.setCursor(13,1);
lcd.print("V ");
lcd.setCursor(13,2);
lcd.print(rpm);
lcd.setCursor(17,2);
lcd.print("RPM");
displaycounter = 0;
}
}