Components and supplies
Arduino Leonardo
Apps and platforms
Everycircuit
Fritzing
UnoArduSim
Project description
Code
HVAC Ctrl 1.0 by LD design (revision 2.5)
arduino
You need a leonardo board and my shield for it to actually do something
1// HVAC Ctrl 1.0, by LD design 2// revision 2.5, 2019-02-10 3 4// Copyright 2018, Louis Desbiens, All rights reserved. 5 6 7#include <avr/pgmspace.h> 8 9 10 11 12// 13// 14// 15// 16// beginning of global variables and constant declarations 17// 18// 19// 20// 21 22 23 24 25 26 27// digital addresses 28 29// outputs 30 31const byte LED_ctrl = 13; // LED control pin address 32const byte H1_ctrl = 12; // Heat strip #1, relay pin address 33const byte H2_ctrl = 11; // Heat strip #2, relay pin address 34const byte H3_ctrl = 10; // Heat strip #3, relay pin address 35const byte H4_ctrl = 9; // Heat strip #4, relay pin address 36const byte BLO_ctrl = 8; // Blower low speed, relay pin address 37const byte BMED_ctrl = 7; // Blower medium speed, relay pin address 38const byte BHI_ctrl = 6; // Blower high speed, relay pin address 39const byte BSSR_ctrl = 5; // Blower circuit, solid-state relay pin address 40 41// inputs 42 43const byte G = 3; // Thermostat G line status address (blower) 44const byte W1 = 2; // Thermostat W1 line status address (heat stage 1) 45const byte W2 = 1; // Thermostat W2 line status address (heat stage 2) 46const byte W3 = 0; // Thermostat W3 line status address (heat stage 3), connected to heat pump Y in the current implementation to override the fan speed algorithm 47 48 49// analog input signal, addresses 50 51const byte TH1 = 0; // Thermistor 1 address 52const byte TH2 = 6; // Thermistor 2 address 53const byte CSFAN = 1; // Fan current sense address 54const byte CSH1 = 5; // Heat strip #1 current sense address 55const byte CSH2 = 4; // Heat strip #2 current sense address 56const byte CSH3 = 3; // Heat strip #3 current sense address 57const byte CSH4 = 2; // Heat strip #4 current sense address 58 59 60// constant values 61 62const byte nb_of_heating_elements = 4; // nb of heating elements 63const byte CS_vector_size = 144; // current sense vector size 64const int delta_H = 1000; // minimal delay (ms) between two subsequent activation / dactivation of heat strip relays 65const int delta_G0 = 5000; // minimal delay (ms), after a blower power-up at the lowest speed, before engaging the speed adjustment algorithm 66const int delta_G = 1000; // minimal delay (ms), between two subsequent blower speed change 67const int delta_W1_level_1 = 5; // minimal delay (s) before engaging the second heat strip on a W1 heat request, (2 x 5 kW capacity) 68const int delta_W2_level_1 = 5; // minimal delay (s) before engaging the second heat strip on a W2 heat request, (2 x 5 kW capacity) 69const int delai_SSR = 10; // minimal delay (ms) before adjusting the blower speed selection relays after opening the circuit with the SSR relay 70const int delai_relay = 15; // minimal delay (ms) after adjustment the blower speed selection relays before closing the circuit with the SSR relay 71const int delta_T_LO_up = 1000; // minimum temp for going from LO to MED in 1/100 of C (hysteresis) 72const int delta_T_MED_up = 1500; // minimum temp for going from MED to HI in 1/100 of C (hysteresis) 73const int delta_T_HI_up = 2000; // minimum temp for going from HI to VHI in 1/100 of C (hysteresis) 74const int delta_T_MED_down = 900; // minimum temp for going from MED to LO in 1/100 of C (hysteresis) 75const int delta_T_HI_down = 1400; // minimum temp for going from HI to MED in 1/100 of C (hysteresis) 76const int delta_T_VHI_down = 1900; // minimum temp for going from VHIGH to HI in 1/100 of C (hysteresis) 77const int H_current_conversion_1 = 35; // current sense conversion constant (30A model, heat strip) 78const int B_current_conversion_1 = 210; // current sense conversion constant (5A model, blower) 79const int HB_current_conversion_2 = 10000; // current sense conversion constant 80const byte nb_pts_period = 4; // nb of points per 60Hz cylce for the current sense evaluation 81const int current_FAN_min[] = {0, 1300, 1400, 1600, 1900}; // blower current sense minimal threshold (mA) for OFF, LO, MED, HIGH, VHIGH states (PRELIMINARY) 82const int current_FAN_max[] = {500, 2200, 2400, 2700, 3200}; // blower current sense maximal threshold (mA) for OFF, LO, MED, HIGH, VHIGH states (PRELIMINARY) 83const int current_H_min[] = {0, 15000}; // heat strip current sense minimal threshold (mA) for OFF, ON states (PRELIMINARY) 84const int current_H_max[] = {1000, 25000}; // heat strip current sense maximal threshold (mA) for OFF, ON states (PRELIMINARY) 85const int USB_comm_period = 2000; // periodic delay (ms) between checks whether a USB connection is present 86 87 88// constants stored in the flash (instead of SRAM) 89 90const PROGMEM int16_t thermistor_conversion[] = {32767, 32767, 29765, 26554, 24485, 22984, 21820, 20876, 20087, 19411, 18822, 18301, 17836, 17415, 17032, 16681, 16358, 16058, 15779, 15518, 15273, 15042, 14824, 14618, 14422, 14235, 14058, 13888, 13726, 13570, 13421, 13277, 13139, 13006, 12877, 12753, 12633, 12517, 12404, 12295, 12189, 12086, 11987, 11889, 11795, 11703, 11613, 11525, 11440, 11357, 11275, 11196, 11118, 11042, 10967, 10895, 10823, 10753, 10685, 10618, 10552, 10487, 10424, 10362, 10300, 10240, 10181, 10123, 10066, 10010, 9955, 9901, 9847, 9795, 9743, 9692, 9642, 9592, 9543, 9495, 9448, 9401, 9355, 9309, 9265, 9220, 9177, 9133, 9091, 9049, 9007, 8966, 8926, 8885, 8846, 8807, 8768, 8730, 8692, 8655, 8618, 8581, 8545, 8509, 8474, 8439, 8404, 8370, 8336, 8302, 8269, 8236, 8203, 8171, 8139, 8107, 8076, 8044, 8014, 7983, 7953, 7923, 7893, 7863, 7834, 7805, 7776, 7748, 7720, 7691, 7664, 7636, 7609, 7582, 7555, 7528, 7501, 7475, 7449, 7423, 7397, 7372, 7346, 7321, 7296, 7272, 7247, 7223, 7198, 7174, 7150, 7126, 7103, 7079, 7056, 7033, 7010, 6987, 6965, 6942, 6920, 6897, 6875, 6853, 6832, 6810, 6788, 6767, 6746, 6724, 6703, 6682, 6662, 6641, 6620, 6600, 6580, 6560, 6539, 6519, 6500, 6480, 6460, 6441, 6421, 6402, 6383, 6364, 6345, 6326, 6307, 6288, 6269, 6251, 6232, 6214, 6196, 6178, 6160, 6142, 6124, 6106, 6088, 6071, 6053, 6036, 6018, 6001, 5984, 5966, 5949, 5932, 5915, 5899, 5882, 5865, 5849, 5832, 5815, 5799, 5783, 5766, 5750, 5734, 5718, 5702, 5686, 5670, 5655, 5639, 5623, 5608, 5592, 5577, 5561, 5546, 5530, 5515, 5500, 5485, 5470, 5455, 5440, 5425, 5410, 5395, 5381, 5366, 5351, 5337, 5322, 5308, 5293, 5279, 5265, 5250, 5236, 5222, 5208, 5194, 5180, 5166, 5152, 5138, 5124, 5111, 5097, 5083, 5069, 5056, 5042, 5029, 5015, 5002, 4989, 4975, 4962, 4949, 4935, 4922, 4909, 4896, 4883, 4870, 4857, 4844, 4831, 4818, 4805, 4793, 4780, 4767, 4754, 4742, 4729, 4717, 4704, 4692, 4679, 4667, 4654, 4642, 4630, 4617, 4605, 4593, 4581, 4568, 4556, 4544, 4532, 4520, 4508, 4496, 4484, 4472, 4460, 4448, 4437, 4425, 4413, 4401, 4389, 4378, 4366, 4354, 4343, 4331, 4320, 4308, 4297, 4285, 4274, 4262, 4251, 4240, 4228, 4217, 4206, 4194, 4183, 4172, 4161, 4150, 4138, 4127, 4116, 4105, 4094, 4083, 4072, 4061, 4050, 4039, 4028, 4017, 4006, 3996, 3985, 3974, 3963, 3952, 3942, 3931, 3920, 3910, 3899, 3888, 3878, 3867, 3857, 3846, 3835, 3825, 3814, 3804, 3793, 3783, 3773, 3762, 3752, 3741, 3731, 3721, 3710, 3700, 3690, 3680, 3669, 3659, 3649, 3639, 3628, 3618, 3608, 3598, 3588, 3578, 3568, 3558, 3548, 3538, 3527, 3517, 3507, 3498, 3488, 3478, 3468, 3458, 3448, 3438, 3428, 3418, 3408, 3399, 3389, 3379, 3369, 3359, 3350, 3340, 3330, 3320, 3311, 3301, 3291, 3282, 3272, 3262, 3253, 3243, 3233, 3224, 3214, 3205, 3195, 3186, 3176, 3166, 3157, 3147, 3138, 3128, 3119, 3109, 3100, 3091, 3081, 3072, 3062, 3053, 3044, 3034, 3025, 3015, 3006, 2997, 2987, 2978, 2969, 2959, 2950, 2941, 2932, 2922, 2913, 2904, 2895, 2885, 2876, 2867, 2858, 2849, 2839, 2830, 2821, 2812, 2803, 2793, 2784, 2775, 2766, 2757, 2748, 2739, 2730, 2721, 2712, 2702, 2693, 2684, 2675, 2666, 2657, 2648, 2639, 2630, 2621, 2612, 2603, 2594, 2585, 2576, 2567, 2558, 2549, 2540, 2531, 2522, 2513, 2504, 2496, 2487, 2478, 2469, 2460, 2451, 2442, 2433, 2424, 2415, 2407, 2398, 2389, 2380, 2371, 2362, 2353, 2344, 2336, 2327, 2318, 2309, 2300, 2291, 2283, 2274, 2265, 2256, 2247, 2239, 2230, 2221, 2212, 2203, 2195, 2186, 2177, 2168, 2159, 2151, 2142, 2133, 2124, 2116, 2107, 2098, 2089, 2081, 2072, 2063, 2054, 2046, 2037, 2028, 2019, 2011, 2002, 1993, 1984, 1976, 1967, 1958, 1949, 1941, 1932, 1923, 1914, 1906, 1897, 1888, 1880, 1871, 1862, 1853, 1845, 1836, 1827, 1818, 1810, 1801, 1792, 1784, 1775, 1766, 1757, 1749, 1740, 1731, 1722, 1714, 1705, 1696, 1687, 1679, 1670, 1661, 1653, 1644, 1635, 1626, 1618, 1609, 1600, 1591, 1583, 1574, 1565, 1556, 1548, 1539, 1530, 1521, 1512, 1504, 1495, 1486, 1477, 1469, 1460, 1451, 1442, 1433, 1425, 1416, 1407, 1398, 1389, 1381, 1372, 1363, 1354, 1345, 1336, 1328, 1319, 1310, 1301, 1292, 1283, 1274, 1266, 1257, 1248, 1239, 1230, 1221, 1212, 1203, 1194, 1185, 1176, 1168, 1159, 1150, 1141, 1132, 1123, 1114, 1105, 1096, 1087, 1078, 1069, 1060, 1051, 1042, 1033, 1024, 1015, 1006, 997, 988, 979, 969, 960, 951, 942, 933, 924, 915, 906, 897, 887, 878, 869, 860, 851, 842, 832, 823, 814, 805, 795, 786, 777, 768, 758, 749, 740, 730, 721, 712, 702, 693, 684, 674, 665, 655, 646, 637, 627, 618, 608, 599, 589, 580, 570, 561, 551, 542, 532, 523, 513, 503, 494, 484, 475, 465, 455, 445, 436, 426, 416, 407, 397, 387, 377, 367, 358, 348, 338, 328, 318, 308, 298, 288, 278, 268, 259, 249, 238, 228, 218, 208, 198, 188, 178, 168, 158, 147, 137, 127, 117, 106, 96, 86, 76, 65, 55, 44, 34, 24, 13, 3, -8, -18, -29, -40, -50, -61, -71, -82, -93, -104, -114, -125, -136, -147, -158, -168, -179, -190, -201, -212, -223, -234, -245, -257, -268, -279, -290, -301, -312, -324, -335, -346, -358, -369, -381, -392, -404, -415, -427, -438, -450, -462, -473, -485, -497, -509, -521, -532, -544, -556, -568, -580, -592, -605, -617, -629, -641, -654, -666, -678, -691, -703, -716, -728, -741, -753, -766, -779, -792, -804, -817, -830, -843, -856, -869, -883, -896, -909, -922, -936, -949, -963, -976, -990, -1003, -1017, -1031, -1045, -1058, -1072, -1086, -1100, -1115, -1129, -1143, -1157, -1172, -1186, -1201, -1216, -1230, -1245, -1260, -1275, -1290, -1305, -1320, -1335, -1351, -1366, -1381, -1397, -1413, -1428, -1444, -1460, -1476, -1492, -1509, -1525, -1541, -1558, -1575, -1591, -1608, -1625, -1642, -1659, -1677, -1694, -1711, -1729, -1747, -1765, -1783, -1801, -1819, -1838, -1856, -1875, -1894, -1913, -1932, -1951, -1971, -1990, -2010, -2030, -2050, -2070, -2091, -2111, -2132, -2153, -2174, -2196, -2217, -2239, -2261, -2283, -2306, -2328, -2351, -2375, -2398, -2422, -2446, -2470, -2494, -2519, -2544, -2569, -2595, -2621, -2647, -2674, -2701, -2728, -2756, -2784, -2812, -2841, -2870, -2900, -2930, -2961, -2992, -3024, -3056, -3089, -3122, -3156, -3190, -3225, -3261, -3297, -3334, -3372, -3411, -3451, -3491, -3533, -3575, -3618, -3663, -3708, -3755, -3803, -3853, -3904, -3956, -4010, -4066, -4124, -4184, -4247, -4311, -4379, -4449, -4523, -4600, -4682, -4768, -4859, -4956, -5059, -5171, -5291, -5423, -5568, -5731, -5915, -6128, -6384, -6704, -7138, -7839, -32768}; // use this form 91const PROGMEM uint16_t current_sensing_conversion[] = {64532, 64280, 64029, 63778, 63527, 63277, 63027, 62778, 62530, 62281, 62034, 61787, 61540, 61294, 61048, 60803, 60558, 60314, 60070, 59827, 59585, 59342, 59101, 58859, 58619, 58378, 58139, 57899, 57661, 57422, 57185, 56947, 56711, 56474, 56238, 56003, 55768, 55534, 55300, 55067, 54834, 54602, 54370, 54138, 53908, 53677, 53447, 53218, 52989, 52761, 52533, 52305, 52078, 51852, 51626, 51401, 51176, 50951, 50727, 50504, 50281, 50058, 49836, 49615, 49394, 49173, 48953, 48734, 48515, 48296, 48078, 47861, 47644, 47427, 47211, 46995, 46780, 46566, 46352, 46138, 45925, 45712, 45500, 45289, 45077, 44867, 44657, 44447, 44238, 44029, 43821, 43613, 43406, 43199, 42993, 42787, 42582, 42378, 42173, 41970, 41766, 41564, 41361, 41160, 40958, 40758, 40557, 40357, 40158, 39959, 39761, 39563, 39366, 39169, 38973, 38777, 38582, 38387, 38192, 37998, 37805, 37612, 37420, 37228, 37036, 36846, 36655, 36465, 36276, 36087, 35898, 35710, 35523, 35336, 35150, 34964, 34778, 34593, 34409, 34225, 34041, 33858, 33676, 33494, 33312, 33131, 32950, 32770, 32591, 32412, 32233, 32055, 31877, 31700, 31524, 31348, 31172, 30997, 30822, 30648, 30475, 30301, 30129, 29957, 29785, 29614, 29443, 29273, 29103, 28934, 28765, 28597, 28429, 28262, 28095, 27929, 27763, 27598, 27433, 27269, 27105, 26942, 26779, 26617, 26455, 26294, 26133, 25973, 25813, 25653, 25495, 25336, 25178, 25021, 24864, 24708, 24552, 24397, 24242, 24087, 23933, 23780, 23627, 23475, 23323, 23171, 23020, 22870, 22720, 22570, 22421, 22273, 22125, 21977, 21830, 21684, 21538, 21392, 21247, 21103, 20959, 20815, 20672, 20529, 20387, 20246, 20105, 19964, 19824, 19684, 19545, 19407, 19269, 19131, 18994, 18857, 18721, 18585, 18450, 18316, 18181, 18048, 17914, 17782, 17650, 17518, 17387, 17256, 17126, 16996, 16867, 16738, 16610, 16482, 16355, 16228, 16102, 15976, 15850, 15726, 15601, 15478, 15354, 15231, 15109, 14987, 14866, 14745, 14625, 14505, 14385, 14266, 14148, 14030, 13913, 13796, 13679, 13564, 13448, 13333, 13219, 13105, 12991, 12878, 12766, 12654, 12542, 12431, 12321, 12211, 12101, 11992, 11884, 11776, 11668, 11561, 11455, 11349, 11243, 11138, 11033, 10929, 10826, 10723, 10620, 10518, 10416, 10315, 10214, 10114, 10015, 9916, 9817, 9719, 9621, 9524, 9427, 9331, 9235, 9140, 9045, 8951, 8857, 8764, 8671, 8579, 8487, 8396, 8305, 8215, 8125, 8036, 7947, 7859, 7771, 7684, 7597, 7511, 7425, 7339, 7255, 7170, 7086, 7003, 6920, 6838, 6756, 6674, 6594, 6513, 6433, 6354, 6275, 6196, 6119, 6041, 5964, 5888, 5812, 5736, 5661, 5587, 5513, 5439, 5366, 5294, 5222, 5150, 5079, 5009, 4939, 4869, 4800, 4731, 4663, 4596, 4529, 4462, 4396, 4330, 4265, 4201, 4136, 4073, 4010, 3947, 3885, 3823, 3762, 3701, 3641, 3581, 3522, 3464, 3405, 3348, 3290, 3234, 3177, 3122, 3066, 3012, 2957, 2904, 2850, 2798, 2745, 2694, 2642, 2591, 2541, 2491, 2442, 2393, 2345, 2297, 2250, 2203, 2156, 2110, 2065, 2020, 1976, 1932, 1888, 1846, 1803, 1761, 1720, 1679, 1638, 1598, 1559, 1520, 1481, 1443, 1406, 1369, 1332, 1296, 1261, 1226, 1191, 1157, 1124, 1091, 1058, 1026, 995, 963, 933, 903, 873, 844, 815, 787, 760, 733, 706, 680, 654, 629, 604, 580, 557, 533, 511, 488, 467, 446, 425, 405, 385, 366, 347, 329, 311, 294, 277, 261, 245, 229, 215, 200, 187, 173, 160, 148, 136, 125, 114, 104, 94, 84, 76, 67, 59, 52, 45, 39, 33, 27, 22, 18, 14, 10, 7, 5, 3, 2, 1, 0, 0, 1, 2, 3, 5, 7, 10, 14, 18, 22, 27, 33, 39, 45, 52, 59, 67, 76, 84, 94, 104, 114, 125, 136, 148, 160, 173, 187, 200, 215, 229, 245, 261, 277, 294, 311, 329, 347, 366, 385, 405, 425, 446, 467, 488, 511, 533, 557, 580, 604, 629, 654, 680, 706, 733, 760, 787, 815, 844, 873, 903, 933, 963, 995, 1026, 1058, 1091, 1124, 1157, 1191, 1226, 1261, 1296, 1332, 1369, 1406, 1443, 1481, 1520, 1559, 1598, 1638, 1679, 1720, 1761, 1803, 1846, 1888, 1932, 1976, 2020, 2065, 2110, 2156, 2203, 2250, 2297, 2345, 2393, 2442, 2491, 2541, 2591, 2642, 2694, 2745, 2798, 2850, 2904, 2957, 3012, 3066, 3122, 3177, 3234, 3290, 3348, 3405, 3464, 3522, 3581, 3641, 3701, 3762, 3823, 3885, 3947, 4010, 4073, 4136, 4201, 4265, 4330, 4396, 4462, 4529, 4596, 4663, 4731, 4800, 4869, 4939, 5009, 5079, 5150, 5222, 5294, 5366, 5439, 5513, 5587, 5661, 5736, 5812, 5888, 5964, 6041, 6119, 6196, 6275, 6354, 6433, 6513, 6594, 6674, 6756, 6838, 6920, 7003, 7086, 7170, 7255, 7339, 7425, 7511, 7597, 7684, 7771, 7859, 7947, 8036, 8125, 8215, 8305, 8396, 8487, 8579, 8671, 8764, 8857, 8951, 9045, 9140, 9235, 9331, 9427, 9524, 9621, 9719, 9817, 9916, 10015, 10114, 10214, 10315, 10416, 10518, 10620, 10723, 10826, 10929, 11033, 11138, 11243, 11349, 11455, 11561, 11668, 11776, 11884, 11992, 12101, 12211, 12321, 12431, 12542, 12654, 12766, 12878, 12991, 13105, 13219, 13333, 13448, 13564, 13679, 13796, 13913, 14030, 14148, 14266, 14385, 14505, 14625, 14745, 14866, 14987, 15109, 15231, 15354, 15478, 15601, 15726, 15850, 15976, 16102, 16228, 16355, 16482, 16610, 16738, 16867, 16996, 17126, 17256, 17387, 17518, 17650, 17782, 17914, 18048, 18181, 18316, 18450, 18585, 18721, 18857, 18994, 19131, 19269, 19407, 19545, 19684, 19824, 19964, 20105, 20246, 20387, 20529, 20672, 20815, 20959, 21103, 21247, 21392, 21538, 21684, 21830, 21977, 22125, 22273, 22421, 22570, 22720, 22870, 23020, 23171, 23323, 23475, 23627, 23780, 23933, 24087, 24242, 24397, 24552, 24708, 24864, 25021, 25178, 25336, 25495, 25653, 25813, 25973, 26133, 26294, 26455, 26617, 26779, 26942, 27105, 27269, 27433, 27598, 27763, 27929, 28095, 28262, 28429, 28597, 28765, 28934, 29103, 29273, 29443, 29614, 29785, 29957, 30129, 30301, 30475, 30648, 30822, 30997, 31172, 31348, 31524, 31700, 31877, 32055, 32233, 32412, 32591, 32770, 32950, 33131, 33312, 33494, 33676, 33858, 34041, 34225, 34409, 34593, 34778, 34964, 35150, 35336, 35523, 35710, 35898, 36087, 36276, 36465, 36655, 36846, 37036, 37228, 37420, 37612, 37805, 37998, 38192, 38387, 38582, 38777, 38973, 39169, 39366, 39563, 39761, 39959, 40158, 40357, 40557, 40758, 40958, 41160, 41361, 41564, 41766, 41970, 42173, 42378, 42582, 42787, 42993, 43199, 43406, 43613, 43821, 44029, 44238, 44447, 44657, 44867, 45077, 45289, 45500, 45712, 45925, 46138, 46352, 46566, 46780, 46995, 47211, 47427, 47644, 47861, 48078, 48296, 48515, 48734, 48953, 49173, 49394, 49615, 49836, 50058, 50281, 50504, 50727, 50951, 51176, 51401, 51626, 51852, 52078, 52305, 52533, 52761, 52989, 53218, 53447, 53677, 53908, 54138, 54370, 54602, 54834, 55067, 55300, 55534, 55768, 56003, 56238, 56474, 56711, 56947, 57185, 57422, 57661, 57899, 58139, 58378, 58619, 58859, 59101, 59342, 59585, 59827, 60070, 60314, 60558, 60803, 61048, 61294, 61540, 61787, 62034, 62281, 62530, 62778, 63027, 63277, 63527, 63778, 64029, 64280, 64532}; 92const PROGMEM byte LED1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}; 93const PROGMEM byte LED2[] = {0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2}; 94const PROGMEM byte LED3[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2}; 95 96// thermistor conversion : the "analogread" value is used as an index, what is stored in the flash are the correspoding 1024 temperatures (in 1/100 C) 97// current sense conversion, the instanteous current (mA) is given by : sqrt(current_sensing_conversion)/H_current_conversion_1*HB_current_conversion_2 for the heat strips and sqrt(current_sensing_conversion)/B_current_conversion_1*HB_current_conversion_2 for the blower 98 99 100 101// working variables 102 103byte current_speed = 0; // 0 min speed, 1,2,3 max speed (blower, current state) 104byte new_speed = 0; // 0 min speed, 1,2,3 max speed (blower, new state) 105byte G_current_status = 0; // current status of the G line (0=OFF, 1=ON) 106byte G_new_status = 0; // new status of the G line (0=OFF, 1=ON) 107byte W1_current_status = 0; // current status of the W1 line (0=OFF, 1=ON) 108byte W1_new_status = 0; // new status of the W1 line (0=OFF, 1=ON) 109byte W2_current_status = 0; // current status of the W2 line (0=OFF, 1=ON) 110byte W2_new_status = 0; // new status of the W2 line (0=OFF, 1=ON) 111byte W3_current_status = 0; // current status of the W3 line (0=OFF, 1=ON) 112byte W3_new_status = 0; // new status of the W3 line (0=OFF, 1=ON) 113int TH1_value = 0; // Temperature value (1/100 C), thermistor 1 114int TH2_value = 0; // Temperature value (1/100 C), thermistor 2 115byte active_elements_W1_W2[5] = {H4_ctrl, H1_ctrl, H2_ctrl, H3_ctrl, H4_ctrl}; // indexes 0 and 1 correspond to W1, indexes 2 and 3 to W2, the addresses of the heat strips are cycled through in the vector each time a new activation of W1 occcurs 116byte W1_heating_state = 0; // heating states associated with W1 (0: no heat strips activates, 1: first heat strip is activated, 2: both heat strips are activated) 117byte W2_heating_state = 0; // heating states associated with W2 (0: no heat strips activates, 1: first heat strip is activated, 2: both heat strips are activated) 118byte speed_change_stage = 3; // blower speed change states (0: beginning of speed change sequence, 1: the circuit is open, 2: The speed adjustment has been made, 3: the circuit is closed) 119byte fan_activation_state = 0; // blower fan state sequence for shutdown (=0 fan is ready for first step of startup or shutdown sequence, =1 shutdown sequence intermediate step, after SSR has openend the circuit before fan speed goes back to minimal value, =2 fan is off and speed is at low) 120byte pointer_CS = 0; // current sense consist of measuring multiplie instantaneous current value samples (4 per 60 Hz cycle, 36 consecutives cycles, 144 samples in total representing 600 ms) and calculating the RMS value, pointer_CS is the index in the vector current 121long correction_us = 0; // To ensure the current measurement are performed every 4.16 ms, a delay is adjusted each cycle to compensate for the small variations, correction_us is the correction to the fized latenccy in us, reevaluated at each cycle 122byte system_status_LED[] = {0, 0, 0, 0, 0, 0, 0, 0}; // LED1 LED2 LED3 color 0 =green 1 = yellow 2 = red, FAN status H1 H2 H3 H4 0 = OK(green) 1 = UC(yellow) 2 = OC(red) PRELIMINARY 123byte FAN_status = 0; // FAN_status (0= OFF, 1= LOW, 2= MED, 3= HIGH, 4= VHIGH) to be used as an indicator in the reporting system (USB) and eventually in the LED control PRELIMINARY 124byte HEATER_status = 0; // HEATER_status (0= OFF, 1= W1 1st heat strip, 2= W2 both heat strip, 3= W2 1st heat strip, 4= W2 both heat strip) to be used as an indicator in the reporting system (USB) and eventually in the LED control PRELIMINARY 125byte system_status_index = 0; // global value indicating the status in which the system is in, 27 possible states PRELIMINARY 126byte USB_connection_status = 0; // indication whether a USB connection is present or not 127unsigned int H1_current_vector[CS_vector_size]; // current sense vector of 144 samples for heat strip #1 128unsigned int H2_current_vector[CS_vector_size]; // current sense vector of 144 samples for heat strip #2 129unsigned int H3_current_vector[CS_vector_size]; // current sense vector of 144 samples for heat strip #3 130unsigned int H4_current_vector[CS_vector_size]; // current sense vector of 144 samples for heat strip #4 131unsigned int FAN_current_vector[CS_vector_size]; // current sense vector of 144 samples for the blower 132unsigned long H1_CS_sum = 0; // current sense sum for heat strip #1 133unsigned long H2_CS_sum = 0; // current sense sum for heat strip #2 134unsigned long H3_CS_sum = 0; // current sense sum for heat strip #3 135unsigned long H4_CS_sum = 0; // current sense sum for heat strip #4 136unsigned long FAN_CS_sum = 0; // current sense sum for the blower 137unsigned int current_sense_H_vector[nb_of_heating_elements]; // actual current value in mA for the heat strips 138unsigned int current_sense_FAN = 0; // actual current value in mA for the blower 139 140 141 142 143// time measurements 144 145unsigned long time_H0 = 0; // absolute time of the last relay activation 146unsigned long time_W1 = 0; // absolute time of the last W1 activation 147unsigned long time_W2 = 0; // absolute time of the last W2 activation 148unsigned long time_G0 = 0; // absolute time of the last blower activation 149unsigned long time_G = 0; // absolute time of the last speed change 150unsigned long time_SC = 0; // absolute time used for counting during the intermediate steps associated with a speed change 151unsigned long time_AF = 0; // absolute time used for couting during the intermediate steps associated with the activation of the fan 152unsigned long time_USB = 0; // absolute time used for the delays in the USB connection presence check 153unsigned long current_time = 0; // absolute time to verify, at each cycle whether the time overflow has occured (~ every ~ 50 days) 154unsigned long old_current_time = 0; // previous value of the absolute time to verify whether the time overflow has occured 155unsigned long time_old_CS = 0; // absolute time used in current sense algorithm to synchronize the measurements on a 60 Hz cycle (previous value) 156unsigned long time_new_CS = 0; // absolute time used in current sense algorithm to synchronize the measurements on a 60 Hz cycle (new value) 157unsigned int fixed_latency_old = 0; // latency to be waited at each cycle to stay synchronized with the 60 Hz electrical supply (previous value) 158unsigned int fixed_latency_new = 0; // latency to be waited at each cycle to stay synchronized with the 60 Hz electrical supply (new value) 159 160 161// 162// 163// 164// 165// end of global variables and constant declarations 166// 167// 168// 169// 170 171 172///////////////////////////////////////////////////////////////////////////// 173// routine for evaluating whether a speed change of the blower is required 174///////////////////////////////////////////////////////////////////////////// 175 176void new_speed_evaluation() { 177 178 179 // The verification is performed only if we're are not currently in the process of changing the speed 180 if (speed_change_stage == 3) { 181 182 183 // If the heat pump is active (W3) we force the blower to high speed for maximum efficiency 184 if (W3_current_status == 1) { 185 new_speed = 3; 186 } 187 else { 188 189 190 191 // validation of the current speed and check whether the temperature difference is over or under the thresholds we have defined 192 switch (current_speed) { 193 case 0: // LO speed 194 if (abs(TH1_value - TH2_value) >= delta_T_LO_up) { 195 new_speed = 1; 196 } 197 break; 198 199 case 1: // MED speed 200 if (abs(TH1_value - TH2_value) >= delta_T_MED_up) { 201 new_speed = 2; 202 } 203 if (abs(TH1_value - TH2_value) < delta_T_MED_down) { 204 new_speed = 0; 205 } 206 break; 207 208 case 2: // HI speed 209 if (abs(TH1_value - TH2_value) >= delta_T_HI_up) { 210 new_speed = 3; 211 } 212 if (abs(TH1_value - TH2_value) < delta_T_HI_down) { 213 new_speed = 1; 214 } 215 break; 216 217 case 3: // VHI speed 218 if (abs(TH1_value - TH2_value) < delta_T_VHI_down) { 219 new_speed = 2; 220 } 221 break; 222 } 223 224 } 225 } 226} 227 228///////////////////////////////////////////////////////////////////////////// 229 230 231 232 233 234 235///////////////////////////////////////////////////////////////////////////// 236// routine for changing the fan speed 237///////////////////////////////////////////////////////////////////////////// 238 239void speed_change() { 240 241 if (new_speed != current_speed) { 242 243 // if the speed_change_stage is equal to 3, its a new speed change sequence (and not an ongoing sequence), therefore we start at the beginning (speed_stage_stage=0) 244 if (speed_change_stage == 3) { 245 speed_change_stage = 0; 246 } 247 248 } 249 250 251 252 switch (speed_change_stage) { 253 254 // The electrical circuit is openend with the SSR relay 255 case 0: 256 257 digitalWrite(BSSR_ctrl, LOW); 258 speed_change_stage = 1; 259 time_SC = millis(); 260 261 break; 262 263 264 // if the delay after opening the circuit is over the 10 ms minimum, we select the new speed 265 case 1: 266 267 if ((long)(current_time - time_SC) >= delai_SSR) { 268 269 switch (new_speed) { 270 case 0: // LOWEST SPEED 271 272 digitalWrite(BHI_ctrl, LOW); 273 digitalWrite(BMED_ctrl, LOW); 274 digitalWrite(BLO_ctrl, LOW); 275 276 break; 277 case 1: // SECOND LOWEST 278 digitalWrite(BHI_ctrl, LOW); 279 digitalWrite(BMED_ctrl, LOW); 280 digitalWrite(BLO_ctrl, HIGH); 281 break; 282 case 2: // SECOND HIGHEST 283 digitalWrite(BHI_ctrl, LOW); 284 digitalWrite(BMED_ctrl, HIGH); 285 digitalWrite(BLO_ctrl, HIGH); 286 break; 287 case 3: // HIGHEST 288 digitalWrite(BHI_ctrl, HIGH); 289 digitalWrite(BMED_ctrl, HIGH); 290 digitalWrite(BLO_ctrl, HIGH); 291 break; 292 } 293 speed_change_stage = 2; 294 time_SC = millis(); 295 296 297 } 298 break; 299 300 301 302 // if the delay after selecting the new speed is over the 15 ms minimum (mechanical relay boucing), we close the circuit again with the SSR 303 case 2: 304 305 if ((long)(current_time - time_SC) >= delai_relay) { 306 digitalWrite(BSSR_ctrl, HIGH); 307 current_speed = new_speed; 308 time_G = millis(); 309 speed_change_stage = 3; 310 break; 311 312 313 } 314 } 315} 316 317///////////////////////////////////////////////////////////////////////////// 318 319 320 321 322 323 324///////////////////////////////////////////////////////////////////////////// 325// temperature reading routine 326///////////////////////////////////////////////////////////////////////////// 327 328int read_temp(int pin_adress) { 329 330 331 int TH_raw_cnt; 332 int read_temp_value; 333 334 TH_raw_cnt = analogRead(pin_adress); 335 336 read_temp_value = pgm_read_word(&thermistor_conversion[TH_raw_cnt]); 337 338 return read_temp_value; 339} 340 341 342 343 344 345 346 347 348 349 350 351 352///////////////////////////////////////////////////////////////////////////// 353 354 355 356 357 358 359///////////////////////////////////////////////////////////////////////////// 360// routine for the activation of the relays associated withe the W1 heat command 361///////////////////////////////////////////////////////////////////////////// 362 363void activate_W1() { 364 365 switch (W1_new_status) { 366 367 // W1 heat strips deactivation 368 case 0: 369 370 // Validation of which heating state we're in (state 0 should not be an option) 371 switch (W1_heating_state) { 372 373 // deactivation of heat strip #1 associated with W1 374 case 1: 375 digitalWrite(active_elements_W1_W2[0], W1_new_status); 376 W1_current_status = W1_new_status; 377 W1_heating_state = 0; 378 break; 379 380 // deactivation of heat strip #2 associated with W1 381 case 2: 382 digitalWrite(active_elements_W1_W2[1], W1_new_status); 383 W1_heating_state = 1; 384 break; 385 } 386 break; 387 388 389 // W1 heat strips activation 390 case 1: 391 392 // Validation of which heating state we're in (state 2 should not be an option) 393 switch (W1_heating_state) { 394 395 // activation of heat strip #1 associated with W1 396 case 0: 397 398 399 // rotation of the heat strips associated with W1 and W2 (for even wear) 400 // before performing the rotation, we validate that W2 is not active, it should not as thermostat usually don't activate W2 without activating W1 401 if (W2_current_status == 0) { 402 403 404 int i; 405 for (i = 0; i < nb_of_heating_elements; i++) { 406 407 active_elements_W1_W2[i] = active_elements_W1_W2[i + 1]; 408 } 409 410 active_elements_W1_W2[nb_of_heating_elements] = active_elements_W1_W2[0]; 411 412 } 413 414 415 // activation of heat strip #1 416 digitalWrite(active_elements_W1_W2[0], W1_new_status); 417 time_W1 = millis(); 418 W1_current_status = W1_new_status; 419 W1_heating_state = 1; 420 break; 421 422 // activation of heat strip #2 assocviated with W1 423 case 1: 424 digitalWrite(active_elements_W1_W2[1], W1_new_status); 425 W1_heating_state = 2; 426 break; 427 428 } 429 break; 430 431 } 432 433 time_H0 = millis(); 434 435} 436 437 438///////////////////////////////////////////////////////////////////////////// 439 440 441 442 443 444 445///////////////////////////////////////////////////////////////////////////// 446// routine for the activation of the relays associated withe the W2 heat command 447///////////////////////////////////////////////////////////////////////////// 448 449void activate_W2() { 450 451 switch (W2_new_status) { 452 453 // W2 heat strips deactivation 454 case 0: 455 456 // Validation of which heating state we're in (state 0 should not be an option) 457 switch (W2_heating_state) { 458 459 // deactivation of heat strip #1 associated with W2 460 case 1: 461 digitalWrite(active_elements_W1_W2[2], W2_new_status); 462 W2_current_status = W2_new_status; 463 W2_heating_state = 0; 464 break; 465 466 // deactivation of heat strip #2 associated with W2 467 case 2: 468 digitalWrite(active_elements_W1_W2[3], W2_new_status); 469 W2_heating_state = 1; 470 break; 471 } 472 break; 473 474 475 // W2 heat strips activation 476 case 1: 477 478 // Validation of which heating state we're in (state 2 should not be an option) 479 switch (W2_heating_state) { 480 481 // activation of heat strip #1 associated with W2 482 case 0: 483 digitalWrite(active_elements_W1_W2[2], W2_new_status); 484 time_W2 = millis(); 485 W2_current_status = W2_new_status; // on met jour le status W2 486 W2_heating_state = 1; 487 break; 488 489 // activation of heat strip #2 associated with W2 490 case 1: 491 digitalWrite(active_elements_W1_W2[3], W2_new_status); 492 W2_heating_state = 2; 493 break; 494 495 } 496 break; 497 498 } 499 time_H0 = millis(); 500 501} 502 503 504 505///////////////////////////////////////////////////////////////////////////// 506 507 508 509 510 511 512///////////////////////////////////////////////////////////////////////////// 513// routine for the activation of the blower 514///////////////////////////////////////////////////////////////////////////// 515 516 517void activate_G() { 518 519 520 // check whether the fan was in a steady state (OFF or ON) 521 // if the answer is positive, put the fan state at value for a new sequence (ON or OFF) 522 523 if (fan_activation_state == 2) { 524 fan_activation_state = 0; 525 526 } 527 528 529 530 switch (G_new_status) { 531 532 533 // blower deactivation, by default we set the speed to the lowest setting for the next power-up 534 case 0: 535 536 switch (fan_activation_state) { 537 538 // The electrical circuit is openend with the SSR relay 539 case 0: 540 digitalWrite(BSSR_ctrl, LOW); 541 fan_activation_state = 1; 542 time_AF = millis(); 543 break; 544 545 // if the delay after opening the circuit is over the 10 ms minimum, we select the new speed (lowest value for next power-up) 546 case 1: 547 548 if ((long)(current_time - time_AF) >= delai_SSR) { 549 550 digitalWrite(BHI_ctrl, LOW); 551 digitalWrite(BMED_ctrl, LOW); 552 digitalWrite(BLO_ctrl, LOW); 553 current_speed = 0; 554 new_speed = 0; 555 fan_activation_state = 2; 556 G_current_status = G_new_status; 557 558 } 559 break; 560 } 561 break; 562 563 564 // We close the circuit with the SSR for the blower power-up 565 case 1: 566 567 digitalWrite(BSSR_ctrl, HIGH); 568 569 time_G0 = millis(); 570 time_G = time_G0; 571 G_current_status = G_new_status; 572 break; 573 } 574 575} 576 577 578///////////////////////////////////////////////////////////////////////////// 579 580 581 582 583 584 585///////////////////////////////////////////////////////////////////////////// 586// routine for the evaluation of the current sense values 587///////////////////////////////////////////////////////////////////////////// 588 589 590void current_update() { 591 592 int CS_raw_cnt; 593 float temp_FLOAT_var; 594 595 596 // we substract the raw instantaneous current value at the current pointer position 597 598 H1_CS_sum = H1_CS_sum - H1_current_vector[pointer_CS]; 599 H2_CS_sum = H2_CS_sum - H2_current_vector[pointer_CS]; 600 H3_CS_sum = H3_CS_sum - H3_current_vector[pointer_CS]; 601 H4_CS_sum = H4_CS_sum - H4_current_vector[pointer_CS]; 602 FAN_CS_sum = FAN_CS_sum - FAN_current_vector[pointer_CS]; 603 604 605 // we update in the raw instanteous current vectors the value at the current pointer position 606 607 CS_raw_cnt = analogRead(CSH1); 608 H1_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 609 610 CS_raw_cnt = analogRead(CSH2); 611 H2_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 612 613 CS_raw_cnt = analogRead(CSH3); 614 H3_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 615 616 CS_raw_cnt = analogRead(CSH4); 617 H4_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 618 619 CS_raw_cnt = analogRead(CSFAN); 620 FAN_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 621 622 // we update the raw sum 623 624 H1_CS_sum = H1_CS_sum + H1_current_vector[pointer_CS]; 625 H2_CS_sum = H2_CS_sum + H2_current_vector[pointer_CS]; 626 H3_CS_sum = H3_CS_sum + H3_current_vector[pointer_CS]; 627 H4_CS_sum = H4_CS_sum + H4_current_vector[pointer_CS]; 628 FAN_CS_sum = FAN_CS_sum + FAN_current_vector[pointer_CS]; 629 630 // check whether the pointer has reached the end of the vector and update of the latency value for synchronizing the current evaluation with the 60 Hz electrical cycle 631 632 if (pointer_CS == CS_vector_size - 1) { 633 pointer_CS = 0; 634 time_new_CS = millis(); 635 correction_us = (long) 100000 / 6 / nb_pts_period - (time_new_CS - time_old_CS) * 1000 / CS_vector_size; 636 time_old_CS = time_new_CS; 637 638 639 fixed_latency_new = fixed_latency_old + correction_us; 640 641 fixed_latency_old = fixed_latency_new; 642 643 644 } 645 else { 646 pointer_CS++; 647 } 648 649 // conversion of the current value from raw to physical value in mA 650 651 temp_FLOAT_var = (float) sqrt(H1_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 652 current_sense_H_vector[0] = temp_FLOAT_var; 653 654 temp_FLOAT_var = (float) sqrt(H2_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 655 current_sense_H_vector[1] = temp_FLOAT_var; 656 657 temp_FLOAT_var = (float) sqrt(H3_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 658 current_sense_H_vector[2] = temp_FLOAT_var; 659 660 temp_FLOAT_var = (float) sqrt(H4_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 661 current_sense_H_vector[3] = temp_FLOAT_var; 662 663 temp_FLOAT_var = (float) sqrt(FAN_CS_sum / CS_vector_size) / B_current_conversion_1 * HB_current_conversion_2; 664 current_sense_FAN = temp_FLOAT_var; 665} 666 667 668///////////////////////////////////////////////////////////////////////////// 669 670 671 672 673 674 675///////////////////////////////////////////////////////////////////////////// 676// routine for comparing the current sense values to the thresholds for error management PRELIMINARY 677///////////////////////////////////////////////////////////////////////////// 678 679void validation_current_vs_status() { 680 681 // blower current management 682 switch (G_current_status) { 683 684 case 0: 685 if (current_sense_FAN < current_FAN_min[0]) { 686 system_status_LED[3] = 1; 687 } 688 if (current_sense_FAN > current_FAN_max[0]) { 689 system_status_LED[3] = 1; 690 } 691 692 break; 693 case 1: 694 695 if (current_sense_FAN < current_FAN_min[current_speed + 1]) { 696 system_status_LED[3] = 1; 697 } 698 if (current_sense_FAN > current_FAN_max[current_speed + 1]) { 699 system_status_LED[3] = 1; 700 } 701 break; 702 } 703 704 705 706 707 708} 709 710 711///////////////////////////////////////////////////////////////////////////// 712 713 714 715 716 717 718///////////////////////////////////////////////////////////////////////////// 719// routine for sending the monitored values on the virtual COM port if a USB connection is detected 720///////////////////////////////////////////////////////////////////////////// 721 722 723void USB_status_verbose() { 724 725 //Serial.print("Current time = "); 726 Serial.println(current_time); 727 //Serial.print("system status index = "); 728 Serial.println(system_status_index); 729 //Serial.print("FAN status = "); 730 Serial.println(FAN_status); 731 //Serial.print("HEATER status = "); 732 Serial.println(HEATER_status); 733 //Serial.print("FAN UC / OC status = "); 734 Serial.println(system_status_LED[3]); 735 //Serial.print("H1 UC / OC status = "); 736 Serial.println(system_status_LED[4]); 737 //Serial.print("H2 UC / OC status = "); 738 Serial.println(system_status_LED[5]); 739 //Serial.print("H3 UC / OC status = "); 740 Serial.println(system_status_LED[6]); 741 //Serial.print("H4 UC / OC status = "); 742 Serial.println(system_status_LED[7]); 743 //Serial.print("G status = "); 744 Serial.println(G_current_status); 745 //Serial.print("W1 status = "); 746 Serial.println(W1_current_status); 747 //Serial.print("W2 status = "); 748 Serial.println(W2_current_status); 749 //Serial.print("W3 status = "); 750 Serial.println(W3_current_status); 751 //Serial.print("Thermistor 1 value (C) = "); 752 Serial.println(TH1_value); 753 //Serial.print("Thermistor 2 value (C) = "); 754 Serial.println(TH2_value); 755 //Serial.print("FAN RMS current (mA) = "); 756 Serial.println(current_sense_FAN); 757 //Serial.print("H1 RMS current (mA) = "); 758 Serial.println(current_sense_H_vector[0]); 759 //Serial.print("H2 RMS current (mA) = "); 760 Serial.println(current_sense_H_vector[1]); 761 //Serial.print("H3 RMS current (mA) = "); 762 Serial.println(current_sense_H_vector[2]); 763 //Serial.print("H4 RMS current (mA) = "); 764 Serial.println(current_sense_H_vector[3]); 765 //Serial.print("loop delay = "); 766 Serial.println(fixed_latency_new); 767 768 time_USB = millis(); 769} 770 771 772///////////////////////////////////////////////////////////////////////////// 773 774 775 776 777 778 779///////////////////////////////////////////////////////////////////////////// 780// error management and system status update PRELIMINARY 781///////////////////////////////////////////////////////////////////////////// 782 783void system_status_update() { 784 785 FAN_status = 0; 786 787 if (G_current_status == 1) { 788 FAN_status = current_speed + 1; 789 } 790 791 HEATER_status = 0; 792 793 if (W1_current_status == 1) { 794 HEATER_status = HEATER_status + W1_heating_state; 795 796 if (W2_current_status == 1) { 797 HEATER_status = HEATER_status + W2_heating_state; 798 } 799 } 800 801 system_status_index = FAN_status * 5 + HEATER_status; 802 803 // Check whether we are in error mode 804 805 if (system_status_LED[3] > 0) { 806 807 808 // blower issue, major error, heat strips cannot be operated (not implemented yet) 809 810 system_status_index = 26; 811 812 } 813 else 814 { 815 816 817 // Limp mode management, blower is working but at least 1 heat strip is not functionnal 818 819 if (system_status_LED[4] + system_status_LED[5] + system_status_LED[6] + system_status_LED[7] > 0) { 820 821 if ((system_status_LED[4] == 0) || (system_status_LED[5] == 0) || (system_status_LED[6] == 0) || (system_status_LED[7] == 0)) { 822 823 824 // At least one heat strip is not functionnal, we are in limp mode 825 826 system_status_index = 25; 827 } 828 else 829 { 830 831 // Every heat strips are not functionnal, major error 832 system_status_index = 26; 833 } 834 } 835 } 836 837 system_status_LED[0] = pgm_read_word(&LED1[system_status_index]); 838 system_status_LED[1] = pgm_read_word(&LED2[system_status_index]); 839 system_status_LED[2] = pgm_read_word(&LED3[system_status_index]); 840 841} 842 843///////////////////////////////////////////////////////////////////////////// 844 845 846 847 848 849 850///////////////////////////////////////////////////////////////////////////// 851// main loop initialization 852///////////////////////////////////////////////////////////////////////////// 853 854 855void setup() { 856 857 Serial.begin(9600); 858 859 // initialisation 860 861 pinMode(LED_ctrl, OUTPUT); 862 pinMode(H1_ctrl, OUTPUT); 863 pinMode(H2_ctrl, OUTPUT); 864 pinMode(H3_ctrl, OUTPUT); 865 pinMode(H4_ctrl, OUTPUT); 866 pinMode(BLO_ctrl, OUTPUT); 867 pinMode(BMED_ctrl, OUTPUT); 868 pinMode(BHI_ctrl, OUTPUT); 869 pinMode(BSSR_ctrl, OUTPUT); 870 pinMode(G, INPUT); 871 pinMode(W1, INPUT); 872 pinMode(W2, INPUT); 873 pinMode(W3, INPUT); 874 875 // analog inputs initialization 876 877 analogRead(TH1); 878 analogRead(TH2); 879 analogRead(CSH1); 880 analogRead(CSH2); 881 analogRead(CSH3); 882 analogRead(CSH4); 883 analogRead(CSFAN); 884 885 // LED light initialization 886 887 digitalWrite(LED_ctrl, LOW); // HIGH = RED, LOW = GREEN 888 889 // initialization of the heat strips relays 890 digitalWrite(H1_ctrl, LOW); 891 digitalWrite(H2_ctrl, LOW); 892 digitalWrite(H3_ctrl, LOW); 893 digitalWrite(H4_ctrl, LOW); 894 895 // initialization of blower relays 896 digitalWrite(BSSR_ctrl, LOW); 897 digitalWrite(BHI_ctrl, LOW); 898 digitalWrite(BMED_ctrl, LOW); 899 digitalWrite(BLO_ctrl, LOW); 900 901 902 // initialization of the vectors 903 memset(H1_current_vector, 0, CS_vector_size); 904 memset(H2_current_vector, 0, CS_vector_size); 905 memset(H3_current_vector, 0, CS_vector_size); 906 memset(H4_current_vector, 0, CS_vector_size); 907 memset(FAN_current_vector, 0, CS_vector_size); 908 memset(current_sense_H_vector, 0, nb_of_heating_elements); 909 910 911} 912 913 914///////////////////////////////////////////////////////////////////////////// 915 916 917 918 919 920 921///////////////////////////////////////////////////////////////////////////// 922// main loop 923///////////////////////////////////////////////////////////////////////////// 924 925 926 927void loop() { 928 929 930 // reading of the thermostat signals 931 932 933 G_new_status = (digitalRead(G) == LOW); // inverse logic, G_new_status is equal to 1 (fan activation) when the actual physical signal on the board is LOW 934 W1_new_status = (digitalRead(W1) == LOW); // inverse logic, W1_new_status is equal to 1 (heat command active) when the actual physical signal on the board is LOW 935 W2_new_status = (digitalRead(W2) == LOW); // inverse logic, W2_new_status is equal to 1 (heat command active) when the actual physical signal on the board is LOW 936 W3_new_status = (digitalRead(W3) == LOW); // inverse logic, W3_new_status is equal to 1 (heat pump is active) when the actual physical signal on the board is LOW 937 938 // current time is updated once per cycle in the main loop 939 current_time = millis(); 940 941 942 // rollover just happenend, reseeting of all the time stamps, the usual delays between the different steps will be longer just this one time, once every 50 days 943 if (old_current_time > current_time) { 944 945 time_H0 = current_time; 946 time_W1 = current_time; 947 time_W2 = current_time; 948 time_G0 = current_time; 949 time_G = current_time; 950 time_old_CS = current_time; 951 time_new_CS = current_time; 952 time_SC = current_time; 953 time_AF = current_time; 954 time_USB = current_time; 955 } 956 957 old_current_time = current_time; 958 959 960 // Update of the thermistor temperature at every loop (mostly for monitoring purposes as it could be performed only when the blower is active) 961 TH1_value = read_temp(TH1); 962 TH2_value = read_temp(TH2); 963 964 // security check, if the heat commands (W1 or W2) or the heat pump (W3) are active, we make sure to operate the blower 965 if ((W1_current_status == 1 || W2_current_status == 1 || W3_current_status == 1) && (G_current_status == 0 || G_new_status == 0 )) { 966 967 G_new_status = 1; 968 969 } 970 971 972 973 // a change has been detected on the blower G command status 974 if (G_new_status != G_current_status) { 975 976 activate_G(); 977 } 978 979 980 // optimization of the blower speed and change of its speed are performed only after a fixed delay (after power-up and after a previous speed change) 981 if (G_current_status == 1) { 982 983 if ((long)(current_time - time_G0) >= delta_G0) { 984 985 if ((long)(current_time - time_G) >= delta_G) { 986 987 new_speed_evaluation(); 988 speed_change(); 989 } 990 } 991 } 992 993 // a change has been detected on the W1 heat command status 994 if (W1_new_status != W1_current_status && (long)(current_time - time_H0) >= delta_H) { 995 activate_W1(); 996 } 997 998 999 1000 // a change has been detected on the W2 heat command status 1001 if (W2_new_status != W2_current_status && (long)(current_time - time_H0) >= delta_H) { 1002 activate_W2(); 1003 } 1004 1005 1006 // delay validation before activating the second heat strip of W1 1007 if (W1_current_status == 1 && W1_new_status == 1) { 1008 if ((long)(current_time - time_W1) / 1000.0 >= delta_W1_level_1 && W1_heating_state == 1 && (long)(current_time - time_H0) >= delta_H) { 1009 activate_W1(); 1010 } 1011 } 1012 1013 1014 // delay validation before activating the second heat strip of W2 1015 if (W2_current_status == 1 && W2_new_status == 1) { 1016 if ((long)(current_time - time_W2) / 1000.0 >= delta_W2_level_1 && W2_heating_state == 1 && (long)(current_time - time_H0) >= delta_H) { 1017 activate_W2(); 1018 } 1019 1020 } 1021 1022 // a change has been detected on the W3 heat command status (heat pump) 1023 if (W3_new_status != W3_current_status) { 1024 W3_current_status = W3_new_status; 1025 } 1026 1027 1028 1029 // current sense value update 1030 current_update(); 1031 1032 1033 // error management PRELIMINARY 1034 validation_current_vs_status(); 1035 1036 // system status update PRELIMINARY 1037 system_status_update(); 1038 1039 1040 1041 // Verification whether a USB connection is present 1042 1043 if (Serial && USB_connection_status == 0) { 1044 USB_connection_status = 1; 1045 } 1046 1047 if (!Serial && USB_connection_status == 1) { 1048 USB_connection_status = 0; 1049 } 1050 1051 1052 // Delay validation and communication with the PC if the USB connection is active 1053 if ((long)(current_time - time_USB) >= USB_comm_period && USB_connection_status == 1) { 1054 1055 USB_status_verbose(); 1056 } 1057 1058 1059 1060 1061 // fixed latency for perfect synchonization with the 60 Hz electrical AC for precise current sense evaluation 1062 delayMicroseconds(fixed_latency_new); 1063 1064} 1065
HVAC Ctrl 1.0 by LD design (revision 2.5)
arduino
You need a leonardo board and my shield for it to actually do something
1// HVAC Ctrl 1.0, by LD design 2// revision 2.5, 2019-02-10 3 4// 5 Copyright 2018, Louis Desbiens, All rights reserved. 6 7 8#include <avr/pgmspace.h> 9 10 11 12 13// 14// 15// 16// 17// 18 beginning of global variables and constant declarations 19// 20// 21// 22// 23 24 25 26 27 28 29// 30 digital addresses 31 32// outputs 33 34const byte LED_ctrl = 13; // LED 35 control pin address 36const byte H1_ctrl = 12; // Heat strip #1, relay pin 37 address 38const byte H2_ctrl = 11; // Heat strip #2, relay pin address 39const 40 byte H3_ctrl = 10; // Heat strip #3, relay pin address 41const byte H4_ctrl 42 = 9; // Heat strip #4, relay pin address 43const byte BLO_ctrl = 8; // 44 Blower low speed, relay pin address 45const byte BMED_ctrl = 7; // Blower 46 medium speed, relay pin address 47const byte BHI_ctrl = 6; // Blower high 48 speed, relay pin address 49const byte BSSR_ctrl = 5; // Blower circuit, solid-state 50 relay pin address 51 52// inputs 53 54const byte G = 3; // Thermostat 55 G line status address (blower) 56const byte W1 = 2; // Thermostat W1 57 line status address (heat stage 1) 58const byte W2 = 1; // Thermostat 59 W2 line status address (heat stage 2) 60const byte W3 = 0; // Thermostat 61 W3 line status address (heat stage 3), connected to heat pump Y in the current implementation 62 to override the fan speed algorithm 63 64 65// analog input signal, addresses 66 67const 68 byte TH1 = 0; // Thermistor 1 address 69const byte TH2 = 6; // 70 Thermistor 2 address 71const byte CSFAN = 1; // Fan current sense address 72const 73 byte CSH1 = 5; // Heat strip #1 current sense address 74const byte CSH2 75 = 4; // Heat strip #2 current sense address 76const byte CSH3 = 3; // 77 Heat strip #3 current sense address 78const byte CSH4 = 2; // Heat strip 79 #4 current sense address 80 81 82// constant values 83 84const byte nb_of_heating_elements 85 = 4; // nb of heating elements 86const byte CS_vector_size 87 = 144; // current sense vector size 88const int 89 delta_H = 1000; // minimal delay (ms) between 90 two subsequent activation / dactivation of heat strip relays 91const int delta_G0 92 = 5000; // minimal delay (ms), after a blower 93 power-up at the lowest speed, before engaging the speed adjustment algorithm 94const 95 int delta_G = 1000; // minimal delay (ms), 96 between two subsequent blower speed change 97const int delta_W1_level_1 = 5; // 98 minimal delay (s) before engaging the second heat strip on a W1 heat request, (2 99 x 5 kW capacity) 100const int delta_W2_level_1 = 5; // 101 minimal delay (s) before engaging the second heat strip on a W2 heat request, (2 102 x 5 kW capacity) 103const int delai_SSR = 10; // 104 minimal delay (ms) before adjusting the blower speed selection relays after opening 105 the circuit with the SSR relay 106const int delai_relay = 15; // 107 minimal delay (ms) after adjustment the blower speed selection relays before closing 108 the circuit with the SSR relay 109const int delta_T_LO_up = 1000; // 110 minimum temp for going from LO to MED in 1/100 of C (hysteresis) 111const int delta_T_MED_up 112 = 1500; // minimum temp for going from MED to HI 113 in 1/100 of C (hysteresis) 114const int delta_T_HI_up = 2000; // 115 minimum temp for going from HI to VHI in 1/100 of C (hysteresis) 116const int delta_T_MED_down 117 = 900; // minimum temp for going from MED to LO in 118 1/100 of C (hysteresis) 119const int delta_T_HI_down = 1400; // 120 minimum temp for going from HI to MED in 1/100 of C (hysteresis) 121const int delta_T_VHI_down 122 = 1900; // minimum temp for going from VHIGH to HI 123 in 1/100 of C (hysteresis) 124const int H_current_conversion_1 = 35; // 125 current sense conversion constant (30A model, heat strip) 126const int B_current_conversion_1 127 = 210; // current sense conversion constant (5A model, 128 blower) 129const int HB_current_conversion_2 = 10000; // current 130 sense conversion constant 131const byte nb_pts_period = 4; // 132 nb of points per 60Hz cylce for the current sense evaluation 133const int current_FAN_min[] 134 = {0, 1300, 1400, 1600, 1900}; // blower current sense minimal threshold (mA) 135 for OFF, LO, MED, HIGH, VHIGH states (PRELIMINARY) 136const int current_FAN_max[] 137 = {500, 2200, 2400, 2700, 3200}; // blower current sense maximal threshold (mA) 138 for OFF, LO, MED, HIGH, VHIGH states (PRELIMINARY) 139const int current_H_min[] 140 = {0, 15000}; // heat strip current sense minimal threshold 141 (mA) for OFF, ON states (PRELIMINARY) 142const int current_H_max[] = {1000, 25000}; 143 // heat strip current sense maximal threshold (mA) for OFF, 144 ON states (PRELIMINARY) 145const int USB_comm_period = 2000; // 146 periodic delay (ms) between checks whether a USB connection is present 147 148 149// 150 constants stored in the flash (instead of SRAM) 151 152const PROGMEM int16_t thermistor_conversion[] 153 = {32767, 32767, 29765, 26554, 24485, 22984, 21820, 20876, 20087, 19411, 18822, 154 18301, 17836, 17415, 17032, 16681, 16358, 16058, 15779, 15518, 15273, 15042, 14824, 155 14618, 14422, 14235, 14058, 13888, 13726, 13570, 13421, 13277, 13139, 13006, 12877, 156 12753, 12633, 12517, 12404, 12295, 12189, 12086, 11987, 11889, 11795, 11703, 11613, 157 11525, 11440, 11357, 11275, 11196, 11118, 11042, 10967, 10895, 10823, 10753, 10685, 158 10618, 10552, 10487, 10424, 10362, 10300, 10240, 10181, 10123, 10066, 10010, 9955, 159 9901, 9847, 9795, 9743, 9692, 9642, 9592, 9543, 9495, 9448, 9401, 9355, 9309, 9265, 160 9220, 9177, 9133, 9091, 9049, 9007, 8966, 8926, 8885, 8846, 8807, 8768, 8730, 8692, 161 8655, 8618, 8581, 8545, 8509, 8474, 8439, 8404, 8370, 8336, 8302, 8269, 8236, 8203, 162 8171, 8139, 8107, 8076, 8044, 8014, 7983, 7953, 7923, 7893, 7863, 7834, 7805, 7776, 163 7748, 7720, 7691, 7664, 7636, 7609, 7582, 7555, 7528, 7501, 7475, 7449, 7423, 7397, 164 7372, 7346, 7321, 7296, 7272, 7247, 7223, 7198, 7174, 7150, 7126, 7103, 7079, 7056, 165 7033, 7010, 6987, 6965, 6942, 6920, 6897, 6875, 6853, 6832, 6810, 6788, 6767, 6746, 166 6724, 6703, 6682, 6662, 6641, 6620, 6600, 6580, 6560, 6539, 6519, 6500, 6480, 6460, 167 6441, 6421, 6402, 6383, 6364, 6345, 6326, 6307, 6288, 6269, 6251, 6232, 6214, 6196, 168 6178, 6160, 6142, 6124, 6106, 6088, 6071, 6053, 6036, 6018, 6001, 5984, 5966, 5949, 169 5932, 5915, 5899, 5882, 5865, 5849, 5832, 5815, 5799, 5783, 5766, 5750, 5734, 5718, 170 5702, 5686, 5670, 5655, 5639, 5623, 5608, 5592, 5577, 5561, 5546, 5530, 5515, 5500, 171 5485, 5470, 5455, 5440, 5425, 5410, 5395, 5381, 5366, 5351, 5337, 5322, 5308, 5293, 172 5279, 5265, 5250, 5236, 5222, 5208, 5194, 5180, 5166, 5152, 5138, 5124, 5111, 5097, 173 5083, 5069, 5056, 5042, 5029, 5015, 5002, 4989, 4975, 4962, 4949, 4935, 4922, 4909, 174 4896, 4883, 4870, 4857, 4844, 4831, 4818, 4805, 4793, 4780, 4767, 4754, 4742, 4729, 175 4717, 4704, 4692, 4679, 4667, 4654, 4642, 4630, 4617, 4605, 4593, 4581, 4568, 4556, 176 4544, 4532, 4520, 4508, 4496, 4484, 4472, 4460, 4448, 4437, 4425, 4413, 4401, 4389, 177 4378, 4366, 4354, 4343, 4331, 4320, 4308, 4297, 4285, 4274, 4262, 4251, 4240, 4228, 178 4217, 4206, 4194, 4183, 4172, 4161, 4150, 4138, 4127, 4116, 4105, 4094, 4083, 4072, 179 4061, 4050, 4039, 4028, 4017, 4006, 3996, 3985, 3974, 3963, 3952, 3942, 3931, 3920, 180 3910, 3899, 3888, 3878, 3867, 3857, 3846, 3835, 3825, 3814, 3804, 3793, 3783, 3773, 181 3762, 3752, 3741, 3731, 3721, 3710, 3700, 3690, 3680, 3669, 3659, 3649, 3639, 3628, 182 3618, 3608, 3598, 3588, 3578, 3568, 3558, 3548, 3538, 3527, 3517, 3507, 3498, 3488, 183 3478, 3468, 3458, 3448, 3438, 3428, 3418, 3408, 3399, 3389, 3379, 3369, 3359, 3350, 184 3340, 3330, 3320, 3311, 3301, 3291, 3282, 3272, 3262, 3253, 3243, 3233, 3224, 3214, 185 3205, 3195, 3186, 3176, 3166, 3157, 3147, 3138, 3128, 3119, 3109, 3100, 3091, 3081, 186 3072, 3062, 3053, 3044, 3034, 3025, 3015, 3006, 2997, 2987, 2978, 2969, 2959, 2950, 187 2941, 2932, 2922, 2913, 2904, 2895, 2885, 2876, 2867, 2858, 2849, 2839, 2830, 2821, 188 2812, 2803, 2793, 2784, 2775, 2766, 2757, 2748, 2739, 2730, 2721, 2712, 2702, 2693, 189 2684, 2675, 2666, 2657, 2648, 2639, 2630, 2621, 2612, 2603, 2594, 2585, 2576, 2567, 190 2558, 2549, 2540, 2531, 2522, 2513, 2504, 2496, 2487, 2478, 2469, 2460, 2451, 2442, 191 2433, 2424, 2415, 2407, 2398, 2389, 2380, 2371, 2362, 2353, 2344, 2336, 2327, 2318, 192 2309, 2300, 2291, 2283, 2274, 2265, 2256, 2247, 2239, 2230, 2221, 2212, 2203, 2195, 193 2186, 2177, 2168, 2159, 2151, 2142, 2133, 2124, 2116, 2107, 2098, 2089, 2081, 2072, 194 2063, 2054, 2046, 2037, 2028, 2019, 2011, 2002, 1993, 1984, 1976, 1967, 1958, 1949, 195 1941, 1932, 1923, 1914, 1906, 1897, 1888, 1880, 1871, 1862, 1853, 1845, 1836, 1827, 196 1818, 1810, 1801, 1792, 1784, 1775, 1766, 1757, 1749, 1740, 1731, 1722, 1714, 1705, 197 1696, 1687, 1679, 1670, 1661, 1653, 1644, 1635, 1626, 1618, 1609, 1600, 1591, 1583, 198 1574, 1565, 1556, 1548, 1539, 1530, 1521, 1512, 1504, 1495, 1486, 1477, 1469, 1460, 199 1451, 1442, 1433, 1425, 1416, 1407, 1398, 1389, 1381, 1372, 1363, 1354, 1345, 1336, 200 1328, 1319, 1310, 1301, 1292, 1283, 1274, 1266, 1257, 1248, 1239, 1230, 1221, 1212, 201 1203, 1194, 1185, 1176, 1168, 1159, 1150, 1141, 1132, 1123, 1114, 1105, 1096, 1087, 202 1078, 1069, 1060, 1051, 1042, 1033, 1024, 1015, 1006, 997, 988, 979, 969, 960, 951, 203 942, 933, 924, 915, 906, 897, 887, 878, 869, 860, 851, 842, 832, 823, 814, 805, 204 795, 786, 777, 768, 758, 749, 740, 730, 721, 712, 702, 693, 684, 674, 665, 655, 205 646, 637, 627, 618, 608, 599, 589, 580, 570, 561, 551, 542, 532, 523, 513, 503, 206 494, 484, 475, 465, 455, 445, 436, 426, 416, 407, 397, 387, 377, 367, 358, 348, 207 338, 328, 318, 308, 298, 288, 278, 268, 259, 249, 238, 228, 218, 208, 198, 188, 208 178, 168, 158, 147, 137, 127, 117, 106, 96, 86, 76, 65, 55, 44, 34, 24, 13, 3, -8, 209 -18, -29, -40, -50, -61, -71, -82, -93, -104, -114, -125, -136, -147, -158, -168, 210 -179, -190, -201, -212, -223, -234, -245, -257, -268, -279, -290, -301, -312, -324, 211 -335, -346, -358, -369, -381, -392, -404, -415, -427, -438, -450, -462, -473, -485, 212 -497, -509, -521, -532, -544, -556, -568, -580, -592, -605, -617, -629, -641, -654, 213 -666, -678, -691, -703, -716, -728, -741, -753, -766, -779, -792, -804, -817, -830, 214 -843, -856, -869, -883, -896, -909, -922, -936, -949, -963, -976, -990, -1003, -1017, 215 -1031, -1045, -1058, -1072, -1086, -1100, -1115, -1129, -1143, -1157, -1172, -1186, 216 -1201, -1216, -1230, -1245, -1260, -1275, -1290, -1305, -1320, -1335, -1351, -1366, 217 -1381, -1397, -1413, -1428, -1444, -1460, -1476, -1492, -1509, -1525, -1541, -1558, 218 -1575, -1591, -1608, -1625, -1642, -1659, -1677, -1694, -1711, -1729, -1747, -1765, 219 -1783, -1801, -1819, -1838, -1856, -1875, -1894, -1913, -1932, -1951, -1971, -1990, 220 -2010, -2030, -2050, -2070, -2091, -2111, -2132, -2153, -2174, -2196, -2217, -2239, 221 -2261, -2283, -2306, -2328, -2351, -2375, -2398, -2422, -2446, -2470, -2494, -2519, 222 -2544, -2569, -2595, -2621, -2647, -2674, -2701, -2728, -2756, -2784, -2812, -2841, 223 -2870, -2900, -2930, -2961, -2992, -3024, -3056, -3089, -3122, -3156, -3190, -3225, 224 -3261, -3297, -3334, -3372, -3411, -3451, -3491, -3533, -3575, -3618, -3663, -3708, 225 -3755, -3803, -3853, -3904, -3956, -4010, -4066, -4124, -4184, -4247, -4311, -4379, 226 -4449, -4523, -4600, -4682, -4768, -4859, -4956, -5059, -5171, -5291, -5423, -5568, 227 -5731, -5915, -6128, -6384, -6704, -7138, -7839, -32768}; // use this form 228const 229 PROGMEM uint16_t current_sensing_conversion[] = {64532, 64280, 64029, 63778, 63527, 230 63277, 63027, 62778, 62530, 62281, 62034, 61787, 61540, 61294, 61048, 60803, 60558, 231 60314, 60070, 59827, 59585, 59342, 59101, 58859, 58619, 58378, 58139, 57899, 57661, 232 57422, 57185, 56947, 56711, 56474, 56238, 56003, 55768, 55534, 55300, 55067, 54834, 233 54602, 54370, 54138, 53908, 53677, 53447, 53218, 52989, 52761, 52533, 52305, 52078, 234 51852, 51626, 51401, 51176, 50951, 50727, 50504, 50281, 50058, 49836, 49615, 49394, 235 49173, 48953, 48734, 48515, 48296, 48078, 47861, 47644, 47427, 47211, 46995, 46780, 236 46566, 46352, 46138, 45925, 45712, 45500, 45289, 45077, 44867, 44657, 44447, 44238, 237 44029, 43821, 43613, 43406, 43199, 42993, 42787, 42582, 42378, 42173, 41970, 41766, 238 41564, 41361, 41160, 40958, 40758, 40557, 40357, 40158, 39959, 39761, 39563, 39366, 239 39169, 38973, 38777, 38582, 38387, 38192, 37998, 37805, 37612, 37420, 37228, 37036, 240 36846, 36655, 36465, 36276, 36087, 35898, 35710, 35523, 35336, 35150, 34964, 34778, 241 34593, 34409, 34225, 34041, 33858, 33676, 33494, 33312, 33131, 32950, 32770, 32591, 242 32412, 32233, 32055, 31877, 31700, 31524, 31348, 31172, 30997, 30822, 30648, 30475, 243 30301, 30129, 29957, 29785, 29614, 29443, 29273, 29103, 28934, 28765, 28597, 28429, 244 28262, 28095, 27929, 27763, 27598, 27433, 27269, 27105, 26942, 26779, 26617, 26455, 245 26294, 26133, 25973, 25813, 25653, 25495, 25336, 25178, 25021, 24864, 24708, 24552, 246 24397, 24242, 24087, 23933, 23780, 23627, 23475, 23323, 23171, 23020, 22870, 22720, 247 22570, 22421, 22273, 22125, 21977, 21830, 21684, 21538, 21392, 21247, 21103, 20959, 248 20815, 20672, 20529, 20387, 20246, 20105, 19964, 19824, 19684, 19545, 19407, 19269, 249 19131, 18994, 18857, 18721, 18585, 18450, 18316, 18181, 18048, 17914, 17782, 17650, 250 17518, 17387, 17256, 17126, 16996, 16867, 16738, 16610, 16482, 16355, 16228, 16102, 251 15976, 15850, 15726, 15601, 15478, 15354, 15231, 15109, 14987, 14866, 14745, 14625, 252 14505, 14385, 14266, 14148, 14030, 13913, 13796, 13679, 13564, 13448, 13333, 13219, 253 13105, 12991, 12878, 12766, 12654, 12542, 12431, 12321, 12211, 12101, 11992, 11884, 254 11776, 11668, 11561, 11455, 11349, 11243, 11138, 11033, 10929, 10826, 10723, 10620, 255 10518, 10416, 10315, 10214, 10114, 10015, 9916, 9817, 9719, 9621, 9524, 9427, 9331, 256 9235, 9140, 9045, 8951, 8857, 8764, 8671, 8579, 8487, 8396, 8305, 8215, 8125, 8036, 257 7947, 7859, 7771, 7684, 7597, 7511, 7425, 7339, 7255, 7170, 7086, 7003, 6920, 6838, 258 6756, 6674, 6594, 6513, 6433, 6354, 6275, 6196, 6119, 6041, 5964, 5888, 5812, 5736, 259 5661, 5587, 5513, 5439, 5366, 5294, 5222, 5150, 5079, 5009, 4939, 4869, 4800, 4731, 260 4663, 4596, 4529, 4462, 4396, 4330, 4265, 4201, 4136, 4073, 4010, 3947, 3885, 3823, 261 3762, 3701, 3641, 3581, 3522, 3464, 3405, 3348, 3290, 3234, 3177, 3122, 3066, 3012, 262 2957, 2904, 2850, 2798, 2745, 2694, 2642, 2591, 2541, 2491, 2442, 2393, 2345, 2297, 263 2250, 2203, 2156, 2110, 2065, 2020, 1976, 1932, 1888, 1846, 1803, 1761, 1720, 1679, 264 1638, 1598, 1559, 1520, 1481, 1443, 1406, 1369, 1332, 1296, 1261, 1226, 1191, 1157, 265 1124, 1091, 1058, 1026, 995, 963, 933, 903, 873, 844, 815, 787, 760, 733, 706, 680, 266 654, 629, 604, 580, 557, 533, 511, 488, 467, 446, 425, 405, 385, 366, 347, 329, 267 311, 294, 277, 261, 245, 229, 215, 200, 187, 173, 160, 148, 136, 125, 114, 104, 268 94, 84, 76, 67, 59, 52, 45, 39, 33, 27, 22, 18, 14, 10, 7, 5, 3, 2, 1, 0, 0, 1, 269 2, 3, 5, 7, 10, 14, 18, 22, 27, 33, 39, 45, 52, 59, 67, 76, 84, 94, 104, 114, 125, 270 136, 148, 160, 173, 187, 200, 215, 229, 245, 261, 277, 294, 311, 329, 347, 366, 271 385, 405, 425, 446, 467, 488, 511, 533, 557, 580, 604, 629, 654, 680, 706, 733, 272 760, 787, 815, 844, 873, 903, 933, 963, 995, 1026, 1058, 1091, 1124, 1157, 1191, 273 1226, 1261, 1296, 1332, 1369, 1406, 1443, 1481, 1520, 1559, 1598, 1638, 1679, 1720, 274 1761, 1803, 1846, 1888, 1932, 1976, 2020, 2065, 2110, 2156, 2203, 2250, 2297, 2345, 275 2393, 2442, 2491, 2541, 2591, 2642, 2694, 2745, 2798, 2850, 2904, 2957, 3012, 3066, 276 3122, 3177, 3234, 3290, 3348, 3405, 3464, 3522, 3581, 3641, 3701, 3762, 3823, 3885, 277 3947, 4010, 4073, 4136, 4201, 4265, 4330, 4396, 4462, 4529, 4596, 4663, 4731, 4800, 278 4869, 4939, 5009, 5079, 5150, 5222, 5294, 5366, 5439, 5513, 5587, 5661, 5736, 5812, 279 5888, 5964, 6041, 6119, 6196, 6275, 6354, 6433, 6513, 6594, 6674, 6756, 6838, 6920, 280 7003, 7086, 7170, 7255, 7339, 7425, 7511, 7597, 7684, 7771, 7859, 7947, 8036, 8125, 281 8215, 8305, 8396, 8487, 8579, 8671, 8764, 8857, 8951, 9045, 9140, 9235, 9331, 9427, 282 9524, 9621, 9719, 9817, 9916, 10015, 10114, 10214, 10315, 10416, 10518, 10620, 10723, 283 10826, 10929, 11033, 11138, 11243, 11349, 11455, 11561, 11668, 11776, 11884, 11992, 284 12101, 12211, 12321, 12431, 12542, 12654, 12766, 12878, 12991, 13105, 13219, 13333, 285 13448, 13564, 13679, 13796, 13913, 14030, 14148, 14266, 14385, 14505, 14625, 14745, 286 14866, 14987, 15109, 15231, 15354, 15478, 15601, 15726, 15850, 15976, 16102, 16228, 287 16355, 16482, 16610, 16738, 16867, 16996, 17126, 17256, 17387, 17518, 17650, 17782, 288 17914, 18048, 18181, 18316, 18450, 18585, 18721, 18857, 18994, 19131, 19269, 19407, 289 19545, 19684, 19824, 19964, 20105, 20246, 20387, 20529, 20672, 20815, 20959, 21103, 290 21247, 21392, 21538, 21684, 21830, 21977, 22125, 22273, 22421, 22570, 22720, 22870, 291 23020, 23171, 23323, 23475, 23627, 23780, 23933, 24087, 24242, 24397, 24552, 24708, 292 24864, 25021, 25178, 25336, 25495, 25653, 25813, 25973, 26133, 26294, 26455, 26617, 293 26779, 26942, 27105, 27269, 27433, 27598, 27763, 27929, 28095, 28262, 28429, 28597, 294 28765, 28934, 29103, 29273, 29443, 29614, 29785, 29957, 30129, 30301, 30475, 30648, 295 30822, 30997, 31172, 31348, 31524, 31700, 31877, 32055, 32233, 32412, 32591, 32770, 296 32950, 33131, 33312, 33494, 33676, 33858, 34041, 34225, 34409, 34593, 34778, 34964, 297 35150, 35336, 35523, 35710, 35898, 36087, 36276, 36465, 36655, 36846, 37036, 37228, 298 37420, 37612, 37805, 37998, 38192, 38387, 38582, 38777, 38973, 39169, 39366, 39563, 299 39761, 39959, 40158, 40357, 40557, 40758, 40958, 41160, 41361, 41564, 41766, 41970, 300 42173, 42378, 42582, 42787, 42993, 43199, 43406, 43613, 43821, 44029, 44238, 44447, 301 44657, 44867, 45077, 45289, 45500, 45712, 45925, 46138, 46352, 46566, 46780, 46995, 302 47211, 47427, 47644, 47861, 48078, 48296, 48515, 48734, 48953, 49173, 49394, 49615, 303 49836, 50058, 50281, 50504, 50727, 50951, 51176, 51401, 51626, 51852, 52078, 52305, 304 52533, 52761, 52989, 53218, 53447, 53677, 53908, 54138, 54370, 54602, 54834, 55067, 305 55300, 55534, 55768, 56003, 56238, 56474, 56711, 56947, 57185, 57422, 57661, 57899, 306 58139, 58378, 58619, 58859, 59101, 59342, 59585, 59827, 60070, 60314, 60558, 60803, 307 61048, 61294, 61540, 61787, 62034, 62281, 62530, 62778, 63027, 63277, 63527, 63778, 308 64029, 64280, 64532}; 309const PROGMEM byte LED1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 310 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}; 311const PROGMEM byte LED2[] 312 = {0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 313 2}; 314const PROGMEM byte LED3[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 315 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2}; 316 317// thermistor conversion : the "analogread" 318 value is used as an index, what is stored in the flash are the correspoding 1024 319 temperatures (in 1/100 C) 320// current sense conversion, the instanteous current 321 (mA) is given by : sqrt(current_sensing_conversion)/H_current_conversion_1*HB_current_conversion_2 322 for the heat strips and sqrt(current_sensing_conversion)/B_current_conversion_1*HB_current_conversion_2 323 for the blower 324 325 326 327// working variables 328 329byte current_speed = 0; 330 // 0 min speed, 1,2,3 max speed 331 (blower, current state) 332byte new_speed = 0; // 333 0 min speed, 1,2,3 max speed (blower, new state) 334byte G_current_status = 0; // 335 current status of the G line (0=OFF, 1=ON) 336byte G_new_status = 0; // 337 new status of the G line (0=OFF, 1=ON) 338byte W1_current_status = 0; // 339 current status of the W1 line (0=OFF, 1=ON) 340byte W1_new_status = 0; // 341 new status of the W1 line (0=OFF, 1=ON) 342byte W2_current_status = 0; // 343 current status of the W2 line (0=OFF, 1=ON) 344byte W2_new_status = 0; // 345 new status of the W2 line (0=OFF, 1=ON) 346byte W3_current_status = 0; // 347 current status of the W3 line (0=OFF, 1=ON) 348byte W3_new_status = 0; // 349 new status of the W3 line (0=OFF, 1=ON) 350int TH1_value = 0; // 351 Temperature value (1/100 C), thermistor 1 352int TH2_value = 0; // 353 Temperature value (1/100 C), thermistor 2 354byte active_elements_W1_W2[5] = {H4_ctrl, 355 H1_ctrl, H2_ctrl, H3_ctrl, H4_ctrl}; // indexes 0 and 1 correspond to W1, indexes 356 2 and 3 to W2, the addresses of the heat strips are cycled through in the vector 357 each time a new activation of W1 occcurs 358byte W1_heating_state = 0; // 359 heating states associated with W1 (0: no heat strips activates, 1: first heat strip 360 is activated, 2: both heat strips are activated) 361byte W2_heating_state = 0; // 362 heating states associated with W2 (0: no heat strips activates, 1: first heat strip 363 is activated, 2: both heat strips are activated) 364byte speed_change_stage = 3; 365 // blower speed change states (0: 366 beginning of speed change sequence, 1: the circuit is open, 2: The speed adjustment 367 has been made, 3: the circuit is closed) 368byte fan_activation_state = 0; // 369 blower fan state sequence for shutdown (=0 fan is ready for first step of startup 370 or shutdown sequence, =1 shutdown sequence intermediate step, after SSR has openend 371 the circuit before fan speed goes back to minimal value, =2 fan is off and speed 372 is at low) 373byte pointer_CS = 0; // 374 current sense consist of measuring multiplie instantaneous current value samples 375 (4 per 60 Hz cycle, 36 consecutives cycles, 144 samples in total representing 600 376 ms) and calculating the RMS value, pointer_CS is the index in the vector current 377long 378 correction_us = 0; // To ensure 379 the current measurement are performed every 4.16 ms, a delay is adjusted each cycle 380 to compensate for the small variations, correction_us is the correction to the fized 381 latenccy in us, reevaluated at each cycle 382byte system_status_LED[] = {0, 0, 0, 383 0, 0, 0, 0, 0}; // LED1 LED2 LED3 color 0 =green 1 = yellow 384 2 = red, FAN status H1 H2 H3 H4 0 = OK(green) 1 = UC(yellow) 2 = OC(red) 385 PRELIMINARY 386byte FAN_status = 0; // 387 FAN_status (0= OFF, 1= LOW, 2= MED, 3= HIGH, 4= VHIGH) to be used as an indicator 388 in the reporting system (USB) and eventually in the LED control PRELIMINARY 389byte 390 HEATER_status = 0; // HEATER_status 391 (0= OFF, 1= W1 1st heat strip, 2= W2 both heat strip, 3= W2 1st heat strip, 4= W2 392 both heat strip) to be used as an indicator in the reporting system (USB) and eventually 393 in the LED control PRELIMINARY 394byte system_status_index = 0; // 395 global value indicating the status in which the system is in, 27 possible states 396 PRELIMINARY 397byte USB_connection_status = 0; // 398 indication whether a USB connection is present or not 399unsigned int H1_current_vector[CS_vector_size]; 400 // current sense vector of 144 samples for heat strip 401 #1 402unsigned int H2_current_vector[CS_vector_size]; // 403 current sense vector of 144 samples for heat strip #2 404unsigned int H3_current_vector[CS_vector_size]; 405 // current sense vector of 144 samples for heat strip 406 #3 407unsigned int H4_current_vector[CS_vector_size]; // 408 current sense vector of 144 samples for heat strip #4 409unsigned int FAN_current_vector[CS_vector_size]; 410 // current sense vector of 144 samples for the blower 411unsigned 412 long H1_CS_sum = 0; // current sense 413 sum for heat strip #1 414unsigned long H2_CS_sum = 0; // 415 current sense sum for heat strip #2 416unsigned long H3_CS_sum = 0; // 417 current sense sum for heat strip #3 418unsigned long H4_CS_sum = 0; // 419 current sense sum for heat strip #4 420unsigned long FAN_CS_sum = 0; // 421 current sense sum for the blower 422unsigned int current_sense_H_vector[nb_of_heating_elements]; 423 // actual current value in mA for the heat strips 424unsigned int 425 current_sense_FAN = 0; // actual current 426 value in mA for the blower 427 428 429 430 431// time measurements 432 433unsigned 434 long time_H0 = 0; // absolute time of the last relay activation 435unsigned 436 long time_W1 = 0; // absolute time of the last W1 activation 437unsigned 438 long time_W2 = 0; // absolute time of the last W2 activation 439unsigned 440 long time_G0 = 0; // absolute time of the last blower activation 441unsigned 442 long time_G = 0; // absolute time of the last speed change 443unsigned 444 long time_SC = 0; // absolute time used for counting during the 445 intermediate steps associated with a speed change 446unsigned long time_AF = 0; 447 // absolute time used for couting during the intermediate steps 448 associated with the activation of the fan 449unsigned long time_USB = 0; // 450 absolute time used for the delays in the USB connection presence check 451unsigned 452 long current_time = 0; // absolute time to verify, at each cycle whether 453 the time overflow has occured (~ every ~ 50 days) 454unsigned long old_current_time 455 = 0; // previous value of the absolute time to verify whether the time overflow 456 has occured 457unsigned long time_old_CS = 0; // absolute time used 458 in current sense algorithm to synchronize the measurements on a 60 Hz cycle (previous 459 value) 460unsigned long time_new_CS = 0; // absolute time used in current 461 sense algorithm to synchronize the measurements on a 60 Hz cycle (new value) 462unsigned 463 int fixed_latency_old = 0; // latency to be waited at each cycle to stay 464 synchronized with the 60 Hz electrical supply (previous value) 465unsigned int fixed_latency_new 466 = 0; // latency to be waited at each cycle to stay synchronized with the 467 60 Hz electrical supply (new value) 468 469 470// 471// 472// 473// 474// end of 475 global variables and constant declarations 476// 477// 478// 479// 480 481 482///////////////////////////////////////////////////////////////////////////// 483// 484 routine for evaluating whether a speed change of the blower is required 485///////////////////////////////////////////////////////////////////////////// 486 487void 488 new_speed_evaluation() { 489 490 491 // The verification is performed only if we're 492 are not currently in the process of changing the speed 493 if (speed_change_stage 494 == 3) { 495 496 497 // If the heat pump is active (W3) we force the blower to 498 high speed for maximum efficiency 499 if (W3_current_status == 1) { 500 new_speed 501 = 3; 502 } 503 else { 504 505 506 507 // validation of the current speed 508 and check whether the temperature difference is over or under the thresholds we 509 have defined 510 switch (current_speed) { 511 case 0: // LO speed 512 513 if (abs(TH1_value - TH2_value) >= delta_T_LO_up) { 514 new_speed 515 = 1; 516 } 517 break; 518 519 case 1: // MED speed 520 521 if (abs(TH1_value - TH2_value) >= delta_T_MED_up) { 522 new_speed 523 = 2; 524 } 525 if (abs(TH1_value - TH2_value) < delta_T_MED_down) 526 { 527 new_speed = 0; 528 } 529 break; 530 531 case 532 2: // HI speed 533 if (abs(TH1_value - TH2_value) >= delta_T_HI_up) { 534 535 new_speed = 3; 536 } 537 if (abs(TH1_value - TH2_value) 538 < delta_T_HI_down) { 539 new_speed = 1; 540 } 541 break; 542 543 544 case 3: // VHI speed 545 if (abs(TH1_value - TH2_value) < delta_T_VHI_down) 546 { 547 new_speed = 2; 548 } 549 break; 550 } 551 552 553 } 554 } 555} 556 557///////////////////////////////////////////////////////////////////////////// 558 559 560 561 562 563 564///////////////////////////////////////////////////////////////////////////// 565// 566 routine for changing the fan speed 567///////////////////////////////////////////////////////////////////////////// 568 569void 570 speed_change() { 571 572 if (new_speed != current_speed) { 573 574 // if the 575 speed_change_stage is equal to 3, its a new speed change sequence (and not an ongoing 576 sequence), therefore we start at the beginning (speed_stage_stage=0) 577 if (speed_change_stage 578 == 3) { 579 speed_change_stage = 0; 580 } 581 582 } 583 584 585 586 switch 587 (speed_change_stage) { 588 589 // The electrical circuit is openend with the 590 SSR relay 591 case 0: 592 593 digitalWrite(BSSR_ctrl, LOW); 594 speed_change_stage 595 = 1; 596 time_SC = millis(); 597 598 break; 599 600 601 // if the delay 602 after opening the circuit is over the 10 ms minimum, we select the new speed 603 604 case 1: 605 606 if ((long)(current_time - time_SC) >= delai_SSR) { 607 608 609 switch (new_speed) { 610 case 0: // LOWEST SPEED 611 612 digitalWrite(BHI_ctrl, 613 LOW); 614 digitalWrite(BMED_ctrl, LOW); 615 digitalWrite(BLO_ctrl, 616 LOW); 617 618 break; 619 case 1: // SECOND LOWEST 620 digitalWrite(BHI_ctrl, 621 LOW); 622 digitalWrite(BMED_ctrl, LOW); 623 digitalWrite(BLO_ctrl, 624 HIGH); 625 break; 626 case 2: // SECOND HIGHEST 627 digitalWrite(BHI_ctrl, 628 LOW); 629 digitalWrite(BMED_ctrl, HIGH); 630 digitalWrite(BLO_ctrl, 631 HIGH); 632 break; 633 case 3: // HIGHEST 634 digitalWrite(BHI_ctrl, 635 HIGH); 636 digitalWrite(BMED_ctrl, HIGH); 637 digitalWrite(BLO_ctrl, 638 HIGH); 639 break; 640 } 641 speed_change_stage = 2; 642 643 time_SC = millis(); 644 645 646 } 647 break; 648 649 650 651 // 652 if the delay after selecting the new speed is over the 15 ms minimum (mechanical 653 relay boucing), we close the circuit again with the SSR 654 case 2: 655 656 if 657 ((long)(current_time - time_SC) >= delai_relay) { 658 digitalWrite(BSSR_ctrl, 659 HIGH); 660 current_speed = new_speed; 661 time_G = millis(); 662 speed_change_stage 663 = 3; 664 break; 665 666 667 } 668 } 669} 670 671///////////////////////////////////////////////////////////////////////////// 672 673 674 675 676 677 678///////////////////////////////////////////////////////////////////////////// 679// 680 temperature reading routine 681///////////////////////////////////////////////////////////////////////////// 682 683int 684 read_temp(int pin_adress) { 685 686 687 int TH_raw_cnt; 688 int read_temp_value; 689 690 691 TH_raw_cnt = analogRead(pin_adress); 692 693 read_temp_value = pgm_read_word(&thermistor_conversion[TH_raw_cnt]); 694 695 696 return read_temp_value; 697} 698 699 700 701 702 703 704 705 706 707 708 709 710///////////////////////////////////////////////////////////////////////////// 711 712 713 714 715 716 717///////////////////////////////////////////////////////////////////////////// 718// 719 routine for the activation of the relays associated withe the W1 heat command 720///////////////////////////////////////////////////////////////////////////// 721 722void 723 activate_W1() { 724 725 switch (W1_new_status) { 726 727 // W1 heat strips deactivation 728 729 case 0: 730 731 // Validation of which heating state we're in (state 0 732 should not be an option) 733 switch (W1_heating_state) { 734 735 // 736 deactivation of heat strip #1 associated with W1 737 case 1: 738 digitalWrite(active_elements_W1_W2[0], 739 W1_new_status); 740 W1_current_status = W1_new_status; 741 W1_heating_state 742 = 0; 743 break; 744 745 // deactivation of heat strip #2 associated 746 with W1 747 case 2: 748 digitalWrite(active_elements_W1_W2[1], W1_new_status); 749 750 W1_heating_state = 1; 751 break; 752 } 753 break; 754 755 756 757 // W1 heat strips activation 758 case 1: 759 760 // Validation of which 761 heating state we're in (state 2 should not be an option) 762 switch (W1_heating_state) 763 { 764 765 // activation of heat strip #1 associated with W1 766 case 767 0: 768 769 770 // rotation of the heat strips associated with W1 and W2 771 (for even wear) 772 // before performing the rotation, we validate that 773 W2 is not active, it should not as thermostat usually don't activate W2 without 774 activating W1 775 if (W2_current_status == 0) { 776 777 778 int 779 i; 780 for (i = 0; i < nb_of_heating_elements; i++) { 781 782 active_elements_W1_W2[i] 783 = active_elements_W1_W2[i + 1]; 784 } 785 786 active_elements_W1_W2[nb_of_heating_elements] 787 = active_elements_W1_W2[0]; 788 789 } 790 791 792 // activation 793 of heat strip #1 794 digitalWrite(active_elements_W1_W2[0], W1_new_status); 795 796 time_W1 = millis(); 797 W1_current_status = W1_new_status; 798 799 W1_heating_state = 1; 800 break; 801 802 // activation 803 of heat strip #2 assocviated with W1 804 case 1: 805 digitalWrite(active_elements_W1_W2[1], 806 W1_new_status); 807 W1_heating_state = 2; 808 break; 809 810 } 811 812 break; 813 814 } 815 816 time_H0 = millis(); 817 818} 819 820 821///////////////////////////////////////////////////////////////////////////// 822 823 824 825 826 827 828///////////////////////////////////////////////////////////////////////////// 829// 830 routine for the activation of the relays associated withe the W2 heat command 831///////////////////////////////////////////////////////////////////////////// 832 833void 834 activate_W2() { 835 836 switch (W2_new_status) { 837 838 // W2 heat strips deactivation 839 840 case 0: 841 842 // Validation of which heating state we're in (state 0 843 should not be an option) 844 switch (W2_heating_state) { 845 846 // 847 deactivation of heat strip #1 associated with W2 848 case 1: 849 digitalWrite(active_elements_W1_W2[2], 850 W2_new_status); 851 W2_current_status = W2_new_status; 852 W2_heating_state 853 = 0; 854 break; 855 856 // deactivation of heat strip #2 associated 857 with W2 858 case 2: 859 digitalWrite(active_elements_W1_W2[3], W2_new_status); 860 861 W2_heating_state = 1; 862 break; 863 } 864 break; 865 866 867 868 // W2 heat strips activation 869 case 1: 870 871 // Validation of which 872 heating state we're in (state 2 should not be an option) 873 switch (W2_heating_state) 874 { 875 876 // activation of heat strip #1 associated with W2 877 case 878 0: 879 digitalWrite(active_elements_W1_W2[2], W2_new_status); 880 time_W2 881 = millis(); 882 W2_current_status = W2_new_status; // on met jour le status 883 W2 884 W2_heating_state = 1; 885 break; 886 887 // activation 888 of heat strip #2 associated with W2 889 case 1: 890 digitalWrite(active_elements_W1_W2[3], 891 W2_new_status); 892 W2_heating_state = 2; 893 break; 894 895 } 896 897 break; 898 899 } 900 time_H0 = millis(); 901 902} 903 904 905 906///////////////////////////////////////////////////////////////////////////// 907 908 909 910 911 912 913///////////////////////////////////////////////////////////////////////////// 914// 915 routine for the activation of the blower 916///////////////////////////////////////////////////////////////////////////// 917 918 919void 920 activate_G() { 921 922 923 // check whether the fan was in a steady state (OFF 924 or ON) 925 // if the answer is positive, put the fan state at value for a new sequence 926 (ON or OFF) 927 928 if (fan_activation_state == 2) { 929 fan_activation_state 930 = 0; 931 932 } 933 934 935 936 switch (G_new_status) { 937 938 939 // blower 940 deactivation, by default we set the speed to the lowest setting for the next power-up 941 942 case 0: 943 944 switch (fan_activation_state) { 945 946 // The electrical 947 circuit is openend with the SSR relay 948 case 0: 949 digitalWrite(BSSR_ctrl, 950 LOW); 951 fan_activation_state = 1; 952 time_AF = millis(); 953 954 break; 955 956 // if the delay after opening the circuit is over 957 the 10 ms minimum, we select the new speed (lowest value for next power-up) 958 959 case 1: 960 961 if ((long)(current_time - time_AF) >= delai_SSR) 962 { 963 964 digitalWrite(BHI_ctrl, LOW); 965 digitalWrite(BMED_ctrl, 966 LOW); 967 digitalWrite(BLO_ctrl, LOW); 968 current_speed = 969 0; 970 new_speed = 0; 971 fan_activation_state = 2; 972 G_current_status 973 = G_new_status; 974 975 } 976 break; 977 } 978 break; 979 980 981 982 // We close the circuit with the SSR for the blower power-up 983 case 1: 984 985 986 digitalWrite(BSSR_ctrl, HIGH); 987 988 time_G0 = millis(); 989 time_G 990 = time_G0; 991 G_current_status = G_new_status; 992 break; 993 } 994 995} 996 997 998///////////////////////////////////////////////////////////////////////////// 999 1000 1001 1002 1003 1004 1005///////////////////////////////////////////////////////////////////////////// 1006// 1007 routine for the evaluation of the current sense values 1008///////////////////////////////////////////////////////////////////////////// 1009 1010 1011void 1012 current_update() { 1013 1014 int CS_raw_cnt; 1015 float temp_FLOAT_var; 1016 1017 1018 1019 // we substract the raw instantaneous current value at the current pointer position 1020 1021 1022 H1_CS_sum = H1_CS_sum - H1_current_vector[pointer_CS]; 1023 H2_CS_sum = H2_CS_sum 1024 - H2_current_vector[pointer_CS]; 1025 H3_CS_sum = H3_CS_sum - H3_current_vector[pointer_CS]; 1026 1027 H4_CS_sum = H4_CS_sum - H4_current_vector[pointer_CS]; 1028 FAN_CS_sum = FAN_CS_sum 1029 - FAN_current_vector[pointer_CS]; 1030 1031 1032 // we update in the raw instanteous 1033 current vectors the value at the current pointer position 1034 1035 CS_raw_cnt = 1036 analogRead(CSH1); 1037 H1_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 1038 1039 1040 CS_raw_cnt = analogRead(CSH2); 1041 H2_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 1042 1043 1044 CS_raw_cnt = analogRead(CSH3); 1045 H3_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 1046 1047 1048 CS_raw_cnt = analogRead(CSH4); 1049 H4_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 1050 1051 1052 CS_raw_cnt = analogRead(CSFAN); 1053 FAN_current_vector[pointer_CS] = pgm_read_word(¤t_sensing_conversion[CS_raw_cnt]); 1054 1055 1056 // we update the raw sum 1057 1058 H1_CS_sum = H1_CS_sum + H1_current_vector[pointer_CS]; 1059 1060 H2_CS_sum = H2_CS_sum + H2_current_vector[pointer_CS]; 1061 H3_CS_sum = H3_CS_sum 1062 + H3_current_vector[pointer_CS]; 1063 H4_CS_sum = H4_CS_sum + H4_current_vector[pointer_CS]; 1064 1065 FAN_CS_sum = FAN_CS_sum + FAN_current_vector[pointer_CS]; 1066 1067 // check whether 1068 the pointer has reached the end of the vector and update of the latency value for 1069 synchronizing the current evaluation with the 60 Hz electrical cycle 1070 1071 if 1072 (pointer_CS == CS_vector_size - 1) { 1073 pointer_CS = 0; 1074 time_new_CS = 1075 millis(); 1076 correction_us = (long) 100000 / 6 / nb_pts_period - (time_new_CS 1077 - time_old_CS) * 1000 / CS_vector_size; 1078 time_old_CS = time_new_CS; 1079 1080 1081 1082 fixed_latency_new = fixed_latency_old + correction_us; 1083 1084 fixed_latency_old 1085 = fixed_latency_new; 1086 1087 1088 } 1089 else { 1090 pointer_CS++; 1091 } 1092 1093 1094 // conversion of the current value from raw to physical value in mA 1095 1096 temp_FLOAT_var 1097 = (float) sqrt(H1_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 1098 1099 current_sense_H_vector[0] = temp_FLOAT_var; 1100 1101 temp_FLOAT_var = (float) 1102 sqrt(H2_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 1103 1104 current_sense_H_vector[1] = temp_FLOAT_var; 1105 1106 temp_FLOAT_var = (float) 1107 sqrt(H3_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 1108 1109 current_sense_H_vector[2] = temp_FLOAT_var; 1110 1111 temp_FLOAT_var = (float) 1112 sqrt(H4_CS_sum / CS_vector_size) / H_current_conversion_1 * HB_current_conversion_2; 1113 1114 current_sense_H_vector[3] = temp_FLOAT_var; 1115 1116 temp_FLOAT_var = (float) 1117 sqrt(FAN_CS_sum / CS_vector_size) / B_current_conversion_1 * HB_current_conversion_2; 1118 1119 current_sense_FAN = temp_FLOAT_var; 1120} 1121 1122 1123///////////////////////////////////////////////////////////////////////////// 1124 1125 1126 1127 1128 1129 1130///////////////////////////////////////////////////////////////////////////// 1131// 1132 routine for comparing the current sense values to the thresholds for error management 1133 PRELIMINARY 1134///////////////////////////////////////////////////////////////////////////// 1135 1136void 1137 validation_current_vs_status() { 1138 1139 // blower current management 1140 switch 1141 (G_current_status) { 1142 1143 case 0: 1144 if (current_sense_FAN < current_FAN_min[0]) 1145 { 1146 system_status_LED[3] = 1; 1147 } 1148 if (current_sense_FAN 1149 > current_FAN_max[0]) { 1150 system_status_LED[3] = 1; 1151 } 1152 1153 1154 break; 1155 case 1: 1156 1157 if (current_sense_FAN < current_FAN_min[current_speed 1158 + 1]) { 1159 system_status_LED[3] = 1; 1160 } 1161 if (current_sense_FAN 1162 > current_FAN_max[current_speed + 1]) { 1163 system_status_LED[3] = 1; 1164 1165 } 1166 break; 1167 } 1168 1169 1170 1171 1172 1173} 1174 1175 1176///////////////////////////////////////////////////////////////////////////// 1177 1178 1179 1180 1181 1182 1183///////////////////////////////////////////////////////////////////////////// 1184// 1185 routine for sending the monitored values on the virtual COM port if a USB connection 1186 is detected 1187///////////////////////////////////////////////////////////////////////////// 1188 1189 1190void 1191 USB_status_verbose() { 1192 1193 //Serial.print("Current time = "); 1194 Serial.println(current_time); 1195 1196 //Serial.print("system status index = "); 1197 Serial.println(system_status_index); 1198 1199 //Serial.print("FAN status = "); 1200 Serial.println(FAN_status); 1201 //Serial.print("HEATER 1202 status = "); 1203 Serial.println(HEATER_status); 1204 //Serial.print("FAN UC 1205 / OC status = "); 1206 Serial.println(system_status_LED[3]); 1207 //Serial.print("H1 1208 UC / OC status = "); 1209 Serial.println(system_status_LED[4]); 1210 //Serial.print("H2 1211 UC / OC status = "); 1212 Serial.println(system_status_LED[5]); 1213 //Serial.print("H3 1214 UC / OC status = "); 1215 Serial.println(system_status_LED[6]); 1216 //Serial.print("H4 1217 UC / OC status = "); 1218 Serial.println(system_status_LED[7]); 1219 //Serial.print("G 1220 status = "); 1221 Serial.println(G_current_status); 1222 //Serial.print("W1 status 1223 = "); 1224 Serial.println(W1_current_status); 1225 //Serial.print("W2 status 1226 = "); 1227 Serial.println(W2_current_status); 1228 //Serial.print("W3 status 1229 = "); 1230 Serial.println(W3_current_status); 1231 //Serial.print("Thermistor 1232 1 value (C) = "); 1233 Serial.println(TH1_value); 1234 //Serial.print("Thermistor 1235 2 value (C) = "); 1236 Serial.println(TH2_value); 1237 //Serial.print("FAN RMS 1238 current (mA) = "); 1239 Serial.println(current_sense_FAN); 1240 //Serial.print("H1 1241 RMS current (mA) = "); 1242 Serial.println(current_sense_H_vector[0]); 1243 //Serial.print("H2 1244 RMS current (mA) = "); 1245 Serial.println(current_sense_H_vector[1]); 1246 //Serial.print("H3 1247 RMS current (mA) = "); 1248 Serial.println(current_sense_H_vector[2]); 1249 //Serial.print("H4 1250 RMS current (mA) = "); 1251 Serial.println(current_sense_H_vector[3]); 1252 //Serial.print("loop 1253 delay = "); 1254 Serial.println(fixed_latency_new); 1255 1256 time_USB = millis(); 1257} 1258 1259 1260///////////////////////////////////////////////////////////////////////////// 1261 1262 1263 1264 1265 1266 1267///////////////////////////////////////////////////////////////////////////// 1268// 1269 error management and system status update PRELIMINARY 1270///////////////////////////////////////////////////////////////////////////// 1271 1272void 1273 system_status_update() { 1274 1275 FAN_status = 0; 1276 1277 if (G_current_status 1278 == 1) { 1279 FAN_status = current_speed + 1; 1280 } 1281 1282 HEATER_status = 0; 1283 1284 1285 if (W1_current_status == 1) { 1286 HEATER_status = HEATER_status + W1_heating_state; 1287 1288 1289 if (W2_current_status == 1) { 1290 HEATER_status = HEATER_status + W2_heating_state; 1291 1292 } 1293 } 1294 1295 system_status_index = FAN_status * 5 + HEATER_status; 1296 1297 1298 // Check whether we are in error mode 1299 1300 if (system_status_LED[3] > 0) { 1301 1302 1303 1304 // blower issue, major error, heat strips cannot be operated (not implemented 1305 yet) 1306 1307 system_status_index = 26; 1308 1309 } 1310 else 1311 { 1312 1313 1314 1315 // Limp mode management, blower is working but at least 1 heat strip is not 1316 functionnal 1317 1318 if (system_status_LED[4] + system_status_LED[5] + system_status_LED[6] 1319 + system_status_LED[7] > 0) { 1320 1321 if ((system_status_LED[4] == 0) || (system_status_LED[5] 1322 == 0) || (system_status_LED[6] == 0) || (system_status_LED[7] == 0)) { 1323 1324 1325 1326 // At least one heat strip is not functionnal, we are in limp mode 1327 1328 1329 system_status_index = 25; 1330 } 1331 else 1332 { 1333 1334 // 1335 Every heat strips are not functionnal, major error 1336 system_status_index 1337 = 26; 1338 } 1339 } 1340 } 1341 1342 system_status_LED[0] = pgm_read_word(&LED1[system_status_index]); 1343 1344 system_status_LED[1] = pgm_read_word(&LED2[system_status_index]); 1345 system_status_LED[2] 1346 = pgm_read_word(&LED3[system_status_index]); 1347 1348} 1349 1350///////////////////////////////////////////////////////////////////////////// 1351 1352 1353 1354 1355 1356 1357///////////////////////////////////////////////////////////////////////////// 1358// 1359 main loop initialization 1360///////////////////////////////////////////////////////////////////////////// 1361 1362 1363void 1364 setup() { 1365 1366 Serial.begin(9600); 1367 1368 // initialisation 1369 1370 pinMode(LED_ctrl, 1371 OUTPUT); 1372 pinMode(H1_ctrl, OUTPUT); 1373 pinMode(H2_ctrl, OUTPUT); 1374 pinMode(H3_ctrl, 1375 OUTPUT); 1376 pinMode(H4_ctrl, OUTPUT); 1377 pinMode(BLO_ctrl, OUTPUT); 1378 pinMode(BMED_ctrl, 1379 OUTPUT); 1380 pinMode(BHI_ctrl, OUTPUT); 1381 pinMode(BSSR_ctrl, OUTPUT); 1382 pinMode(G, 1383 INPUT); 1384 pinMode(W1, INPUT); 1385 pinMode(W2, INPUT); 1386 pinMode(W3, INPUT); 1387 1388 1389 // analog inputs initialization 1390 1391 analogRead(TH1); 1392 analogRead(TH2); 1393 1394 analogRead(CSH1); 1395 analogRead(CSH2); 1396 analogRead(CSH3); 1397 analogRead(CSH4); 1398 1399 analogRead(CSFAN); 1400 1401 // LED light initialization 1402 1403 digitalWrite(LED_ctrl, 1404 LOW); // HIGH = RED, LOW = GREEN 1405 1406 // initialization of the heat strips 1407 relays 1408 digitalWrite(H1_ctrl, LOW); 1409 digitalWrite(H2_ctrl, LOW); 1410 digitalWrite(H3_ctrl, 1411 LOW); 1412 digitalWrite(H4_ctrl, LOW); 1413 1414 // initialization of blower relays 1415 1416 digitalWrite(BSSR_ctrl, LOW); 1417 digitalWrite(BHI_ctrl, LOW); 1418 digitalWrite(BMED_ctrl, 1419 LOW); 1420 digitalWrite(BLO_ctrl, LOW); 1421 1422 1423 // initialization of the vectors 1424 1425 memset(H1_current_vector, 0, CS_vector_size); 1426 memset(H2_current_vector, 0, 1427 CS_vector_size); 1428 memset(H3_current_vector, 0, CS_vector_size); 1429 memset(H4_current_vector, 1430 0, CS_vector_size); 1431 memset(FAN_current_vector, 0, CS_vector_size); 1432 memset(current_sense_H_vector, 1433 0, nb_of_heating_elements); 1434 1435 1436} 1437 1438 1439///////////////////////////////////////////////////////////////////////////// 1440 1441 1442 1443 1444 1445 1446///////////////////////////////////////////////////////////////////////////// 1447// 1448 main loop 1449///////////////////////////////////////////////////////////////////////////// 1450 1451 1452 1453void 1454 loop() { 1455 1456 1457 // reading of the thermostat signals 1458 1459 1460 G_new_status 1461 = (digitalRead(G) == LOW); // inverse logic, G_new_status is equal to 1 (fan 1462 activation) when the actual physical signal on the board is LOW 1463 W1_new_status 1464 = (digitalRead(W1) == LOW); // inverse logic, W1_new_status is equal to 1 (heat 1465 command active) when the actual physical signal on the board is LOW 1466 W2_new_status 1467 = (digitalRead(W2) == LOW); // inverse logic, W2_new_status is equal to 1 (heat 1468 command active) when the actual physical signal on the board is LOW 1469 W3_new_status 1470 = (digitalRead(W3) == LOW); // inverse logic, W3_new_status is equal to 1 (heat 1471 pump is active) when the actual physical signal on the board is LOW 1472 1473 // 1474 current time is updated once per cycle in the main loop 1475 current_time = millis(); 1476 1477 1478 1479 // rollover just happenend, reseeting of all the time stamps, the usual delays 1480 between the different steps will be longer just this one time, once every 50 days 1481 1482 if (old_current_time > current_time) { 1483 1484 time_H0 = current_time; 1485 1486 time_W1 = current_time; 1487 time_W2 = current_time; 1488 time_G0 = current_time; 1489 1490 time_G = current_time; 1491 time_old_CS = current_time; 1492 time_new_CS 1493 = current_time; 1494 time_SC = current_time; 1495 time_AF = current_time; 1496 1497 time_USB = current_time; 1498 } 1499 1500 old_current_time = current_time; 1501 1502 1503 1504 // Update of the thermistor temperature at every loop (mostly for monitoring purposes 1505 as it could be performed only when the blower is active) 1506 TH1_value = read_temp(TH1); 1507 1508 TH2_value = read_temp(TH2); 1509 1510 // security check, if the heat commands (W1 1511 or W2) or the heat pump (W3) are active, we make sure to operate the blower 1512 1513 if ((W1_current_status == 1 || W2_current_status == 1 || W3_current_status == 1514 1) && (G_current_status == 0 || G_new_status == 0 )) { 1515 1516 G_new_status = 1517 1; 1518 1519 } 1520 1521 1522 1523 // a change has been detected on the blower G command 1524 status 1525 if (G_new_status != G_current_status) { 1526 1527 activate_G(); 1528 1529 } 1530 1531 1532 // optimization of the blower speed and change of its speed are 1533 performed only after a fixed delay (after power-up and after a previous speed change) 1534 1535 if (G_current_status == 1) { 1536 1537 if ((long)(current_time - time_G0) >= 1538 delta_G0) { 1539 1540 if ((long)(current_time - time_G) >= delta_G) { 1541 1542 1543 new_speed_evaluation(); 1544 speed_change(); 1545 } 1546 } 1547 1548 } 1549 1550 // a change has been detected on the W1 heat command status 1551 if 1552 (W1_new_status != W1_current_status && (long)(current_time - time_H0) >= delta_H) 1553 { 1554 activate_W1(); 1555 } 1556 1557 1558 1559 // a change has been detected 1560 on the W2 heat command status 1561 if (W2_new_status != W2_current_status && (long)(current_time 1562 - time_H0) >= delta_H) { 1563 activate_W2(); 1564 } 1565 1566 1567 // delay validation 1568 before activating the second heat strip of W1 1569 if (W1_current_status == 1 && 1570 W1_new_status == 1) { 1571 if ((long)(current_time - time_W1) / 1000.0 >= delta_W1_level_1 1572 && W1_heating_state == 1 && (long)(current_time - time_H0) >= delta_H) { 1573 activate_W1(); 1574 1575 } 1576 } 1577 1578 1579 // delay validation before activating the second heat 1580 strip of W2 1581 if (W2_current_status == 1 && W2_new_status == 1) { 1582 if ((long)(current_time 1583 - time_W2) / 1000.0 >= delta_W2_level_1 && W2_heating_state == 1 && (long)(current_time 1584 - time_H0) >= delta_H) { 1585 activate_W2(); 1586 } 1587 1588 } 1589 1590 // 1591 a change has been detected on the W3 heat command status (heat pump) 1592 if (W3_new_status 1593 != W3_current_status) { 1594 W3_current_status = W3_new_status; 1595 } 1596 1597 1598 1599 1600 // current sense value update 1601 current_update(); 1602 1603 1604 // error management 1605 PRELIMINARY 1606 validation_current_vs_status(); 1607 1608 // system status update 1609 PRELIMINARY 1610 system_status_update(); 1611 1612 1613 1614 // Verification whether 1615 a USB connection is present 1616 1617 if (Serial && USB_connection_status == 0) { 1618 1619 USB_connection_status = 1; 1620 } 1621 1622 if (!Serial && USB_connection_status 1623 == 1) { 1624 USB_connection_status = 0; 1625 } 1626 1627 1628 // Delay validation 1629 and communication with the PC if the USB connection is active 1630 if ((long)(current_time 1631 - time_USB) >= USB_comm_period && USB_connection_status == 1) { 1632 1633 USB_status_verbose(); 1634 1635 } 1636 1637 1638 1639 1640 // fixed latency for perfect synchonization with the 60 1641 Hz electrical AC for precise current sense evaluation 1642 delayMicroseconds(fixed_latency_new); 1643 1644} 1645
Downloadable files
schematic
schematic
24VAC interfacing
how to interface 24VAC to Arduino
24VAC interfacing
schematic
schematic
Comments
Only logged in users can leave comments
desbiensl
0 Followers
•0 Projects
Table of contents
Intro
24
0