Skocz do zawartości

[Worklog] Piecyk do lutowania rozpływowego za <300zł


Pomocna odpowiedź

Hm, no tak, rozwiązanie które na początku wydaje się niegroźne i oczywiste, z czasem staje się niewygodne. Myślę o tym detektorze przejścia przez zero. Gdy stałeś przed mnóstwem innych problemów (projekt PCB i czy to w ogóle zadziała) grzejący się opornik nie był zmorą. Teraz gdy projekt jest trochę wyczyszczony, ciepełko zaczyna doskwierać..

Cóż, mam kilka pomysłów:

1. Użycie czulszego transoptora i większego rezystora 🙂

2. Zamiana mocy czynnej na bierną, tj. wstawienie szeregowo z opornikiem (znacznie mniejszym np. 1k) kondensatora. Jego reaktancja 1/(2*Pi*f*C) powinna być taka, by dla 50Hz "udawał" te poprzednie 15k. Wadą jest oczywiście wtedy ok. 90° przesunięcie fazy prądu LEDa (a więc i impulsów wyjściowych) względem napięcia sieci, ale procesor pewnie by sobie z tym poradził. Gdyby częstotliwość sieci była stała, przesunięcie też powinno, przynajmniej w granicach błędu sensowności.

3. Użycie prostego, tranzystorowego źródełka prądowego wstawionego zamiast obecnego rezystora. Takie coś dawałoby dużo ostrzejsze zbocze podczas samego przejścia sieci przez zero i ograniczałoby prąd diody podczas całego (pół)okresu do wartości minimalnej, koniecznej do pewnego zapalenia LEDa.

4. Inne, bardziej wymyślne układy (ale bez przesady, to wciąż jakieś dwa-trzy tranzystory..) które generują np. krótki impuls na początku sinusoidy zamiast pchać prąd diodki przez cały (pół)okres sieci. Można wtedy zejść spokojnie poniżej 100mW.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Chwilowo zostawię jak jest, działa, będzie jakiś wentylator jeszcze to będzie OK.

Jeśli będę robił drugą wersję to pomyślę nad 4.

Dlaczego nikt nie robi gotowych scalaków do tego?

Przecież to brzmi jak coś co TI miałoby w 15 różnych wersjach!

Ogólnie jestem bardzo pozytywnie zaskoczony tym jak dobrze chwilowo działa. I jestem bardzo wdzięczny za przekonanie mnie do zakupu oscyloskopu 😃

Link do komentarza
Share on other sites

Skończone przenoszenie kodu odpowiadającego za wyjścia do struktur, przepisana więkdzość strony, teraz działa już wiele kanałów:

Dwa termistory na jednym PCB, ogrzewane halogenami.

Trochę mała różnica, boję się że w piekarniku będzie jeszcze gorzej.

Idea jest taka żeby móc lutować jedną stronę bez uszkadzania drugiej.

Ktoś ma jakiś pomysł?

Wszelka pomoc z kodem mile widziana, główny sterownik: https://github.com/SteelLiras/OvenController/blob/master/OvenSoft/OvenSoft.ino

#include <pins_arduino.h>
#include <Arduino.h>
#include <avr/pgmspace.h>

