//This program allows digital dimming of AC resisitive loads. It has two dimming channels,
//which share a common zero-cross detector. Power levels are set by 2 byte serial inputs,
//the first byte controlling channel0 the second byte controlling channel1. A key feature
//of this program is a nearly linear relationship between byte input and dimmer output voltage.
//Thus the output voltage from an input byte of 63 is about 50% of that from an input of 127
//etc.
//Initialize zc and triac pins
const int zc = 8;
const int triac0 = 9;
const int triac1 = 10;
unsigned long trigger0; //trigger0 is the time the triac0 will be triggered
unsigned long trigger1;
unsigned long epoch; //Time of last zero cross
unsigned long now; //ca. current time
unsigned long delay0 = 7500; //This ensures that, until first serial input is recieved,
unsigned long delay1 = 7500; //power to load is essentially off
unsigned short byte2microsec[]={8333.3886729122842, 8001.597423429539, 7863.8580842646543, 7757.9562806851836, 7668.4994629994653, 7589.52948065694, 7517.9925604055315, 7452.0757200753233, 7390.5983933087982, 7332.7410209745321, 7277.9072147096867, 7225.6469885375391, 7175.6109272900385, 7127.5212965621176, 7081.1530170752394, 7036.3206753543082, 6992.8693833325297, 6950.6681786914987, 6909.605152795405, 6869.5837837973704, 6830.5201295068127, 6792.3406458278387, 6754.9804684199426, 6718.3820427867295, 6682.494020171237, 6647.2703588340928, 6612.6695858796284, 6578.6541859203016, 6545.1900909265651, 6512.2462515231045, 6479.7942743868625, 6447.8081137053123, 6416.2638071624187, 6385.139248844258, 6354.4139929459352, 6324.069083324548, 6294.0869048580216, 6264.4510532952891, 6235.1462208625217, 6206.1580953556395, 6177.4732708257761, 6149.0791682706213, 6120.9639649949713, 6093.1165315097933, 6065.5263750092727, 6038.1835886066365, 6011.0788056273659, 5984.2031583571434, 5957.5482407249128, 5931.1060744715069, 5904.8690784137416, 5878.8300404643996, 5852.982092111637, 5827.3186850983166, 5801.8335700734624, 5776.5207770153838, 5751.3745972495981, 5726.3895669052072, 5701.5604516710937, 5676.8822327288426, 5652.3500937527742, 5627.9594088793683, 5603.7057315586735, 5579.584784209499, 5555.5924486081904, 5531.7247569479077, 5507.9778835116367, 5484.3481369076999, 5460.8319528215243, 5437.4258872418095, 5414.1266101231877, 5390.9308994509393, 5367.8356356765325, 5344.8377964954861, 5321.93445194166, 5299.1227597742782, 5276.3999611360859, 5253.7633764628372, 5231.2104016260037, 5208.7385042920896, 5186.3452204832747, 5164.028151325374, 5141.7849599701922, 5119.613368680386, 5097.5111560658443, 5075.4761544614757, 5053.5062474370134, 5031.5993674301899, 5009.7534934952391, 4987.9666491592861, 4966.2369003797103, 4944.5623535960658, 4922.9411538705772, 4901.371483111654, 4879.8515583752451, 4858.3796302391829, 4836.9539812460207, 4815.5729244101149, 4794.23480178503, 4772.937983087535, 4751.6808643747454, 4730.461866771122, 4709.2794352422943, 4688.1320374127972, 4667.0181624250199, 4645.9363198367964, 4624.8850385552241, 4603.8628658044163, 4582.8683661250179, 4561.9001204034394, 4540.9567249288466, 4520.0367904760551, 4499.1389414125533, 4478.2618148279798, 4457.4040596844243, 4436.5643359860214, 4415.7413139663404, 4394.9336732921665, 4374.140102282272, 4353.3592971398793, 4332.5899611975155, 4311.8308041730188, 4291.0805414354863, 4270.3378932799915, 4249.6015842099041, 4228.870342225694, 4208.142898119112, 4187.4179847716405, 4166.6943364561421, 4145.9706881406446, 4125.2457747931721, 4104.5183306865911, 4083.7870887023819, 4063.0507796322941, 4042.3081314767992, 4021.5578687392672, 4000.7987117147695, 3980.0293757724057, 3959.2485706300131, 3938.454999620119, 3917.6473589459442, 3896.8243369262646, 3875.9846132278603, 3855.1268580843057, 3834.2497314997327, 3813.3518824362309, 3792.4319479834385, 3771.4885525088462, 3750.5203067872671, 3729.5258071078688, 3708.5036343570605, 3687.4523530754891, 3666.3705104872661, 3645.2566354994883, 3624.1092376699917, 3602.926806141164, 3581.7078085375401, 3560.4506898247496, 3539.1538711272556, 3517.8157485021707, 3496.4346916662648, 3475.0090426731017, 3453.5371145370405, 3432.0171898006311, 3410.4475190417083, 3388.8263193162188, 3367.1517725325748, 3345.4220237529994, 3323.6351794170464, 3301.7893054820952, 3279.8824254752722, 3257.9125184508093, 3235.8775168464408, 3213.7753042319, 3191.6037129420934, 3169.360521586912, 3147.0434524290108, 3124.650168620195, 3102.178271286281, 3079.6252964494479, 3056.9887117761991, 3034.2659131380065, 3011.4542209706256, 2988.5508764167989, 2965.5530372357534, 2942.4577734613463, 2919.2620627890988, 2895.962785670476, 2872.5567200907617, 2849.0405360045856, 2825.4107894006484, 2801.6639159643773, 2777.7962243040952, 2753.803888702786, 2729.682941353612, 2705.4292640329172, 2681.0385791595113, 2656.5064401834434, 2631.8282212411909, 2606.9991060070779, 2582.014075662687, 2556.8678958969012, 2531.5551028388222, 2506.0699878139694, 2480.4065808006485, 2454.5586324478854, 2428.5195944985435, 2402.2825984407791, 2375.8404321873727, 2349.1855145551417, 2322.3098672849196, 2295.2050843056486, 2267.8622979030124, 2240.2721414024918, 2212.4247079173133, 2184.3095046416638, 2155.9154020865094, 2127.2305775566456, 2098.242452049763, 2068.9376196169969, 2039.3017680542644, 2009.319589587737, 1978.9746799663499, 1948.2494240680278, 1917.1248657498663, 1885.5805592069737, 1853.5943985254223, 1821.1424213891803, 1788.1985819857202, 1754.7344869919832, 1720.7190870326565, 1686.1183140781927, 1650.8946527410476, 1615.0066301255563, 1578.4082044923432, 1541.0480270844459, 1502.8685434054719, 1463.8048891149153, 1423.7835201168796, 1382.7204942207857, 1340.5192895797557, 1297.0679975579774, 1252.2356558370457, 1205.8673763501677, 1157.7777456222468, 1107.741684374746, 1055.481458202599, 1000.6476519377538, 942.79027960348685, 881.31295283696249, 815.39611250675364, 743.8591922553461, 664.88920991282055, 575.4323922271011, 469.53058864763085, 331.79124948274608};
// ^^ is a lookup table it has 256 entries, entry 0 is the delay time for 0% power
//entry 127 is delay time for 50% power and entry 255 is delay time for 100% power
//see the byte2ms function in python code to see how this lookup table was calculated
void setup() {
pinMode(zc,INPUT);
pinMode(triac0,OUTPUT);
pinMode(triac1,OUTPUT);
//next 2 lines set triac0 and 1 to off; remember, data pins SINK optotriacs
digitalWrite(triac0,HIGH);
digitalWrite(triac1,HIGH);
Serial.begin(115200); //initialize serial, high baud rate is REQUIRED for relaiable operation
}
void loop() {
if (Serial.available() > 0) { //if a new serial command is available....do stuff
delay0 = byte2microsec[Serial.read()]; //computer will send 2 bytes; first byte --> triac0 power
delayMicroseconds(75); //this delay gives time for serial buffer to fill with next byte
//If baud rate is low second byte is unreliably read b/c buffer
//does not have time to be updated
delay1 = byte2microsec[Serial.read()]; //second byte is triac1 power. Delay is simply taken from the lookup table
//delay is in microseconds
//Serial.flush(); //Not necissary if all bytes are read from buffer
//Serial.print(delay0); //these functions are useful for debugging serial communications
//Serial.println(delay1); //but cause poor operation of dimmer b/c serial writes take a long time
}
if(digitalRead(zc) == LOW) { //if True, we are at zero cross
epoch = micros(); //epoch is the time at zero cross
trigger0 = epoch + delay0; //trigger0 is the time the triac0 will be triggered
trigger1 = epoch + delay1; //trigger1 "" triac1 ""
unsigned int repeat[] = {1,1}; //This is for the while loop; a 1 indicates the triac hasn't been triggered
//triac0 is first value of list triac1 is second
while (repeat[0]+repeat[1] > 0) { //while loop is exited when repeat[] = {0,0}
now = micros(); //this is current time
if (now >= trigger0 and repeat[0] == 1) { //To satisfy, we must be after time trigger0
//AND triac0 must not have been triggered in this current half cycle
digitalWrite(triac0,LOW); //triac0 is triggered; this has been shown to be nearly instantanious,
//no delay is needed to ensure the triac latches; it always does
repeat[0] = 0; //set repeat[0] to 0 indicating to the while loop that triac0 has triggered in this cycle
digitalWrite(triac0,HIGH); //stop triggering the triac, it has latched for the rest of this half wave
}
if (now >= trigger1 and repeat[1] == 1) { //like the previous if statement just everything for triac1
digitalWrite(triac1,LOW);
repeat[1] = 0;
digitalWrite(triac1,HIGH);
}
}
}
}