#define info0 "EMC4 Build-01 PWMGen"
#define info1 "F/W P0325-C01_v0.13 "
#define info2 "Assy: CES180325-3 "
#define info3 "Date: 10/12/2018 "
/*
* P0325-C01_v0.13 10/12/18 --------------------------------
* Check PWM Prescaller, update calculation OK
* Program 47%, Memory 49%
* Ready for Acceptance Test
* Pending LCD Display I2C Address updater
* Pending CS Current Calibration
* P0325-C01_v0.12 9/19/18 --------------------------------
* Program 49%, Memory 49%
* --------------------------------------------------------
* Pro Mini 16MHz/5V
* 1x5 Extend Header
* --------------------------------------------------------
* Pro MiniPORT Assignments
* A7 'sFreq' POT Frequency Adj
* A6 'sDutycycle' POT Duty Adj
* A5/D19 I2C-SCL
* A4/D18 I2C-SDA
* -----------------------
* A3/D17 'sPrescaler' POT Prescaler Adj
* A2/D16 'ps1A' DMA-CS (Ics Load Current 100A)
* A1/D15 'ps2V' DMV-PB (PROBE 200V)
* A0/D14 'ps1V' DMV-PS (PS+ 200V)
* D13 loopbeat (IDE Reserved Output Only)
* D12 Output ZDRV (connect to ZDRV.D17)
* D11 Output 'freqout' PWM-OUT
* D10 Input EDM-ON sameas ZDRV.D10 (HI=EDM-On)
* D9 Input DCOMM nRXD Rx NodeReady (LO=NotReady)
* D8 Output DCOMM nTXD Tx RunMode (LO=EDM-OFF)
* D7 Output 'FREQOFF' F/2 OFF(-) GND = OFF
* D6 Output 'PWMOUT' PWM OFF(-) GND = OFF
* D5 Output 'DRVOFF' OFF(-) GND = OFF
* D4 Input 'modesw' Mode SW GND=F/2 50% dutycycle
* D3 Output 'pwmout' PWM output
* D2 Data 'Tport' DS18B20 Temp Sensor
* -----------------------
* D1 RXD reserved
* D0 TXD reserved
* === Pro Mini w/ 5x1 Extended Header =========================
* (D9)(D8)(D7)(D6)(D5)(D4)(D3)(D2)(GND)(RES)(RXD)(TXD) < DTR >
* (GND) * < RX >
* A4 * < TX >
* A5 * < VCC >
* A6 * < CTS >
* A7 * < GND >
* (D10)(D11)(D12)(D13)(A0)(A1)(A2)(A3)(VCC)(RES)(GND)(RAW)
* =============================================================
*/
// LCD 2004 with I2C
#include <FastIO.h>
#include <I2CIO.h>
#include <LiquidCrystal_I2C.h>
// the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd2(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // TOP LCD TESTER
//LiquidCrystal_I2C lcd2(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // TOP LCD EDMP3
// DS18B20 Temperature Sensor(s)
#include <OneWire.h>
#include <DallasTemperature.h>
#define Tport 2 // Port
#define Tdata 9 // Resolution
//#define Tdata 10 // Resolution
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(Tport);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// arrays to hold device addresses
DeviceAddress Tsensor1, Tsensor2; // for Auto Config
//DeviceAddress Tsensor1 = { 0x28, 0xFF, 0x77, 0x95, 0x94, 0x16, 0x04, 0x85 }; // RR= Brown
//DeviceAddress Tsensor2 = { 0x28, 0xFF, 0xE8, 0x8E, 0x86, 0x16, 0x04, 0xF4 }; // LT= Blue
float TempC;
// ZDRV Interface
#define zDRV 12 //ZDRV Interface Input Port
#define Ready HIGH
#define NotReady LOW
String NRmsg = " ! Node NOT Ready ! ";
#define zEDM 10 //Input connect to ZDRV EDM Control Port D10 (HI=EDM-ON)
#define zEDMon HIGH
#define zEDMoff LOW
// Node Interface
#define nRXD 9 //Input from all Nodes (LO=NotReady)
#define nTXD 8 //Output Broadcast EDM Control On/Off Status to all Nodes
#define EDMon LOW
#define EDMoff HIGH
// DMM Variables
#define ps1V A0 // Supply Voltage PS+ Port
#define ps2V A1 // Probe Voltage Port
#define ps1A A2 // Current CS+ Port
// for testing only
//#define ps1V A6 // Supply Voltage PS+ Port
//#define ps2V A7 // Probe Voltage Port
//#define ps1A A3 // Current CS+ Port
float dmmV;
float dmmA;
float dmmW;
float dmmVdutycycle;
float dmmAdutycycle;
double K1V = 0.196899874; // 200.0 FSC pre-scale 200/1023
double K2V = 0.196899874; // 200.0 FSC pre-scale 200/1023
//double K1A = 0.106251859; // 100.0 FSC pre-scale 100/1023
//double K1V = 0.196899874; // 200.0 FSC pre-scale 200/1023 Calibrated
//double K2V = 0.196899874; // 200.0 FSC pre-scale 200/1023 Calibrated
double K1A = 0.115545796; // 100.0 FSC pre-scale 100/1023 Calibrated
// AnalogREAD Array
const byte AAcount = 10; // sample size
byte ps1VA[AAcount]; // array
byte ps2VA[AAcount]; // array
byte ps1AA[AAcount]; // array
byte Aindex = 0; // index
byte ps1Vmin;
byte ps1Vavg;
byte ps1Vmax;
byte ps2Vmin;
byte ps2Vavg;
byte ps2Vmax;
byte ps1Amin;
byte ps1Aavg;
byte ps1Amax;
// PWM I/O
#define sFreq A7 //POT Freq Adj
#define sDutycycle A6 //POT Dutycycle Adj
#define sPrescaler A3 //POT Prescaler Adj
#define FREQOFF 7 //Output F/2 OFF(-)
#define PWMOFF 6 //Output PWM OFF(-)
#define DRVOFF 5 //Output F/2 OFF(-)
#define freqout 11 //F/2 50% dutycycle output
#define pwmout 3 //PWM output
#define modesw 4 //Mode Switch input LOW=F/2
// PWM POT
byte potfreq; //Freq ADC Value
byte lastpotfreq; //save value
byte potduty; //dutycycle ADC Value
byte lastpotduty; //save value
byte potprescale; //Prescaler ADC Value
byte lastpotprescale; //save value
// PWM Output
byte pwmfreq; //Freq ADC Value
byte pwmduty; //dutycycle ADC Value
byte pwmprescale; //Prescaler ADC Value
float pwmHt; // for storing high time
float pwmfrequency; // for storing frequency
float F2frequency;
float F2Ht;
// PWM Controls
int divider2[8] = { 0,1,8,32,64,128,256,1024 };
//float freqmax[8] = { 0, 1333333, 166667, 41667, 20833, 10417, 5208, 1302 };
//float freqmin[8] = { 0, 31746, 3968, 996, 496, 248, 124, 31 };
byte ocra = 126; // set to 1KHz
byte ocrb = 63; // OCRA/2 50% dutycycle Phase Corrected
double sysclk = 16000000; //system clock 16MHz default
// PWM Prescaler MSG 2004 20-chr
char* scalerPWM[]={
"0 INOP Not Used ",
"/1 F= 32K~1.3MHz",
"/8 F= 3.9K~166KHz",
"/32 F= 977~41.6KHz",
"/64 F= 496~20.8KHz",
"/128 F= 248~10.4KHz",
"/256 F= 124~5.2KHz",
"/1024 F= 31~1.3KHz"};
char* scalerF2[]={
"0 INOP Not Used ",
"/1 F= 16K~650KHz",
"/8 F= 1.9K~83KHz",
"/32 F= 498~20.8KHz",
"/64 F= 248~10.4KHz",
"/128 F= 124~5.2KHz",
"/256 F= 62~2.6KHz",
"/1024 F= 16~651Hz"};
// System Variable
#define loopbeat 13 // toggle onboard LED per Loop
String mfg; // Long MSG
int rdisplock = 0; //>0 lock rdisplay
byte rline; //rdisp line#
String rmfg; //rdisp message
String rtemp; //temperary msg storage
unsigned long msNow; //Current Wait Timer
unsigned long msLast; //Last Wait Timer
unsigned long msWait = 1000; //timer default at 1-second Wait
byte waitprescaler = 0; // Prescaler display timer
byte waitfreq = 0; // Freq display timer
byte waitduty = 0; // Duty display timer
byte waitFT = 3; // Freq/Time display timer
#define waitFTset 3 // Freq/Time display change period default
byte showF = 1; // Freq/Time display setting
byte screenscan = 1;
byte screen = 0; // screen page index
#define freqpage 1 // screen page for freq setup
#define bypass 2 // screen page for Node Info
/* ------------------------------------------------------------------------*/
/// Setup Start Here
void setup() {
// Loop Beat
pinMode(loopbeat, OUTPUT);
//Output Controls (ALL OFF)
pinMode(FREQOFF, OUTPUT); digitalWrite(FREQOFF, LOW);
pinMode(PWMOFF, OUTPUT); digitalWrite(PWMOFF, LOW);
pinMode(DRVOFF, OUTPUT); digitalWrite(DRVOFF, LOW);
//ZDRV Interface
pinMode(zDRV, OUTPUT); digitalWrite(zDRV, Ready);
pinMode(zEDM, INPUT_PULLUP);
//Node Interface
pinMode(nRXD, INPUT_PULLUP);
pinMode(nTXD, OUTPUT);
//LCD setup
lcd2.begin(20, 4);
//PWM setup
pinMode(modesw, INPUT_PULLUP); // PWM=HI F/2=LOW
pinMode(pwmout, OUTPUT); // Variable dutycycle port
pinMode(freqout, OUTPUT); // 2/F 50% dutycycle port
// PWM Mode (Fast or Phase-Correct)
//TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); //Fast PWM
TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20); // Phase Correct PWM
TCCR2B = _BV(WGM22) | _BV(CS22);
// Display Info
mfg = (info0); printmfg(0,0);
mfg = (info1); printmfg(0,1);
mfg = (info2); printmfg(0,2);
mfg = (info3); printmfg(0,3);
delay(4000);
}
/// Setup End Here
/* ------------------------------------------------------------------------*/
/* P r o g r a m S t a r t H e r e
/* ------------------------------------------------------------------------*/
void loop() {
// Loop Beat on D13 LED
if (digitalRead(loopbeat)==LOW) digitalWrite(loopbeat,HIGH); else digitalWrite(loopbeat,LOW);
// PWM read POT for change
readPWMpot();
if ((potfreq>lastpotfreq+1) || (potfreq<lastpotfreq-1) || (potduty>lastpotduty+1) || (potduty<lastpotduty-1) || (potprescale!=lastpotprescale)) {
setPWM();
msLast = msNow; waitfreq=3;
}
// ADC Read DMM Section
AAread();
AAproc();
// Screen Page Display
if (waitfreq>0) {
screen = freqpage;
rdisplock = 0;
rline=0;
} else {
if (rdisplock>0) { screen = bypass; } else { screen=0; }
}
switch(screen) {
case 0: // default screen
lcd2.setCursor(0,0);
if (digitalRead(modesw)==LOW) {
if (showF>0) dispFD(F2frequency, F2Ht); else dispHL(F2frequency, F2Ht);
} else {
if (showF>0) dispFD(pwmfrequency, pwmHt); else dispHL(pwmfrequency, pwmHt);
}
lcd2.setCursor(0,1); dispVAW1();
lcd2.setCursor(0,2); dispVAW2();
lcd2.setCursor(0,3);
if (digitalRead(nRXD)==NotReady) lcd2.print (NRmsg); else showT12();
break;
case freqpage: // freq/Duty/Prescaler change screen
lcd2.setCursor(0,0);
if (digitalRead(modesw)==LOW) dispFD(F2frequency, F2Ht); else dispFD(pwmfrequency, pwmHt);
lcd2.setCursor(0,1);
if (digitalRead(modesw)==LOW) dispHL(F2frequency, F2Ht); else dispHL(pwmfrequency, pwmHt);
lcd2.setCursor(0,2);
if (digitalRead(modesw)==LOW) lcd2.print(scalerF2[pwmprescale]); else lcd2.print(scalerPWM[pwmprescale]);
lcd2.setCursor(0,3);
if (digitalRead(nRXD)==NotReady) lcd2.print (NRmsg); else ocrab();
break;
case bypass:
break;
}
//Output Controls (ALL ON)
digitalWrite(FREQOFF, HIGH);
digitalWrite(PWMOFF, HIGH);
digitalWrite(DRVOFF, HIGH);
//Interprete Node and PWM OFF status
if ((digitalRead(nRXD)==NotReady) || (ocrb==0)) digitalWrite(zDRV,NotReady); else digitalWrite(zDRV,Ready);
//Broadcast Console EDM Status
if (digitalRead(zEDM)==zEDMoff) digitalWrite(nTXD,EDMoff); else digitalWrite(nTXD,EDMon);
// Auto Timer Update
msNow = millis();
if (msNow-msLast > msWait) {
msLast = msNow;
if (waitprescaler>0) waitprescaler--;
if (waitfreq>0) waitfreq--;
if (waitduty>0) waitduty--;
if (waitFT>0) waitFT--; else {
waitFT=waitFTset;
if (showF==0) showF=1; else showF=0; }
if (rdisplock>0) rdisplock--;
}
}
/// Program End Here
/* ------------------------------------------------------------------------*/
/// Print mfg on Cursor i, Line j
void printmfg(int i, int j) {
lcd2.setCursor(i,j); lcd2.print(mfg);
}
/// Clear line J
void dispclear(int j) {
lcd2.setCursor(0,j); lcd2.print (" ");
}
/// << PWM Section >> -------------------------------------------------
/// Read Freq/Duty/Prescale POTs
void readPWMpot() {
int j;
j = 2; if (j != 0) { potfreq = analogRead(sFreq)/4; j--; }
j = 2; if (j != 0) { potduty = analogRead(sDutycycle)/4; j--; }
j = 2; if (j != 0) { potprescale = analogRead(sPrescaler)/147; j--; }
//potduty = 255 - potduty; //swap H/L
if (potfreq < 6) { potfreq = 6; }
if (potduty > 240) { potduty = 240; } //Limit MAX dutycycle to ~90%
}
/// Set PWM Output
void setPWM() {
lastpotfreq = potfreq;
lastpotduty = potduty;
lastpotprescale = potprescale;
ocra = potfreq;
ocrb = potduty * ocra / 255;
pwmprescale = potprescale +1; //skip 0
pwmfrequency = sysclk / divider2[pwmprescale] / (ocra) / 2; //Phase Corrected
F2frequency = pwmfrequency / 2;
F2Ht = (1000000 / F2frequency / 2);
pwmHt = (float)ocrb / (float)ocra * (1000000/pwmfrequency); // in uS
switch(pwmprescale) {
case 1: TCCR2B = TCCR2B & B11111000 | B00000001; break; // T2 divisor = 1 INOP
case 2: TCCR2B = TCCR2B & B11111000 | B00000010; break; // T2 divisor = 8 3.9KHz ~ 50KHz (H)
case 3: TCCR2B = TCCR2B & B11111000 | B00000011; break; // T2 divisor = 32 980Hz ~ 12.2KHz
case 4: TCCR2B = TCCR2B & B11111000 | B00000100; break; // T2 divisor = 64 247Hz ~ 6.2KHz (M)
case 5: TCCR2B = TCCR2B & B11111000 | B00000101; break; // T2 divisor = 128 491Hz ~ 3.15KHz
case 6: TCCR2B = TCCR2B & B11111000 | B00000110; break; // T2 divisor = 256 121Hz ~ 1.56KHz (L)
case 7: TCCR2B = TCCR2B & B11111000 | B00000111; break; // T2 divisor = 1024 31Hz ~ 390Hz
}
OCR2A = ocra; OCR2B = ocrb;
}
/// PWM Display Freq/Duty "FREQ xxx.xxxKHz D%xx" 20-chr
void dispFD(float freq, float Ht) {
mfg = "FREQ ";
if (ocrb==0) { mfg=mfg+" -- PWM OFF -- "; } else {
float Tt = 1000000 / freq; // in uS
if ((freq/1000)<10) { mfg=mfg+" "; } else if ((freq/1000)<100) { mfg=mfg+" "; }
if (freq<1000000) { mfg=mfg + String(freq/1000,3); } else { mfg=mfg + String(freq/1000,2); }
mfg += "KHz D"+ String((Ht/Tt)*100,0) + "%";
}
lcd2.print(mfg);
}
/// PWM Display H/L Time "ON= xxxuS OFF= xxxuS"
/// H/L Time Display // 16 chr
void dispHL(float freq, float Ht) {
float Lt = 1000000 / freq - Ht; // in uS
mfg = "ON "; tDisp(Ht);
mfg += " OFF "; tDisp (Lt);
lcd2.print(mfg);
}
/// H/L Data output
/// "x.xxuS"
/// "xx.xuS"
/// " xxxuS"
/// "x.xxmS"
/// "xx.xmS"
/// " xxxmS"
void tDisp (float T) {
if ((T)>1000) { //mS Range
if ((T/1000)<10) {
mfg += String(T/1000,2);
} else if ((T/1000)<100) {
mfg += String(T/1000,1);
} else { mfg += "="; mfg += String(T/1000,0); }
mfg += "mS";
} else {
if ((T)<10) {
mfg += String(T,2);
} else if ((T)<100) {
mfg += String(T,1);
} else { mfg += "="; mfg += String(T,0); }
mfg += "uS";
}
}
/// PulseGen Display "CRxA=xxx CRxB=xxx" //20-chr
void ocrab() {
mfg = "CRxA:"; //20-chr
if (ocra<10) { mfg += " "; } else if (ocra<100) { mfg += " "; }
mfg += String(ocra) + " CRxB:"; //20-chr
if (ocrb<10) { mfg += " "; } else if (ocrb<100) { mfg += " "; }
mfg += String(ocrb); mfg += (" ");
lcd2.print(mfg);
}
/// << DMM Section >> ///////////////////////////////////
/// Array READ
void AAread() {
Aindex++; if (Aindex == AAcount) Aindex = 0;
int j;
j = 2; if (j != 0) { ps1VA[Aindex] = analogRead(ps1V); j--; }
j = 2; if (j != 0) { ps2VA[Aindex] = analogRead(ps2V); j--; }
j = 2; if (j != 0) { ps1AA[Aindex] = analogRead(ps1A); j--; }
}
/// Array data Processing
void AAproc() {
ps1Vmin = ps1VA[Aindex]; ps1Vavg = ps1VA[Aindex]; ps1Vmax = ps1VA[Aindex];
ps2Vmin = ps2VA[Aindex]; ps2Vavg = ps2VA[Aindex]; ps2Vmax = ps2VA[Aindex];
ps1Amin = ps1AA[Aindex]; ps1Aavg = ps1AA[Aindex]; ps1Amax = ps1AA[Aindex];
int i=0;
for (i=0; i<AAcount; i++) {
if (ps1Vmin > ps1VA[i]) ps1Vmin = ps1VA[i];
if (ps2Vmin > ps2VA[i]) ps2Vmin = ps2VA[i];
if (ps1Amin > ps1AA[i]) ps1Amin = ps1AA[i];
if (ps1Vmax < ps1VA[i]) ps1Vmax = ps1VA[i];
if (ps2Vmax < ps2VA[i]) ps2Vmax = ps2VA[i];
if (ps1Amax < ps1AA[i]) ps1Amax = ps1AA[i];
ps1Vavg = ( ps1Vavg + ps1VA[i] ) /2;
ps2Vavg = ( ps2Vavg + ps2VA[i] ) /2;
ps1Aavg = ( ps1Aavg + ps1AA[i] ) /2;
}
}
/// DMM Display "xxxV xx.xA xxxxW" 16-chr
void dispVAW1() {
mfg = "PS+ ";
dmmV = ps1Vmax * K1V;
dmmA = ps1Aavg * K1A;
dmmW = dmmV * dmmA;
if (dmmV<100) { mfg += " "; }
mfg += String(dmmV,0) + "V ";
if (dmmA<10) { mfg += " "; }
mfg += String(dmmA,1) + "A ";
/// Display "xxxxW" 5-Chr
if (dmmW>9999) { mfg += " --- "; }
else {
if (dmmW<100) { mfg += " "; } else if (dmmW<1000) { mfg += " "; }
mfg += String(dmmW,0) + "W";
}
lcd2.print(mfg);
}
/// DMM Display "xxxV xx.xA xxxxW" 16-chr
void dispVAW2() {
mfg = "EDP ";
dmmV = ps2Vmin * K2V;
dmmA = ps1Amax * K1A;
//dmmW = dmmV * dmmA;
if (dmmV<100) { mfg += " "; }
mfg += String(dmmV,0) + "V ";
if (dmmA<10) { mfg += " "; }
mfg += String(dmmA,1) + "A ";
/// Display Controld Status
mfg += " ";
if (digitalRead(FREQOFF) == HIGH) { mfg += "+"; } else { mfg += "-"; }
if (digitalRead(PWMOFF) == HIGH) { mfg += "+"; } else { mfg += "-"; }
if (digitalRead(DRVOFF) == HIGH) { mfg += "+"; } else { mfg += "-"; }
mfg += " ";
/// Display "xxxxW" 5-Chr
//if (dmmW>9999) { mfg += " --- "; }
//else {
//if (dmmW<100) { mfg += " "; } else if (dmmW<1000) { mfg += " "; }
//mfg += String(dmmW,0) + "W";
//}
lcd2.print(mfg);
}
/// DS18B20 Dual Temp Display "T1-xxx.xC T2-xxx.xC"
void dualTemp(char* pname1, DeviceAddress paddress1, byte pindex1, char* pname2, DeviceAddress paddress2, byte pindex2) {
mfg = (pname1);
if (!sensors.getAddress(paddress1,pindex1)) { mfg += " --- "; }
else { dispT(paddress1); }
mfg += " "; mfg += (pname2);
if (!sensors.getAddress(paddress2,pindex2)) { mfg += " --- "; }
else { dispT(paddress2); }
lcd2.print (mfg);
}
/// Show Temperatures Sensors
void showT12() { dualTemp("HS=", Tsensor1, 0, "IN=", Tsensor2, 1); }
/// DS18B20 Display Temperature in "-xxx.xC" 8chr
void dispT(DeviceAddress paddress) {
sensors.requestTemperaturesByAddress(paddress);
TempC = sensors.getTempC(paddress);
rmfg = String(TempC,1);
//mfg="";
for (int j=5; j>rmfg.length(); j--) mfg += " ";
mfg += (rmfg); mfg += "C";
}
/// Software Reset
void resetBoot() {
asm volatile (" jmp 0");
}
/// F/W End Here
/* ------------------------------------------------------------------------*/