const float lookupTemp[1024] PROGMEM = { -273.150, -16.227, -4.079, 3.583, 9.295, 13.895, 17.770, 21.133, 24.112, 26.793, 29.235, 31.480, 33.562, 35.504, 37.326, 39.043, 40.669, 42.213, 43.684, 45.089, 46.435, 47.728, 48.971, 50.170, 51.327, 52.445, 53.529, 54.579, 55.598, 56.589, 57.552, 58.491, 59.405, 60.298, 61.169, 62.020, 62.852, 63.666, 64.463, 65.243, 66.008, 66.759, 67.495, 68.218, 68.928, 69.625, 70.311, 70.985, 71.648, 72.301, 72.943, 73.576, 74.200, 74.814, 75.420, 76.017, 76.606, 77.187, 77.761, 78.327, 78.886, 79.438, 79.983, 80.522, 81.054, 81.581, 82.101, 82.616, 83.125, 83.628, 84.126, 84.619, 85.107, 85.590, 86.069, 86.542, 87.011, 87.476, 87.936, 88.392, 88.844, 89.292, 89.736, 90.176, 90.612, 91.045, 91.474, 91.899, 92.322, 92.740, 93.156, 93.568, 93.977, 94.383, 94.786, 95.186, 95.583, 95.978, 96.369, 96.758, 97.144, 97.527, 97.908, 98.286, 98.662, 99.036, 99.407, 99.775, 100.142, 100.506, 100.868, 101.227, 101.585, 101.940, 102.294, 102.645, 102.994, 103.341, 103.687, 104.030, 104.372, 104.711, 105.049, 105.385, 105.720, 106.052, 106.383, 106.713, 107.040, 107.366, 107.691, 108.013, 108.335, 108.654, 108.972, 109.289, 109.604, 109.918, 110.231, 110.542, 110.851, 111.159, 111.466, 111.772, 112.076, 112.379, 112.681, 112.981, 113.281, 113.579, 113.876, 114.171, 114.466, 114.759, 115.051, 115.342, 115.632, 115.921, 116.209, 116.496, 116.781, 117.066, 117.350, 117.632, 117.914, 118.195, 118.474, 118.753, 119.031, 119.308, 119.584, 119.859, 120.133, 120.406, 120.678, 120.950, 121.221, 121.490, 121.759, 122.027, 122.295, 122.561, 122.827, 123.092, 123.356, 123.619, 123.882, 124.144, 124.405, 124.665, 124.925, 125.184, 125.442, 125.700, 125.957, 126.213, 126.468, 126.723, 126.977, 127.231, 127.484, 127.736, 127.987, 128.238, 128.489, 128.739, 128.988, 129.236, 129.484, 129.732, 129.978, 130.225, 130.470, 130.715, 130.960, 131.204, 131.447, 131.690, 131.933, 132.175, 132.416, 132.657, 132.897, 133.137, 133.377, 133.616, 133.854, 134.092, 134.329, 134.566, 134.803, 135.039, 135.275, 135.510, 135.745, 135.979, 136.213, 136.446, 136.679, 136.912, 137.144, 137.376, 137.607, 137.838, 138.069, 138.299, 138.529, 138.759, 138.988, 139.216, 139.445, 139.673, 139.900, 140.127, 140.354, 140.581, 140.807, 141.033, 141.258, 141.484, 141.708, 141.933, 142.157, 142.381, 142.605, 142.828, 143.051, 143.273, 143.496, 143.718, 143.940, 144.161, 144.382, 144.603, 144.824, 145.044, 145.264, 145.484, 145.703, 145.923, 146.142, 146.360, 146.579, 146.797, 147.015, 147.233, 147.450, 147.668, 147.885, 148.101, 148.318, 148.534, 148.750, 148.966, 149.182, 149.397, 149.612, 149.827, 150.042, 150.257, 150.471, 150.685, 150.899, 151.113, 151.327, 151.540, 151.753, 151.966, 152.179, 152.392, 152.604, 152.817, 153.029, 153.241, 153.452, 153.664, 153.876, 154.087, 154.298, 154.509, 154.720, 154.931, 155.141, 155.351, 155.562, 155.772, 155.982, 156.192, 156.401, 156.611, 156.820, 157.030, 157.239, 157.448, 157.657, 157.866, 158.074, 158.283, 158.491, 158.700, 158.908, 159.116, 159.324, 159.532, 159.740, 159.948, 160.155, 160.363, 160.570, 160.778, 160.985, 161.192, 161.399, 161.606, 161.813, 162.020, 162.227, 162.433, 162.640, 162.847, 163.053, 163.260, 163.466, 163.672, 163.878, 164.085, 164.291, 164.497, 164.703, 164.909, 165.115, 165.321, 165.526, 165.732, 165.938, 166.144, 166.349, 166.555, 166.760, 166.966, 167.172, 167.377, 167.582, 167.788, 167.993, 168.199, 168.404, 168.609, 168.815, 169.020, 169.225, 169.431, 169.636, 169.841, 170.047, 170.252, 170.457, 170.662, 170.868, 171.073, 171.278, 171.483, 171.689, 171.894, 172.099, 172.305, 172.510, 172.715, 172.921, 173.126, 173.331, 173.537, 173.742, 173.948, 174.153, 174.359, 174.564, 174.770, 174.976, 175.181, 175.387, 175.593, 175.799, 176.005, 176.210, 176.416, 176.622, 176.828, 177.034, 177.241, 177.447, 177.653, 177.859, 178.066, 178.272, 178.479, 178.685, 178.892, 179.098, 179.305, 179.512, 179.719, 179.926, 180.133, 180.340, 180.547, 180.755, 180.962, 181.170, 181.377, 181.585, 181.793, 182.000, 182.208, 182.416, 182.624, 182.833, 183.041, 183.249, 183.458, 183.667, 183.875, 184.084, 184.293, 184.502, 184.711, 184.921, 185.130, 185.340, 185.549, 185.759, 185.969, 186.179, 186.389, 186.600, 186.810, 187.021, 187.231, 187.442, 187.653, 187.864, 188.075, 188.287, 188.498, 188.710, 188.922, 189.134, 189.346, 189.558, 189.771, 189.983, 190.196, 190.409, 190.622, 190.836, 191.049, 191.263, 191.476, 191.690, 191.904, 192.119, 192.333, 192.548, 192.763, 192.978, 193.193, 193.408, 193.624, 193.840, 194.056, 194.272, 194.488, 194.705, 194.922, 195.139, 195.356, 195.573, 195.791, 196.009, 196.227, 196.445, 196.663, 196.882, 197.101, 197.320, 197.539, 197.759, 197.979, 198.199, 198.419, 198.640, 198.860, 199.081, 199.303, 199.524, 199.746, 199.968, 200.190, 200.412, 200.635, 200.858, 201.081, 201.305, 201.529, 201.753, 201.977, 202.201, 202.426, 202.651, 202.877, 203.102, 203.328, 203.555, 203.781, 204.008, 204.235, 204.462, 204.690, 204.918, 205.146, 205.375, 205.604, 205.833, 206.062, 206.292, 206.522, 206.753, 206.984, 207.215, 207.446, 207.678, 207.910, 208.142, 208.375, 208.608, 208.841, 209.075, 209.309, 209.544, 209.778, 210.014, 210.249, 210.485, 210.721, 210.958, 211.195, 211.432, 211.670, 211.908, 212.146, 212.385, 212.624, 212.864, 213.104, 213.344, 213.585, 213.826, 214.067, 214.309, 214.552, 214.794, 215.037, 215.281, 215.525, 215.769, 216.014, 216.260, 216.505, 216.751, 216.998, 217.245, 217.492, 217.740, 217.989, 218.237, 218.487, 218.736, 218.987, 219.237, 219.488, 219.740, 219.992, 220.244, 220.497, 220.751, 221.005, 221.259, 221.514, 221.770, 222.026, 222.282, 222.539, 222.797, 223.055, 223.314, 223.573, 223.832, 224.092, 224.353, 224.614, 224.876, 225.138, 225.401, 225.665, 225.929, 226.193, 226.459, 226.724, 226.991, 227.257, 227.525, 227.793, 228.062, 228.331, 228.601, 228.871, 229.142, 229.414, 229.686, 229.959, 230.233, 230.507, 230.782, 231.058, 231.334, 231.611, 231.888, 232.166, 232.445, 232.725, 233.005, 233.286, 233.567, 233.850, 234.133, 234.416, 234.701, 234.986, 235.272, 235.558, 235.846, 236.134, 236.422, 236.712, 237.002, 237.293, 237.585, 237.878, 238.171, 238.465, 238.760, 239.056, 239.353, 239.650, 239.948, 240.247, 240.547, 240.848, 241.149, 241.452, 241.755, 242.059, 242.364, 242.670, 242.977, 243.285, 243.593, 243.903, 244.213, 244.524, 244.836, 245.150, 245.464, 245.779, 246.095, 246.412, 246.730, 247.049, 247.369, 247.690, 248.011, 248.334, 248.658, 248.983, 249.309, 249.637, 249.965, 250.294, 250.624, 250.956, 251.288, 251.622, 251.956, 252.292, 252.629, 252.967, 253.306, 253.647, 253.988, 254.331, 254.675, 255.020, 255.367, 255.714, 256.063, 256.413, 256.764, 257.117, 257.471, 257.826, 258.182, 258.540, 258.899, 259.260, 259.621, 259.984, 260.349, 260.715, 261.082, 261.451, 261.821, 262.192, 262.565, 262.940, 263.316, 263.693, 264.072, 264.453, 264.835, 265.218, 265.603, 265.990, 266.378, 266.768, 267.159, 267.553, 267.947, 268.344, 268.742, 269.142, 269.543, 269.947, 270.352, 270.759, 271.167, 271.578, 271.990, 272.404, 272.820, 273.238, 273.657, 274.079, 274.503, 274.928, 275.356, 275.785, 276.217, 276.651, 277.086, 277.524, 277.964, 278.406, 278.850, 279.296, 279.745, 280.196, 280.649, 281.104, 281.561, 282.021, 282.484, 282.948, 283.415, 283.885, 284.357, 284.831, 285.308, 285.787, 286.269, 286.754, 287.241, 287.731, 288.224, 288.719, 289.217, 289.718, 290.222, 290.729, 291.238, 291.751, 292.266, 292.784, 293.306, 293.830, 294.358, 294.888, 295.422, 295.960, 296.500, 297.044, 297.591, 298.141, 298.695, 299.253, 299.814, 300.378, 300.947, 301.519, 302.094, 302.674, 303.257, 303.844, 304.435, 305.030, 305.629, 306.232, 306.840, 307.451, 308.067, 308.687, 309.312, 309.941, 310.574, 311.212, 311.855, 312.503, 313.155, 313.813, 314.475, 315.142, 315.814, 316.492, 317.175, 317.863, 318.556, 319.255, 319.960, 320.670, 321.387, 322.109, 322.837, 323.571, 324.311, 325.057, 325.810, 326.570, 327.336, 328.108, 328.888, 329.675, 330.468, 331.269, 332.077, 332.893, 333.716, 334.547, 335.386, 336.233, 337.088, 337.951, 338.823, 339.704, 340.593, 341.491, 342.399, 343.316, 344.242, 345.178, 346.124, 347.081, 348.047, 349.025, 350.013, 351.012, 352.022, 353.044, 354.077, 355.123, 356.181, 357.251, 358.335, 359.431, 360.541, 361.665, 362.803, 363.955, 365.122, 366.305, 367.503, 368.716, 369.946, 371.193, 372.457, 373.739, 375.039, 376.357, 377.695, 379.052, 380.429, 381.827, 383.246, 384.688, 386.152, 387.639, 389.150, 390.686, 392.247, 393.834, 395.449, 397.091, 398.763, 400.464, 402.195, 403.959, 405.756, 407.586, 409.452, 411.355, 413.295, 415.275, 417.295, 419.358, 421.465, 423.618, 425.818, 428.068, 430.369, 432.724, 435.136, 437.606, 440.137, 442.733, 445.396, 448.129, 450.936, 453.821, 456.787, 459.838, 462.980, 466.218, 469.556, 473.000, 476.557, 480.233, 484.037, 487.975, 492.056, 496.292, 500.691, 505.266, 510.029, 514.995, 520.181, 525.603, 531.281, 537.238, 543.500, 550.094, 557.054, 564.417, 572.225, 580.529, 589.387, 598.868, 609.051, 620.036, 631.937, 644.899, 659.098, 674.755, 692.151, 711.653, 733.744, 759.082, 788.589, 823.603, 866.155, 919.522, 989.401, 1086.827, 1236.905, 1514.704, 2333.720, 9999.99 };
const uint16_t lookupTime[1001] PROGMEM = { 0, 181, 256, 314, 363, 405, 444, 480, 513, 544, 574, 602, 629, 655, 680, 703, 727, 749, 771, 792, 813, 833, 853, 872, 891, 910, 928, 946, 963, 980, 997, 1014, 1030, 1047, 1063, 1078, 1094, 1109, 1124, 1139, 1154, 1168, 1183, 1197, 1211, 1225, 1238, 1252, 1266, 1279, 1292, 1305, 1318, 1331, 1344, 1356, 1369, 1381, 1394, 1406, 1418, 1430, 1442, 1454, 1465, 1477, 1489, 1500, 1512, 1523, 1534, 1545, 1556, 1568, 1579, 1589, 1600, 1611, 1622, 1632, 1643, 1654, 1664, 1674, 1685, 1695, 1705, 1715, 1726, 1736, 1746, 1756, 1766, 1776, 1785, 1795, 1805, 1815, 1824, 1834, 1843, 1853, 1863, 1872, 1881, 1891, 1900, 1909, 1919, 1928, 1937, 1946, 1955, 1964, 1973, 1982, 1991, 2000, 2009, 2018, 2027, 2036, 2044, 2053, 2062, 2070, 2079, 2088, 2096, 2105, 2113, 2122, 2130, 2139, 2147, 2156, 2164, 2172, 2181, 2189, 2197, 2206, 2214, 2222, 2230, 2238, 2246, 2254, 2263, 2271, 2279, 2287, 2295, 2303, 2311, 2318, 2326, 2334, 2342, 2350, 2358, 2366, 2373, 2381, 2389, 2397, 2404, 2412, 2420, 2427, 2435, 2443, 2450, 2458, 2465, 2473, 2480, 2488, 2495, 2503, 2510, 2518, 2525, 2533, 2540, 2547, 2555, 2562, 2570, 2577, 2584, 2591, 2599, 2606, 2613, 2621, 2628, 2635, 2642, 2649, 2657, 2664, 2671, 2678, 2685, 2692, 2699, 2706, 2713, 2720, 2727, 2735, 2742, 2749, 2756, 2762, 2769, 2776, 2783, 2790, 2797, 2804, 2811, 2818, 2825, 2832, 2839, 2845, 2852, 2859, 2866, 2873, 2879, 2886, 2893, 2900, 2906, 2913, 2920, 2927, 2933, 2940, 2947, 2953, 2960, 2967, 2973, 2980, 2987, 2993, 3000, 3007, 3013, 3020, 3026, 3033, 3040, 3046, 3053, 3059, 3066, 3072, 3079, 3085, 3092, 3098, 3105, 3111, 3118, 3124, 3131, 3137, 3144, 3150, 3156, 3163, 3169, 3176, 3182, 3188, 3195, 3201, 3208, 3214, 3220, 3227, 3233, 3239, 3246, 3252, 3258, 3265, 3271, 3277, 3283, 3290, 3296, 3302, 3309, 3315, 3321, 3327, 3334, 3340, 3346, 3352, 3358, 3365, 3371, 3377, 3383, 3390, 3396, 3402, 3408, 3414, 3420, 3427, 3433, 3439, 3445, 3451, 3457, 3463, 3470, 3476, 3482, 3488, 3494, 3500, 3506, 3512, 3518, 3524, 3530, 3537, 3543, 3549, 3555, 3561, 3567, 3573, 3579, 3585, 3591, 3597, 3603, 3609, 3615, 3621, 3627, 3633, 3639, 3645, 3651, 3657, 3663, 3669, 3675, 3681, 3687, 3693, 3699, 3705, 3711, 3717, 3723, 3729, 3735, 3741, 3746, 3752, 3758, 3764, 3770, 3776, 3782, 3788, 3794, 3800, 3806, 3812, 3817, 3823, 3829, 3835, 3841, 3847, 3853, 3859, 3865, 3870, 3876, 3882, 3888, 3894, 3900, 3906, 3911, 3917, 3923, 3929, 3935, 3941, 3947, 3952, 3958, 3964, 3970, 3976, 3982, 3987, 3993, 3999, 4005, 4011, 4016, 4022, 4028, 4034, 4040, 4045, 4051, 4057, 4063, 4069, 4074, 4080, 4086, 4092, 4098, 4103, 4109, 4115, 4121, 4127, 4132, 4138, 4144, 4150, 4155, 4161, 4167, 4173, 4178, 4184, 4190, 4196, 4202, 4207, 4213, 4219, 4225, 4230, 4236, 4242, 4248, 4253, 4259, 4265, 4271, 4276, 4282, 4288, 4294, 4299, 4305, 4311, 4317, 4322, 4328, 4334, 4339, 4345, 4351, 4357, 4362, 4368, 4374, 4380, 4385, 4391, 4397, 4403, 4408, 4414, 4420, 4426, 4431, 4437, 4443, 4448, 4454, 4460, 4466, 4471, 4477, 4483, 4489, 4494, 4500, 4506, 4511, 4517, 4523, 4529, 4534, 4540, 4546, 4552, 4557, 4563, 4569, 4574, 4580, 4586, 4592, 4597, 4603, 4609, 4615, 4620, 4626, 4632, 4638, 4643, 4649, 4655, 4661, 4666, 4672, 4678, 4683, 4689, 4695, 4701, 4706, 4712, 4718, 4724, 4729, 4735, 4741, 4747, 4752, 4758, 4764, 4770, 4775, 4781, 4787, 4793, 4798, 4804, 4810, 4816, 4822, 4827, 4833, 4839, 4845, 4850, 4856, 4862, 4868, 4873, 4879, 4885, 4891, 4897, 4902, 4908, 4914, 4920, 4926, 4931, 4937, 4943, 4949, 4955, 4960, 4966, 4972, 4978, 4984, 4989, 4995, 5001, 5007, 5013, 5018, 5024, 5030, 5036, 5042, 5048, 5053, 5059, 5065, 5071, 5077, 5083, 5089, 5094, 5100, 5106, 5112, 5118, 5124, 5130, 5135, 5141, 5147, 5153, 5159, 5165, 5171, 5177, 5183, 5188, 5194, 5200, 5206, 5212, 5218, 5224, 5230, 5236, 5242, 5248, 5254, 5259, 5265, 5271, 5277, 5283, 5289, 5295, 5301, 5307, 5313, 5319, 5325, 5331, 5337, 5343, 5349, 5355, 5361, 5367, 5373, 5379, 5385, 5391, 5397, 5403, 5409, 5415, 5421, 5427, 5433, 5439, 5445, 5451, 5457, 5463, 5470, 5476, 5482, 5488, 5494, 5500, 5506, 5512, 5518, 5524, 5530, 5537, 5543, 5549, 5555, 5561, 5567, 5573, 5580, 5586, 5592, 5598, 5604, 5610, 5617, 5623, 5629, 5635, 5642, 5648, 5654, 5660, 5666, 5673, 5679, 5685, 5691, 5698, 5704, 5710, 5717, 5723, 5729, 5735, 5742, 5748, 5754, 5761, 5767, 5773, 5780, 5786, 5792, 5799, 5805, 5812, 5818, 5824, 5831, 5837, 5844, 5850, 5856, 5863, 5869, 5876, 5882, 5889, 5895, 5902, 5908, 5915, 5921, 5928, 5934, 5941, 5947, 5954, 5960, 5967, 5974, 5980, 5987, 5993, 6000, 6007, 6013, 6020, 6027, 6033, 6040, 6047, 6053, 6060, 6067, 6073, 6080, 6087, 6094, 6100, 6107, 6114, 6121, 6127, 6134, 6141, 6148, 6155, 6161, 6168, 6175, 6182, 6189, 6196, 6203, 6210, 6217, 6224, 6231, 6238, 6244, 6251, 6258, 6265, 6273, 6280, 6287, 6294, 6301, 6308, 6315, 6322, 6329, 6336, 6343, 6351, 6358, 6365, 6372, 6379, 6387, 6394, 6401, 6409, 6416, 6423, 6430, 6438, 6445, 6453, 6460, 6467, 6475, 6482, 6490, 6497, 6505, 6512, 6520, 6527, 6535, 6542, 6550, 6557, 6565, 6573, 6580, 6588, 6596, 6603, 6611, 6619, 6627, 6634, 6642, 6650, 6658, 6666, 6674, 6682, 6689, 6697, 6705, 6713, 6721, 6729, 6737, 6746, 6754, 6762, 6770, 6778, 6786, 6794, 6803, 6811, 6819, 6828, 6836, 6844, 6853, 6861, 6870, 6878, 6887, 6895, 6904, 6912, 6921, 6930, 6938, 6947, 6956, 6964, 6973, 6982, 6991, 7000, 7009, 7018, 7027, 7036, 7045, 7054, 7063, 7072, 7081, 7091, 7100, 7109, 7119, 7128, 7137, 7147, 7157, 7166, 7176, 7185, 7195, 7205, 7215, 7224, 7234, 7244, 7254, 7264, 7274, 7285, 7295, 7305, 7315, 7326, 7336, 7346, 7357, 7368, 7378, 7389, 7400, 7411, 7421, 7432, 7444, 7455, 7466, 7477, 7488, 7500, 7511, 7523, 7535, 7546, 7558, 7570, 7582, 7594, 7606, 7619, 7631, 7644, 7656, 7669, 7682, 7695, 7708, 7721, 7734, 7748, 7762, 7775, 7789, 7803, 7817, 7832, 7846, 7861, 7876, 7891, 7906, 7922, 7937, 7953, 7970, 7986, 8003, 8020, 8037, 8054, 8072, 8090, 8109, 8128, 8147, 8167, 8187, 8208, 8229, 8251, 8273, 8297, 8320, 8345, 8371, 8398, 8426, 8456, 8487, 8520, 8556, 8595, 8637, 8686, 8744, 8819, 9000 };

