const char* info0 = "F/W: PWMGen3_v0.20 "; // 20 chr
const char* info1 = " Release 03/04/2018";
const char* info2 = "PCB Assy# CES171107";
const char* info3 = " update as built ";
/*
* PWMGen3_v0.2
* Add Alternet display of Freq/Duty and On-Time/Off-Time
* Mod Base on PWMGen3 v0.17 2/18/18
* Initial 1st Built EDMP3 Lawrence Chu v0.17 2/18/18
* Remove Watt Display on EDP
* Initial 1st Built EDMP3 Lawrence Chu 2/16/18
* Add Min/Max/Avg AnalogRead()
* Reduce Prescaller display time to half
* PS+ dispVAW1() ps1Vmax, ps1Aavg
* EDP dispVAW2() ps2Vmin, ps1Amax
* Initial 1st Built EDMP3 Lawrence CHu 2/13/18
* Limit dutycycle to 90% MAX <dutycycleMAX>
* Initial 1st Built EDMP3 Lawrence CHu 2/4/18
* Change Info Display timing to 2s (same as ZDRV3)
* T1 = HS, T2 = IN
* Initial Release v0.10 Lawrence Chu 11/27/17
* --------------------------------------------------------
* Pro Mini 16MHz/5V
* Serial Monitor = None
* --------------------------------------------------------
* LCD 2004 I2C (5V)
* A5 = SCL
* A4 = SDA
* --------------------------------------------------------
* PWM Generator (I/O & POT Controls)
* A3 = Adj Prescale
* A7 = Adj Freq
* A6 = Adj dutycycle
* D11 = Output Freq/2 50% dutycycle
* D3 = Output PWM
* D4 = Mode SW GND=F/2 50% dutycycle
* D5 = DRV Output OFF(-) GND = OFF
* D6 = PWM Output OFF(-) GND = OFF
* D7 = F/2 Output OFF(-) GND = OFF
* D12 *Reserved
* --------------------------------------------------------
* DS18B20 Temperature Sensor (2x)
* D2 = Data Port
* Auto Detect
* --------------------------------------------------------
* ZSense Monitor
* A0 = DMV Power Supply (200V)
* A1 = DMV Probe (200V)
* A2 = DMA Current (50A)
*
*/
// 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>
#include <Wire.h>
#define Tport 2 // Port
#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;
// 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.19550; // 200.0 FSC pre-scale 200/1023
double K2V = 0.19550; // 200.0 FSC pre-scale 200/1023
double K1A = 0.04887; // 50.0 FSC pre-scale 50/1023
// AnalogREAD Array
const int AAcount = 10; // sample size
unsigned int ps1VA[AAcount]; // array
unsigned int ps2VA[AAcount]; // array
unsigned int ps1AA[AAcount]; // array
unsigned int Aindex = 0; // index
unsigned int ps1Vmin;
unsigned int ps1Vavg;
unsigned int ps1Vmax;
unsigned int ps2Vmin;
unsigned int ps2Vavg;
unsigned int ps2Vmax;
unsigned int ps1Amin;
unsigned int ps1Aavg;
unsigned int ps1Amax;
// PulseGen I/O
#define sFreq A7 //POT Freq Adj
#define sdutycycle A6 //POT dutycycle Adj
#define sPrescaler A3 //POT dutycycle 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
// PulseGen Variables
double sysclk = 16000000; //system clock 16MHz default
byte potfreq; //Freq Read ADC Value
byte potdutycycle; //dutycycle Read ADC Value
byte potprescale; //Prescale Read ADC Value
float frequency; // for storing frequency
float dutycycle; //dutycycle
float Htime; // integer for storing high time
float Ltime; // integer for storing low time
float Ttime; // integer for storing total time of a cycle
byte ocra = 126; // set to 1KHz
byte ocrb = 63; // OCRA/2 50% dutycycle Phase Corrected
int divider2[8] ={0,1,8,32,64,128,256,1024};
byte prescaler2=4; //defualt Divider=64
// Prescaler MSG 2004 20-chr
char* scalerPWM[]={
"0 INOP Not Used ",
"/1 F= 32K~380KHz",
"/8 F= 3.9K~47KHz",
"/32 F= 977~11.9KHz",
"/64 F= 488~5.95KHz",
"/128 F= 244~2.97KHz",
"/256 F= 122~1.48KHz",
"/1024 F= 69 ~845Hz"};
char* scalerFreq[]={
"0 INOP Not Used ",
"/1 F= 16K~190KHz",
"/8 F= 1.9K~23KHz",
"/32 F= 488~5.95KHz",
"/64 F= 244~2.97KHz",
"/128 F= 122~1.48KHz",
"/256 F= 122~1.48KHz",
"/1024 F= 34.5~422Hz"};
// System Variable
byte loopcount = 0; //Init timeout
byte loopmax = 25; // maximum loop count
#define dispmax 100 // loop count for display change
byte dispcount = 0; // Freq display change counts
String mfg; // Long MSG
/* ------------------------------------------------------------------------*/
/// Setup Start Here
void setup() {
//Output Controls (ALL OFF)
pinMode(FREQOFF, OUTPUT); digitalWrite(FREQOFF, LOW);
pinMode(PWMOFF, OUTPUT); digitalWrite(PWMOFF, LOW);
pinMode(DRVOFF, OUTPUT); digitalWrite(DRVOFF, LOW);
//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
showinfo(); lcd2.clear();
}
/// Setup End Here
/* ------------------------------------------------------------------------*/
/// Program Start Here
void loop() {
// Check Prescaler Freq dutycycle
prescalerpot(); // Read Prescaler POT Setting
if (prescaler2 == potprescale) {
if (loopcount < loopmax) loopcount++; }
else {
prescaler2 = potprescale;
loopcount=0; }
pscaler(); // to ensured register setting
freqpot(); // Read Freq/dutycycle POT Setting
// Set PulseGen Output
OCR2A = ocra;
OCR2B = ocrb;
// ADC Read DMM Section
AAread();
AAproc();
// Alternate Display counter
if (dispcount > dispmax) dispcount = 0; else dispcount ++;
// Display Freq & Scaller Row#1-2
if (digitalRead(modesw)==LOW) {
lcd2.setCursor(0,0);
if (dispcount < dispmax/2) freqDF(); else hltimeD();
lcd2.setCursor(0,1);
//if (loopcount < loopmax) lcd2.print(scalerFreq[prescaler2]); else showVAW1(); } // realtime
if (loopcount < loopmax) lcd2.print(scalerFreq[prescaler2]); else dispVAW1(); }
else {
lcd2.setCursor(0,0);
if (dispcount < dispmax/2) freqD(); else hltimeD();
lcd2.setCursor(0,1);
//if (loopcount < loopmax) lcd2.print(scalerPWM[prescaler2]); else showVAW1(); } // realtime
if (loopcount < loopmax) lcd2.print(scalerPWM[prescaler2]); else dispVAW1(); }
// Row #3 RAW VAW or CRxA/B
lcd2.setCursor(0,2);
//if (loopcount < loopmax) ocrab(); else showVAW2(); // realtime
if (loopcount < loopmax) ocrab(); else dispVAW2();
// Row #4 Dual Temp
lcd2.setCursor(0,3);
showT12();
//ocrab();
//Output Controls (ALL ON)
digitalWrite(FREQOFF, HIGH);
digitalWrite(PWMOFF, HIGH);
digitalWrite(DRVOFF, HIGH);
}
/// Program End Here
/* ------------------------------------------------------------------------*/
/// SYS Function to display info
void showinfo() {
lcd2.setCursor(0,0); lcd2.print(info0);
lcd2.setCursor(0,1); lcd2.print(info1);
lcd2.setCursor(0,2); lcd2.print(info2);
lcd2.setCursor(0,3); lcd2.print(info3);
delay(2000);
}
/// PulseGen Prescaller Setting
void pscaler() {
switch(prescaler2) { // Phase Corrected
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
}
}
/// Get Prescaler from POT
void prescalerpot() {
int j;
j = 3; if (j != 0) { potprescale = analogRead(sPrescaler)/147; j--; }
potprescale++;
}
/// Get Frequency/dutycycle from POT
void freqpot() {
int j;
j = 3; if (j != 0) { potfreq = analogRead(sFreq)/4; j--; }
j = 3; if (j != 0) { potdutycycle = analogRead(sdutycycle)/4; j--; }
if (potfreq < 6) { potfreq = 6; }
if (potdutycycle > 240) { potdutycycle = 240; } //Limit MAX dutycycle to ~90%
ocra = potfreq;
ocrb = potdutycycle * ocra / 255;
//ocrb = potdutycycle;
frequency = sysclk / divider2[prescaler2] / (ocra+1) / 2;
Ttime = (float)1000000/frequency; // in uS
dutycycle = (float)ocrb / (float)ocra;
Htime = (float)dutycycle * Ttime;
Ltime = (float)Ttime - Htime;
}
/// PulseGen Display "FREQ xxx.xxxKHz D%xx" 20-chr
/// PulseGen Display "Fxxx.xxxKHz D%xx" 16-chr
void freqD() {
mfg = "FREQ "; //20-chr
//mfg = "F"; //16-chr
if ((frequency/1000)>400) { mfg += "! Over Range ! "; }
else {
if ((frequency/1000)<10) { mfg += " "; }
else if ((frequency/1000)<100) { mfg += " "; }
mfg += String(frequency/1000,3) + "KHz ";
//dutycycle = (float)ocrb / (float)ocra;
if ((dutycycle<0.99) && (dutycycle>0.001)) { mfg += "D%"; mfg += String(dutycycle*100 ,0); }
else
if (dutycycle>0.99) { mfg += "D%99"; }
if (dutycycle<0.001) { mfg += "=OFF"; }
lcd2.print(mfg);
}
}
/// PWMout Display H/L Time "12345678901234567890"
/// "ON= xxxuS OFF= xxxuS"
void hltimeD() {
mfg = "ON:";
if ((Htime)>999) {
if ((Htime/1000)<10) { mfg=mfg+" "; }
mfg=mfg + String(Htime/1000,1) + "mS";
} else {
mfg += " ";
if (Htime<10) { mfg=mfg+" "; } else if (Htime<100) { mfg=mfg+" "; }
mfg = mfg + String(Htime,0) + "uS";
}
mfg += " OFF:";
if ((Ltime)>1000) {
if ((Ltime/1000)<10) { mfg=mfg+" "; }
mfg=mfg + String(Ltime/1000,1) + "mS";
}
else {
mfg += " ";
if (Ltime<10) { mfg=mfg+" "; } else if (Ltime<100) { mfg=mfg+" "; }
mfg=mfg + String(Ltime,0) + "uS";
}
lcd2.print(mfg);
}
/// PulseGen Display In F/2 Mode
void freqDF() {
mfg = "FREQ "; //20-chr
//mfg = "F"; //16-chr
frequency=frequency/2;
if ((frequency/1000)>200) { mfg += "! Over Range ! "; }
else {
if ((frequency/1000)<10) { mfg += " "; }
else if ((frequency/1000)<100) { mfg += " "; }
mfg += String(frequency/1000,3) + "KHz D%50";
lcd2.print(mfg);
}
}
/// PulseGen Display "CRxA=xxx CRxB=xxx" //20-chr
/// PulseGen Display "CxA=xxx CxB=xxx" //16-chr
void ocrab() {
mfg = "CRxA:"; //20-chr
//mfg = "CRxA:"; //16-chrt
if (ocra<10) { mfg += " "; } else if (ocra<100) { mfg += " "; }
mfg += String(ocra) + " CRxB:"; //20-chr
//mfg += String(ocra) + " CxB:"; //16-chr
if (ocrb<10) { mfg += " "; } else if (ocrb<100) { mfg += " "; }
mfg += String(ocrb); mfg += (" ");
lcd2.print(mfg);
}
/// Array READ
void AAread() {
Aindex++; if (Aindex == AAcount) Aindex = 0;
int j;
j = 3; if (j != 0) { ps1VA[Aindex] = analogRead(ps1V); j--; }
j = 3; if (j != 0) { ps2VA[Aindex] = analogRead(ps2V); j--; }
j = 3; 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);
//mfg="";
if (TempC<0) {
if (TempC>-10) { mfg += " "; } else if (TempC>-100) { mfg += ""; }
mfg += String(TempC,1);
}
else {
mfg += " ";
if (TempC<10) { mfg += " "; } else if (TempC<100) { mfg += ""; }
mfg += String(TempC,1);
}
mfg += ("C");
}
/// Software Reset
void resetBoot() {
asm volatile (" jmp 0");
}
/// F/W End Here
/* ------------------------------------------------------------------------*/