// para Arduino nano
#include <avr/wdt.h>
//#include <TimerOne.h>
#define TIMER1_COMPB_vect _VECTOR(12) // con esto no mejora
// Pin definitions
#define Relay_1_Pin1 6
#define Relay_1_Pin2 7
#define Relay_2_Pin1 8
#define Relay_2_Pin2 9
#define Pilot_PWM_Pin 10
#define GFCI_Test_Pin 11
#define Indicator_LED 13
#define GFCI_ADC_Pin A0
#define Pilot_ReadADC_Pin A1
// State and fault definitions
#define STATE_A 1 // No EV connected
#define STATE_B 2 // EV Connected but not charging
#define STATE_C 3 // Charging
#define CHARGE_PWM_DUTY 4000 //350 // Seems to result in 7.4 kW charging rate. (Lower numbers = higher duty cycle and charge rates)
#define _12_VOLTS 12
#define _9_VOLTS 9
#define _6_VOLTS 6
#define _3_VOLTS 3
#define _DIODE_FAULT 1 // el diodo del circuito del vehiculo??
#define _FAULT 0
#define FAIL 0
#define PASS 1
#define STARTUP_GFCI_TEST_FAIL 2
#define GFCI_DETECT 3
#define DIODE_FAULT 4
#define VOLTAGE_CLASS_FAULT 5
#define START_CHARGE_GFCI_TEST_FAIL 6
// ADC ranges for classifying voltage levels (923 = 12v and 285 = -12v)
#define POS_12V_MAX 936 // 12.5V, 12v --> 4,51v
#define POS_12V_MIN 910 // 11.5V
#define POS_9V_MAX 868 // 10V
#define POS_9V_MIN 815 // 8V
#define POS_6V_MAX 789 // 7V
#define POS_6V_MIN 735 // 5V
#define POS_3V_MAX 708 // 4V
#define POS_3V_MIN 656 // 2V
#define NEG_12V_MAX 327 // -11.5v
#define NEG_12V_MIN 245 // -12,5
// GFCI
#define GFCI_FAULT_THRESHOLD 300
#define GFCI_FAULT_ABORT_THRESHOLD 500
#define FAULT_COUNT_THRESHOLD 10
// Global variable definitions (no bueno !!!!!)
volatile int Pilot_Low_ADC = 320; // originalmente no estban con valor
volatile int Pilot_High_ADC = 930;
volatile int GFCI_ADC;
volatile byte ADC_Channel = 0;
volatile int cont_print_COMP = 0; // para mis pruebas
volatile int cont_print_OVF = 0; // para mis pruebas
volatile byte PVC_prub = 0; // ""
// Declaración de funciones
void Close_Relays();
void Open_Relays();
byte Read_Pilot_Voltage();
byte GFCI_Test();
void Fault_Handler(byte Fault_type);
// ========================================================
void setup() {
cont_print_COMP = 0; // pruebas
cont_print_OVF = 0;
PVC_prub = 0; // ""
delay(500);
noInterrupts();
Serial.begin(115200);
Serial.println("starting up...");
pinMode(Indicator_LED, OUTPUT);
// Abrir Reles
Open_Relays();
pinMode(Pilot_PWM_Pin, OUTPUT); // Configue Pin 10 for PWM output 1kHz.
// -------- Configure Timer 1 ---------
ICR1 = 4000; //1000 PWM-freq=16MHz/(2*8*1000)=1kHz, con prescaler = 8
TCCR1A = 0;
TCCR1B = 0;
TCCR1A = 0b00100010; // PWM
TCCR1B = 0b00010010; // Prescaler: WGM13 =1 prescaler = 8 (0b00010010;)
OCR1B = 100; // Duty Cicle, PWM pin 10, originalmente a 0;
TIMSK1 |= 1 << TOIE1; // enable Timer Overflow Interrupt (ahora convierte los 3 canales)
// al ponerla el ADC no convierte
TIMSK1 |= 1 << OCIE1B; // No funciona??enable Timer triggered when timer counter matches OCR1B (Output Compare Register B).
// --------- Configure ADC Module -------
ADMUX = B01000000; // AREF = 1, Referencua =5v (Vcc)
ADCSRA = B10001111; // Prescaler=128; 16MHz/ 128=125KHz, 125KHz/13clocks=9,615Khz
// (ADC Sampling rate)=104uS (one conversion period)
// ADEN=1, Enable ADC
// Enable Watch Dog 4seg
// wdt_enable(WDTO_4S);
// wdt_reset(); // quitados de momento
interrupts(); // habilita interrupciones
if(GFCI_Test() != PASS) { // al habilitar este código entra en las 2 interrupciones
Fault_Handler(STARTUP_GFCI_TEST_FAIL);
}
OCR1B = 300; // originalmente 0 (no funciona con 0) Duty Cicle= (OCR1B+1)/2^16
/*while(1) { // solo para pruebas del ADC
delay(100);
// prueba para Leer Pilot_High_ADC
ADMUX = B01000001; // pruebas when the PWM signal is in the middle of its high period
ADCSRA |= B01000000; // Start ADC, funciona lee el potenciómetro
ADC_Channel = 2;
Serial.print(Pilot_Low_ADC); Serial.print(", ");
Serial.print(Pilot_High_ADC); Serial.print(", ");
Serial.println(GFCI_ADC);
} */
// Ready to start main loop
Serial.println("Starting in State A");
}
// ===========================================================
void loop() {
/* solo pruebas */
// increm de contadores en las inerrupciones
if (cont_print_COMP >= 100 and cont_print_OVF >= 100) {
Serial.print(PVC_prub); Serial.print(", ");
Serial.print(cont_print_COMP + cont_print_OVF); Serial.print(": ");
Serial.print(Pilot_Low_ADC); Serial.print(", ");
Serial.print(Pilot_High_ADC);Serial.print(", ");
Serial.println(GFCI_ADC);
cont_print_COMP = 0;
cont_print_OVF = 0;
}
static byte Current_State = STATE_A;
static byte PVC;
// wdt_reset(); // quitado de momento
delay(10);
PVC = Read_Pilot_Voltage(); // llamada a la Función
PVC_prub=PVC; // para las pruebs
// ---- Fault detection ------------------------
if(GFCI_ADC > GFCI_FAULT_THRESHOLD)
Fault_Handler(GFCI_DETECT);
if(PVC == _DIODE_FAULT) // si == 1
Fault_Handler(DIODE_FAULT); // llama a la función con 4
if(PVC == _FAULT) // si == 0
Fault_Handler(VOLTAGE_CLASS_FAULT); // 5
// PVC = Pilot Voltage Classification
// ---- Main State machine logic ------------
switch (Current_State) {
case STATE_A:
if(PVC == _9_VOLTS or PVC == _6_VOLTS or PVC == _3_VOLTS) {
OCR1B = 500; // pruebas originalmente OCR1B = 0;
digitalWrite(Indicator_LED, HIGH);
Serial.println("State B");
Current_State = STATE_B;
}
break;
case STATE_B:
if(PVC == _12_VOLTS) {
OCR1B = 0; // pruebas originalmente OCR1B = 0;
digitalWrite(Indicator_LED, LOW);
Serial.println("State A");
Current_State = STATE_A;
}
else if(PVC == _6_VOLTS or PVC == _3_VOLTS) {
if(GFCI_Test() != PASS) {
Fault_Handler(START_CHARGE_GFCI_TEST_FAIL);
}
else {
Serial.println("State C");
Close_Relays();
Current_State = STATE_C;
}
}
break;
case STATE_C:
if(PVC == _12_VOLTS or PVC == _9_VOLTS) {
Open_Relays();
Serial.println("State B");
Current_State = STATE_B;
}
break;
}
} // de void loop()
// ############################################################
// -------------- Funciones -------------------------
// ############################################################
byte Read_Pilot_Voltage()
{
static int Fault_Count = 0;
static int Previous_Value = _12_VOLTS;
// Here we take the Pilot voltages and classfy them into states
if((Pilot_Low_ADC > NEG_12V_MIN and Pilot_Low_ADC < NEG_12V_MAX) or OCR1B == 0) {
if(Pilot_High_ADC > POS_12V_MIN and Pilot_High_ADC < POS_12V_MAX) {
Previous_Value = _12_VOLTS; Fault_Count = 0;
return(_12_VOLTS);
}
else if(Pilot_High_ADC > POS_9V_MIN and Pilot_High_ADC < POS_9V_MAX) {
Previous_Value = _9_VOLTS; Fault_Count = 0;
return(_9_VOLTS);
}
else if(Pilot_High_ADC > POS_6V_MIN and Pilot_High_ADC < POS_6V_MAX) {
Previous_Value = _6_VOLTS; Fault_Count = 0;
return(_6_VOLTS);
}
else if(Pilot_High_ADC > POS_3V_MIN and Pilot_High_ADC < POS_3V_MAX) {
Previous_Value = _3_VOLTS; Fault_Count = 0;
return(_3_VOLTS);
}
else {
// The measured voltage is out of any expected range. We call this a fault condition
Fault_Count++;
if(Fault_Count > FAULT_COUNT_THRESHOLD) // si > 10
return(_FAULT); // return 0
else
return(Previous_Value);
}
}
else {
// Diode fault - the negative PWM should always be -12v, if it's not we have a diode missing fault!
Fault_Count++;
if(Fault_Count > FAULT_COUNT_THRESHOLD)
return(_DIODE_FAULT); // return 1
else
return(Previous_Value);
}
}
// ############################################################
void Fault_Handler(byte Fault_type)
{
Open_Relays();
OCR1B = 0; // originalmente 0
Serial.print("FAULT: "); Serial.print(Fault_type);
while(1) { // se queda parpadeando el diodo LED 13
delay(100);
digitalWrite(Indicator_LED, HIGH);
delay(100);
digitalWrite(Indicator_LED, LOW);
// wdt_reset(); // quitado de momento
}
}
// ############################################################
byte GFCI_Test() // This routine energises the test coil on the current transformer using a 50Hz square wave
{ // de momento siempre pasa el test
return(PASS);
}
void Close_Relays()
{
pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);
digitalWrite(Relay_1_Pin1, HIGH); digitalWrite(Relay_2_Pin1, HIGH);
digitalWrite(Relay_1_Pin2, HIGH); digitalWrite(Relay_2_Pin2, HIGH);
pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT); //añadirlo bién
digitalWrite(Relay_1_Pin1, HIGH); digitalWrite(Relay_2_Pin1, HIGH);
digitalWrite(Relay_1_Pin2, HIGH); digitalWrite(Relay_2_Pin2, HIGH); // añadirlo bién
}
void Open_Relays()
{
pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);
digitalWrite(Relay_1_Pin1, LOW); digitalWrite(Relay_2_Pin1, LOW);
digitalWrite(Relay_1_Pin2, LOW); digitalWrite(Relay_2_Pin2, LOW);
pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);
digitalWrite(Relay_1_Pin1, LOW); digitalWrite(Relay_2_Pin1, LOW);
digitalWrite(Relay_1_Pin2, LOW); digitalWrite(Relay_2_Pin2, LOW);
}
// ##################################################################
// -------------------- Interrupciones ------------------
// ###################################################################
// This code runs when the PWM signal is in the middle of its low period
ISR(TIMER1_OVF_vect)
{
static byte selector = 0;
if(ADCSRA & 0b01000000) // If the ADC is still performing a conversion (it shouldn't be) then return
return;
if(selector) {
ADMUX = B01000000; // A0,
ADCSRA |= B01000000; // Start the next ADC conversión
ADC_Channel = 0; // GFCI
selector = 0;
}
else {
ADMUX = B01000001; // A1,
ADCSRA |= B01000000; // Start the next ADC conversión
ADC_Channel = 1; // Pilot_Low_AD
selector = 1;
}
/* solo pruebas */
cont_print_OVF ++; // cont_print+1 no vale
pinMode(Relay_1_Pin1, OUTPUT);
digitalWrite(Relay_1_Pin1, LOW);
// --------Funciona pero y lee Pilot High ---------
}
// This code runs when the PWM signal is in the middle of its high period
ISR(TIMER1_COMPB_vect) //originalmente CAPT_vect
{
static byte selector = 0; // originalmente a 0
if(ADCSRA & 0b01000000)
return;
if(selector) {
ADMUX = B01000000;
ADCSRA |= B01000000; // Start the next ADC conversión
ADC_Channel = 0; // GFCI
selector = 0;
}
else {
ADMUX = B01000001;
ADCSRA |= B01000000;
ADC_Channel = 2; // Pilot_High_AD
selector = 1;
}
cont_print_COMP ++; // cont_print+1 no vale
pinMode(Relay_1_Pin1, OUTPUT);
digitalWrite(Relay_1_Pin1, HIGH);
// -------- entra ---------
}
// Interrupt service routine for ADC conversion complete
ISR(ADC_vect) // si entra en esta interrup pero no convierte
{
unsigned char adcl = ADCL;
unsigned char adch = ADCH;
switch(ADC_Channel) {
case 0:
GFCI_ADC = (adch << 8) | adcl;
//GFCI_ADC = 9;
break;
case 1:
//Pilot_Low_ADC = (adch << 8) | adcl;
Pilot_Low_ADC = 320; // -12v prueba
break;
case 2:
Pilot_High_ADC = (adch << 8) | adcl;
//Pilot_High_ADC = 860; //9v 923--> +12v prueba
break;
}
}