bool enforceSlope = false;
volatile bool justCrossedZero = false;
volatile unsigned long zeroCrossingTime = 0;
unsigned long heatingStartTime = 0;

#define ELAPSED (millis() - heatingStartTime)	//TODO: Maybe make it nicer?
#define CROSSING (millis() - zeroCrossingTime)

bool started = false;

#define BUFFERSIZE 7

struct Thermistor {
unsigned char pin;
int buffer[BUFFERSIZE];
float temp = 0;
float average = 0;
void calculate() {
	volatile unsigned long sum = 0;
	for (int i = 0; i < BUFFERSIZE; i++) {
		sum += buffer[i];
	}
	average = ((float) sum) / ((float) BUFFERSIZE);
	temp = pgm_read_float_near(lookupTemp + ((int )(average + 0.5)));
}
void forceInit() {
	for (int i = 0; i < BUFFERSIZE; i++) {
		buffer[i] = analogRead(pin);
	}
	calculate();
	for (int i = 0; i < BUFFERSIZE; i++) {
		buffer[i] = average;
	}
}
int rejected = 0;
void update() {
	int tempVal = analogRead(pin);
	if (abs(tempVal - buffer[BUFFERSIZE - 1]) < 10) {
		rejected = 0;
		for (int i = 0; i < BUFFERSIZE - 1; i++) {
			buffer[i] = buffer[i + 1];
		}
		buffer[BUFFERSIZE - 1] = tempVal;
	} else {
		rejected++;
	}
	if(rejected > 10){
		forceInit();
	}
	calculate();
}
};

#define THERMISTOR_CHANNEL_NR 2
Thermistor thermistors[THERMISTOR_CHANNEL_NR];

#define POINTS 20

struct event {
uint32_t timeVal;
float targetTemp;
};

struct ACchannel {
int pin;
int thermistorNo;
bool channelEnabled = false;

float target = 0;
bool notStarted = false;
unsigned int onTime = 0;

event eventArray[POINTS];
int totalEvents = 0;
int currentEvent = -1;

unsigned long endNodeTime = 0;
int endNodeTemp = 0;
unsigned long lastNodeEnd = 0;
int lastNodeTemp = 0;

void init() {
	endNodeTemp = thermistors[thermistorNo].temp;
	endNodeTime = ELAPSED;
	currentEvent = -1;
	nextNode();
	channelEnabled = true;
}
void eval() {
	if (notStarted && (CROSSING >= onTime) && (onTime < 9600) && channelEnabled) {
		digitalWrite(pin, HIGH);
		delayMicroseconds(7);   //experimental, do not "fix".
		digitalWrite(pin, LOW);
		notStarted = false;
	}
}

void nextNode() {
	currentEvent++;
	if (currentEvent == totalEvents) {
		channelEnabled = false;
		return;
	}
	lastNodeEnd = endNodeTime;   //TODO: A mode that waits until temperature is achieved before next node.
	lastNodeTemp = endNodeTemp;
	endNodeTemp = eventArray[currentEvent].targetTemp;
	endNodeTime = eventArray[currentEvent].timeVal;
}

float kP = 200.0;

void calculatePID() {
	float temperature = thermistors[thermistorNo].temp;
	if (ELAPSED >= endNodeTime) {
		nextNode();
	}
	if (enforceSlope) {
		/*NEW:
		 if (endNodeTemp > lastNodeTemp) { //closer to current of the slope as-is or going from current temperature
		 target = min(
		 temperature
		 + ((float) (endNodeTemp - lastNodeTemp)) * 20.0
		 / ((float) (endNodeTime - lastNodeEnd)),
		 lastNodeTemp
		 + ((float) (endNodeTemp - lastNodeTemp))
		 * ((float) (ELAPSED - lastNodeEnd))
		 / ((float) (endNodeTime - lastNodeEnd)));
		 } else {
		 target = max(
		 temperature
		 + ((float) (endNodeTemp - lastNodeTemp)) * 20.0
		 / ((float) (endNodeTime - lastNodeEnd)),
		 lastNodeTemp
		 + ((float) (endNodeTemp - lastNodeTemp))
		 * ((float) (ELAPSED - lastNodeEnd))
		 / ((float) (endNodeTime - lastNodeEnd)));
		 }*/
		//OLD:
		target = lastNodeTemp + ((float) (endNodeTemp - lastNodeTemp)) * ((float) (ELAPSED - lastNodeEnd)) / ((float) (endNodeTime - lastNodeEnd));
	} else {
		target = endNodeTemp;
	}
	float difference = target - temperature;

	onTime = 9600 - pgm_read_word_near(lookupTime + ((int) (constrain(difference, 0, 999.5/kP) * kP)));
}
};

#define AC_CHANNEL_NR 2
ACchannel channels[AC_CHANNEL_NR];

void zeroCrossing() {
justCrossedZero = true;
zeroCrossingTime = micros();
}


void setup() {

pinMode(6, OUTPUT); //TRIAC
pinMode(7, OUTPUT); //TRIAC
pinMode(2, INPUT); //ZERO
digitalWrite(6, LOW);
digitalWrite(7, LOW);

Serial.begin(115200);
attachInterrupt(digitalPinToInterrupt(2), zeroCrossing, RISING);

channels[0].pin = 6;
channels[0].thermistorNo = 0;
thermistors[0].pin = A0;
channels[1].pin = 7;
channels[1].thermistorNo = 1;
thermistors[1].pin = A1;
}

int debugV = 0;


void updatePID() {
for (int i = 0; i < THERMISTOR_CHANNEL_NR; i++) {
	thermistors[i].update();
}
for (int i = 0; i < AC_CHANNEL_NR; i++) {
	channels[i].calculatePID();
}
}

void loop() {
if (Serial.available() > 0) {
	char function = Serial.read();
	switch (function) {
	case 'V': //get version
		Serial.print(POINTS);
		Serial.print(";0;"); //TODO: Finalize float support for temperature points.
		break;
	case 'C': //change enforce
		enforceSlope = (bool) Serial.readStringUntil(';').toInt();
		break;
	case 'S': //stop
		started = false;
		break;
	case 'T': //get temp
		Serial.print(ELAPSED);
		Serial.print(";");
		Serial.print(thermistors[0].temp);
		Serial.print(";");
		Serial.print(thermistors[1].temp);
		//Serial.print(channels[0].target);
		Serial.print(";");
		break;
	case 'Q':
		for (int i = 0; i < THERMISTOR_CHANNEL_NR; i++) {
			thermistors[i].forceInit();
		}
		int activeChannels = Serial.readStringUntil(';').toInt();
		for (int ch = 0; ch < activeChannels; ch++) {
			channels[ch].totalEvents = Serial.readStringUntil(';').toInt();
			for (int i = 0; i < channels[ch].totalEvents; i++) {
				channels[ch].eventArray[i].timeVal = Serial.readStringUntil(';').toInt(); //TODO: Better transfer method.
				channels[ch].eventArray[i].targetTemp = Serial.readStringUntil(';').toFloat();
			}
			channels[ch].init();
		}
		heatingStartTime = millis();
		started = true;
		break;
	}
}
if (started && justCrossedZero) {
	justCrossedZero = false;
	updatePID();
	for (int i = 0; i < AC_CHANNEL_NR; i++) {
		channels[i].notStarted = true;
	}
}

for (int i = 0; i < AC_CHANNEL_NR; i++) {
	channels[i].eval();
}
}
Link do komentarza
Share on other sites

Jak chodzi o program to proponowałbym przemyśleć kilka małych zmian.

Po pierwsze, w C program byłby niepoprawny - struktury z metodami i inicjalizacją wartości to już C++. Ale skoro piszesz w C++ to dlaczego to ukrywać? Może lepiej zamiast "struct" napisać "class" - i od razu mamy kod obiektowy. Można nawet podzielić zawartość klasy na część publiczną i prywatną.

Druga sprawa, to wielkość kodu. Niby jeszcze jest krótki, ale już ciężko na pierwszy rzut oka połapać się o co chodzi. W takiej sytuacji często pomaga podzielenie programu na kilka plików źródłowych.

Na początku masz spore tablice współczynników - dlaczego nie przenieść ich do zewnętrznego pliku? Wtedy jeśli będziesz chciał mieć kilka wersji, wystarczy wybrać który plik włączać do projektu.

Kolejna sprawa to klasy Thermistor i ACchannel - gdyby je przenieść do oddzielnych plików, kod byłby dużo czytelniejszy.

Kolejnym krokiem mogłobybyć pomyślenie o stworzeniu testów jednostkowych - skoro są klasy, to dlaczego ich nie przetestować? Przecież taki piecyk to dość niebezpieczne narzędzie - błąd w programie może wywołać pożar albo zniszczyć drogą i cenną elektronikę.

Dla C++ dostępnych jest sporo narzędzi do testowania. Ja mogę polecić framework Google Unit Test (https://github.com/google/googletest), ale jakikolwiek będzie lepszy niż program bez testów.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Może lepiej zamiast "struct" napisać "class" - i od razu mamy kod obiektowy.

Szczerze mówiąc używam struct z przyzwyczajenia.

Z drugiej strony na Stack Overflow mówią że praktycznie nie ma różnicy: http://stackoverflow.com/questions/54585/when-should-you-use-a-class-vs-a-struct-in-c

podzielenie programu na kilka plików źródłowych

Tak, powinienem. Szczerze mówiąc kod zaczął w Arduino IDE gdzie zrobienie tego byłoby dość niewygodne, potem przemigrował do Eclipse i jakoś o tym nie pomyślałem.

pomyślenie o stworzeniu testów jednostkowych

W sumie ciekawy pomysł. No i możnaby zrobić filmik pt. "Unit tests for Arduino applications" xD

Możesz polecić jakiś dobry poradnik do tego?

Link do komentarza
Share on other sites

Nie chcę się spierać z tym co ktoś napisał na StackOverflow, ani oceniać kompetencji piszących, ale klasa daje możliwośc podziału na części publiczne, prywatne i chronione, warto też pomyśleć nad wydzieleniem interfejsu do pliku nagłówkowego, a treści metod do pliku z kodem. Niby niewielkie zmiany, ale łatwiej wtedy czytać program.

Poza tym taką klasę można użyć w innym projekcie - albo nawet tym samym, ale kompilując np. na PC żeby wykonać testy jednostkowe.

Właśnie o takich testach pomyślałem, ale może testowanie na Arduino też jest pewną opcją. Wujek google mówi, ktoś już próbował coś takiego zrobić: https://github.com/mmurdoch/arduinounit

Link do komentarza
Share on other sites

Przepraszam, że się wtrące z off-topikiem, ale intryguje mnie coś.

Nigdy nie rozumiałem konieczności dzielenia kodu na częśći prywatne, publiczne i chronione, szczególnie jeśli jesteś jedynym programistą w projektcie. Co to w praktyce daje? Tyle, że jak jednak okazuje się, że potrzebujesz jakiejś zmiennej, to musisz zmieniać więcej kodu -- albo ją przenosić do innej sekcji, albo dopisywać gettery. Kod i tak jest twój i masz nad nim pełną kontrolę. A potem jeszcze testy się trudniej pisze.

A co do re-używania klas w innych projektach, to rzeczywiście kiedykolwiek się to wam zdażyło? Bo z mojego doświadczenia to się zawsze i tak kończy jej przerabianiem.

Link do komentarza
Share on other sites

deshipu, wcale mnie nie dziwi, że dla programisty Pythona taki podział wydaje się niepotrzebny 🙂 To trochę inne podejście do programowania. Tobie wydaje się sztuczny podział na część prywatną i publiczną, dla mnie koszmarne jest że cała klasa jest widoczna.

Ogólnie podział ten ma sens głównie na etapie projektowania. Część publiczna to interfejs, czyli to co jest widoczne na zewnątrz klasy. Elementy prywatne są tylko implementacją - nie mają znaczenia dla użytaczności i dlatego są niejako ukryte. Jęśli są napisane brzydko, mają nieeleganckie nazwy itd. można to wybaczyć. Dopóki klasa poprawnie implementuje zadeklarowany interfejs, jej implementacja nie ma znaczenia (albo raczej ma, ale to nie jest krytyczne).

Faktycznie, jeśli piszemy kod tylko dla siebie i tylko raz chcemy go wykorzystać, podział na pliki, ustalanie widoczności elemtentów może wydawać się niepotrzebne.

Ma to jednak kilka zalet. Po pierwsze nigdy nie wiadomo, czy z czasem projekt nie stanie się większy i czy nie będziemy chcieli go umieścić na githubie czy też przyłączyć większej liczby osób do zespołu. Widziałem kiepsko zaprojektowane klasy, które ktoś napisał a inni używali zupełnie nieprawidłowo - bo uważali że tak można.

Druga moim zdaniem zaleta, to okazja do nauki - pisząc dla siebie elegancki kod mamy okazję poćwiczyć umiejętności które przydają się w większych projektach.

I wracając do ponownego użycia klas - mi się to zdarzało, chociaż w małych, własnych projektach faktycznie niezbyt często. Ale już w większych, czysto zawodowych, takie działanie to codzienność, Bardzo często kod jest wykorzystywany przez kilka, czy kilkanaście a może i kilkadziesiąt projektów jednocześnie - skrypty budujące dany program wybierają które moduły mają zostać włączone. Wtedy jedna klasa jest włączania do bardzo wielu programów.

Często wykorzystuje się też klasy do budowania dla różnych środowisk - przykładowo inna wersja do debugowania, inna produkcyjna. W przypadku projektów wbudowanych, testy jednostkowe oraz wiele testów wykonuje się na PC używając innych klas łączących ze sprzętem (HAL). Wtedy ten sam kod jest czasem kompilowany np. gcc i uruchamiany na x86, a innym razem na architekturze docelowej, przykładowo ARM.

Jak chodzi o przerabianie interfejsu na potrzeby testów, to nie jest wada stosowania metod prywatnych, ale efekt niepoprawnego zaprojektowania interfejsu klasy.

Link do komentarza
Share on other sites

Wypraszam sobie takie ad hominem w stylu "dla programisty Pythona". Pomijając to, że programuję w wielu językach, chyba dla jakości dyskusji lepiej będzie założyć, że nie wiemy od kogo pytanie padło, wtedy możemy się skupić na merytorycznych faktach.

Podział na interfejs i implementacje jak najbardziej jest potrzebny i oczywiście na etapie projektowania to się zawsze robi, niezależnie od tego na co pozwala akurat dany język. Ale to się ma nijak do sztucznych ograniczeń języka. To, czy dany atrybut lub metoda są publiczne czy prywatne w zupełności załatwia konwencja nazw i dokumentacja. Przecież to jest mój własny kod, to tak jak bym we własny mieszkaniu zawsze zamykał na klucz wszystkie drzwi. To nie ma sensu, bo jak będę chciał się do danego elementu dostać, to go sobie zmienię na publiczny -- tylko niepotrzebnie z tym więcej roboty i potem powstają potworki, bo się komuś nie chciało zmieniać.

To, że zawsze należy pisać czysty kod jest oczywistą oczywistością i nie musisz mnie do tego przekonywać. Dzielenie na moduły, wydzielanie bibliotek, projektowanie API dla każdej, etc. -- jasne, to jest bardzo ważna część programowania. Ale nie o to pytam. Mnie dziwi jaką wartość dodaną daje błąd w stylu "ten atrybut jest prywatny, nie możesz go tu użyć dopóki nie zmienisz swojego kodu żeby nie był prywatny". Jeszcze rozumiem gdyby nazwa była po prostu niewidoczna -- wtedy miałoby to jakiś sens, bo unikamy konfliktów nazw pomiędzy API a implementacją i nie zaśmiecamy sobie przestrzeni nazw. Ale nie jest -- jest widoczna, tylko niedostępna. Nie rozumiem jaka jest w tym momencie zaleta.

Co do reużywania klas, to oczywiście jak specjalnie napiszesz bibliotekę, framework, abstraction layer, etc. -- to tam będziesz mieć uniwersalne klasy przeznaczone do użycia w wielu programach, i to jest oczywiste. Ja mam wątpliwości co do ponownego użycia klas, które napisaliśmy w ramach jakiegoś konkretnego projektu. Po prostu w ciągu mojej kariery programistycznej to się nigdy dobrze nie kończyło i zawsze się na koniec okazywało, że potrzeby są niby podobne, ale jednak nie takie same. Stąd moje wątpliwości.

Co do testów natomiast, całkowicie się z tobą nie zgadzam. Oczywiście testy integracyjne, które testują tylko API nie powinny zaglądać głębiej i powinny się zadowolić tym, co jest na wierzchu. Ale testy jednostkowe z samej swojej definicji mają testować pojedyncze elementy implementacji, więc żeby to miało jakikolwiek sens muszą zaglądać w bebechy. I nie, nie chcesz tak projektować klasy, żeby te rzeczy były publiczne -- one mają być prywatne, ale przetestowane.

Link do komentarza
Share on other sites

Nie chciałem Cię w żaden sposób urazić pisaniem o Pythonie. Chodziło mi tylko o zwrócenie uwagi na inny paradygmat programowania. To na co pozwala / wspiera dany język nie ma z tym nic wspólnego. W Pythonie można stosować prorgamowanie funkcyjne, a w czystym C obiektowe. Można też w C++ napisać program czysto strukturalnie.

Natomiast większość osób ma swój "natywny" język i nawet pisząc w innych używa konstrukcji charakterystycznych dla ich języka ojczystego.

Stąd było moje stwierdzenie odnośnie programisty Pythona - to nie obelga, po prostu sposób myślenia.

Do czego są wykorzystywane i użyteczne metody prywatne uczą na studiach informatycznych, nie będę do tego ani zachęcał ani robił wykładu - to po prostu jeden ze sposobów programowania. W sumie ani lepszy, ani gorszy od innych.

Link do komentarza
Share on other sites

Nie czuję się urażony, chciałem tylko zaznaczyć, że dyskusja może być ciekawsza jeśli podejdzie się do tematu bardziej abstrakcyjnie. Argument "bo tak uczą na studiach" też mnie raczej nie przekonuje. Studia informatyczne i matematyczne skończyłem, a nadal nie widzę zysku z takich ograniczeń na etapie pisania kodu (nie na etapie projektowania) w praktyce. Ciekaw jestem praktycznych doświadczeń innych, bo być może to jest jedna z tych rzeczy, która prawdziwa była kiedyś i miała sens, a potem to już po prostu tak zostało i nikt tego nie kwestionuje...

Link do komentarza
Share on other sites

Ok, więc przykład praktyczny.

Mamy dość skomplikowaną metodę - fajnie byłoby ją podzielić na kilka mniejszych. Nie są one dostępne poza klasą, to po prostu podział kodu. Nie chcemy, żeby ktokolwiek miał do tego dostęp. Jeśli zadeklarujemy jako prywatną, sami nie będziemy mieli pokusy jej wywoływania i inni też nie powinni.

Inny przykład - mamy kilka metod w interfejsie, każda metoda ma inne paramtry, które musi pobrać, sprawdzić, a później coś wykonać. To "coś" jest wspólne dla wielu metod, ale nie powinno być wywoływane bez sprawdzania. Znowu ograniczony dostęp się przydaje - pozwala na uniknięcie powtarzania kodu, a jednocześnie nie udostępnia niebezpiecznej funkcji na zewnątrz.

Pewnie sporo innych przykładów można byłoby wymyślić...

Link do komentarza
Share on other sites

Ale przecież dokładnie to samo możesz osiągnąć nie oznaczając jej jako "prywatnej" -- wystarczy, że jest nazwana/udokumentowana odpowiedno (w Googlowym stylu do C++ na przykład i tak wszystkie prywatne rzeczy nazywasz z podkreślnikiem na końcu). Argument o "pokusie" do mnie nie przemawia, bo jak będziesz chciał tę metodę wywołać, to i tak ją wywołasz -- zmienisz ją na publiczną, w końcu to jest twój własny kod. Skoro sam napisałeś ten kod, to wiesz, że jest "niebezpieczna" i czym grozi jej wywoływanie.

To samo zresztą, jak nie piszesz kodu sam, ale współpracujesz z rozgarniętymi ludźmi i/lub robisz review kodu (nie wyobrażam sobie pracy w zespole bez tego już). Jedyny przypadek, kiedy takie "zamykanie" dostępu mogłoby mieć sens, to jak jesteś Wielkim Architektem piszącym bibliotekę do użytku dla niedorozwiniętych studentów pracujących na pół etatu w biedronce i polegających przy pracy głównie na funkcji autouzupełniania w IDE?

Link do komentarza
Share on other sites

Więc potraktuj oznaczanie private jako po prostu dokumentację. Jak napisałem wcześniej - każdy język ma swoje charakterystyczne cechy, a osoby go używające mają pewne nawyki. Ale wszystko można robić na różne sposoby i dzięki temu świat jest bardziej różnorodny.

Link do komentarza
Share on other sites

Ale przecież nie o to chodzi. Wiadomo, każdy język jest jaki jest i pisze się w nim kod tak, jak tego język wymaga. Przez to jedne języki nadają się lepiej do jednych zastosowań, a inne do inncyh. Ale zakładam, że to nie zostało zaprojektowane tak a nie inaczej przez rzucanie monetę, tylko jednak ktoś się nad tym zastanawiał i podjął decyzję na jakiejś podstawie. I zastanawiam się, czy podstawą były jakieś rzeczywiste praktyczne korzyści, czy cargo cult wcześniejszych tradycyjnych rozwiązań.

Stąd moje pytanie do bardziej doświadczonych użytkowników o praktyczną przydatność. Takie przykłady, jak podałeś -- bardzo dziękuję -- tylko te konkretne akurat działają tak samo dobrze bez tej cechy języka.

Swoją drogą, mógłbym to traktować jak dokumentację, gdyby nie zawadzało w praktyce. A zawadza. Właśnie ostatnio miałem z tym zderzenie, którego ostatecznym efektem jest kod taki jak https://github.com/bbcmicrobit/micropython/pull/377/commits/e88e3b2f6c579eab0eafda02242092bff51f6934#diff-cb0496c3b461838d030742ce3abffe2fR31 gdzie musiałem zdefiniować własną podklasę i zrzutować typ tylko po to, żeby móc użyć prywatnego atrybutu, bo autor HAL-a nie przewidział, że to może być potrzebne.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.