Главный недостаток предыдущей версии было резкое включение мощного вентилятора. Из-за высокого уровня постороннего шума при работе мощного вентилятора на малых оборотах, мне пришлось добавить постоянно работающий тихий маломощный вентилятор. После перебора нескольких видов вентиляторов с алиэкспресс (рассматривались только модели 120*120*38) нашёлся супервентилятор San Ace 9SG1212P1G06:
При разработке данного устройства я обнаружил ещё пару интересных особенностей digispark. Все они вытекают из главной фишки, возможности прошивки платы от компьтера через стандарный USB.
Под подключение tm1637 я выделил под неё выводы 1 и 3. С первым проблем не было, а вот 3й используется при подключении к USB. В итоге при подключении к разным источникам питанияс присоединенным tm1637 скетч иногда зависал при включении и не стартовал. Причина в том, что digispark 4 секунды ждёт подключения к компьютеру, а tm1637 данные не только принимает, но и передаёт. В итоге загрузчик думает, что его сейчас прошивать будут и не запускает основной код. Решение логическая развязка:
Следующая проблема запуска digispark в том, что на время ожидания прошивки - 4 сек - его выходы находятся в подвешенном состоянии, не притянуты ни к земле, ни к 5 Вольтам. В чём проявилась проблема - вентиляторы крутятся на минимальных оборотах при входе PWM, притянутом к земле, в результат при включении вентиляторы за 4 сек пытались раскрутиться до максимума, что немного шумновато :) Решение та же логическая развязка. Сперва попробовал вариант с инверсией. К тому времени пришли с китая маломощные полевики 2sk3019, попробовал собрать на нём:
Ещё была проблема, что tm1637 не работал, пока я с платы digispark не выпаял резистор подтягивающий выход 3 к 5 Вольтам, но это ошибочный путь, более правильный логическая развязка.
Поскольку планировалось ставить несколько мощных вентиляторов 4 шт * 12 Вольт * 4 Ампера = 192 Ватта :) силовой части пришлось уделить дополнительное внимание. Да конечно, большую часть времени вентиляторы работают практически на ХХ, но если вдруг приспичит развить максимальную мощность не хотелось бы фейерверков. Начал с разьёма подключения вентилятора, заказал тройники с алиэкспресса:
Вместо подключения питания от SATA разъёма, который сам по себе небольшого сечения, да ещё и бюджет линии БП не резиновый, взял провод подачи питания на видеокарту 6 pin. Разъём можно или взять с б\у видеокарты с авито, или закать на али:
Схема выглядит следующим образом:
Плата до добавления двух tc4420 выглядела так:
При практической эксплутации индикатора на максимальной яркости плата digispark сильно грелась, причина была в высокой нагрузке на преобразователь 12 Вольт -> 5 Вольт, отчего пришлось программно убавить яркость индикатора. В общем при большом количестве потребителей 5 Вольт желательно предусмотреть отдельную линию.
У данного устройства было две версии кода, промежуточную приводь смысла не вижу, сразу окончательная:
#include <core_adc.h> #define CLK 3 #define DIO 1 #define tm1637bit(b) (1 << (b)) #define _dash 0x40 //- #define _degree 0x63 #define _low_degree 0x5c #define avr_iterations_pow2 12 //1 = 2, 10 = 1024 const byte tm1637translator[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7f, 0x39, 0x3f, 0x79, 0x71, 0}; const unsigned char lm19translator[380] = { 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, 252, 251, 251, 250, 249, 248, 248, 247, 246, 245, 244, 244, 243, 242, 241, 241, 240, 239, 238, 237, 237, 236, 235, 234, 233, 233, 232, 231, 230, 229, 229, 228, 227, 226, 226, 225, 224, 223, 222, 222, 221, 220, 219, 218, 218, 217, 216, 215, 214, 214, 213, 212, 211, 211, 210, 209, 208, 207, 207, 206, 205, 204, 203, 203, 202, 201, 200, 199, 199, 198, 197, 196, 195, 195, 194, 193, 192, 191, 191, 190, 189, 188, 187, 187, 186, 185, 184, 183, 183, 182, 181, 180, 179, 179, 178, 177, 176, 175, 175, 174, 173, 172, 171, 171, 170, 169, 168, 167, 167, 166, 165, 164, 163, 163, 162, 161, 160, 159, 159, 158, 157, 156, 155, 155, 154, 153, 152, 151, 150, 150, 149, 148, 147, 146, 146, 145, 144, 143, 142, 142, 141, 140, 139, 138, 138, 137, 136, 135, 134, 133, 133, 132, 131, 130, 129, 129, 128, 127, 126, 125, 125, 124, 123, 122, 121, 120, 120, 119, 118, 117, 116, 116, 115, 114, 113, 112, 111, 111, 110, 109, 108, 107, 107, 106, 105, 104, 103, 102, 102, 101, 100, 99, 98, 98, 97, 96, 95, 94, 93, 93, 92, 91, 90, 89, 88, 88, 87, 86, 85, 84, 84, 83, 82, 81, 80, 79, 79, 78, 77, 76, 75, 74, 74, 73, 72, 71, 70, 69, 69, 68, 67, 66, 65, 64, 64, 63, 62, 61, 60, 59, 59, 58, 57, 56, 55, 54, 54, 53, 52, 51, 50, 49, 49, 48, 47, 46, 45, 44, 44, 43, 42, 41, 40, 39, 39, 38, 37, 36, 35, 34, 34, 33, 32, 31, 30, 29, 28, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 19, 18, 18, 17, 16, 15, 14, 13, 12, 12, 11, 10, 9, 8, 7, 7, 6, 5, 4, 3, 2}; byte old_pwm; void CLKDIO11(){ // *(byte*)0x38 |= tm1637bit(CLK) + tm1637bit(DIO); CLK1(); DIO1(); } void CLK1(){//inverse *(byte*)0x38 |= tm1637bit(CLK); } void DIO1(){ *(byte*)0x38 |= tm1637bit(DIO); } void CLK0(){//inverse *(byte*)0x38 &= 255 - tm1637bit(CLK); } void DIO0(){ *(byte*)0x38 &= 255 - tm1637bit(DIO); } void tm1637send(byte v){ for(byte i = 0; i < 8; i++){ CLK0(); if( v & 1 ){ DIO1(); }else{ DIO0(); } v >>= 1; CLK1(); } CLK0(); CLKDIO11(); DIO0(); } void tm1637out(byte tablo[4], byte howmuch){ CLKDIO11(); DIO0(); CLK0(); tm1637send( 0xc0); tm1637send(tablo[0]); tm1637send(tablo[1]); tm1637send(tablo[2]); tm1637send(tablo[3]); DIO0(); CLK0(); CLKDIO11(); CLKDIO11(); CLKDIO11(); DIO0(); CLK0(); tm1637send(0x88 + (howmuch & 7)); DIO0(); CLK0(); CLKDIO11(); CLKDIO11(); } void setup() { pinMode(0, OUTPUT); digitalWrite(0, LOW);//pwm pinMode(CLK, OUTPUT); pinMode(2, INPUT);//t in pinMode(DIO, OUTPUT); pinMode(4, INPUT);//t out byte tablo[4] = {_dash, _dash, _dash, _dash}; tm1637out(tablo, 7); } void loop() { int t_in, t_out, diff; word new_pwm; long avr_t_in, avr_t_out; avr_t_in = 0; avr_t_out = 0; for(int c = 0; c < (1 << avr_iterations_pow2); c++){ ADC_SetInputChannel((adc_ic_t) 1); ADC_StartConversion(); while( ADC_ConversionInProgress() ); avr_t_in += ADC_GetDataRegister(); ADC_SetInputChannel((adc_ic_t) 2); ADC_StartConversion(); while( ADC_ConversionInProgress() ); avr_t_out += ADC_GetDataRegister(); } t_in = avr_t_in >> avr_iterations_pow2; t_out = avr_t_out >> avr_iterations_pow2; if( t_in >= 379 ){ t_in = 379; } t_in = lm19translator[t_in]; if( t_out >= 379 ){ t_out = 379; } t_out = lm19translator[t_out]; diff = (t_out - t_in); if( diff <= 20 ){ new_pwm = 0; }else{ if( diff >= 70 ){ new_pwm = 100; }else{ new_pwm = diff - 20; new_pwm = new_pwm << 1; } } if( new_pwm >= 100 ) new_pwm = 254; if( new_pwm < old_pwm ){ new_pwm = old_pwm - ((old_pwm - new_pwm) >> 3) - 1; } analogWrite(0, new_pwm); old_pwm = new_pwm; byte tablo[4] = {0, 0, 0, 0}; word x = 0; byte x100 = 0, x10 = 0; x = t_in; if( (x & 1) > 0 ){ tablo[2] = tm1637translator[5]; } else{ tablo[2] = tm1637translator[0]; } x >>= 1; x100 = x10 = 0; if( x > 999 ) x = 999; while( x >= 100 ){ x -= 100; x100++; } if( x100 == 0 ) x100 = 17; while( x >= 10 ){ x -= 10; x10++; } tablo[0] = tm1637translator[x10]; tablo[1] = tm1637translator[x] + 128; tablo[3] = _low_degree; tm1637out(tablo, 5); delay(1000); x = t_out; if( (x & 1) > 0 ){ tablo[2] = tm1637translator[5]; } else{ tablo[2] = tm1637translator[0]; } x >>= 1; x100 = x10 = 0; if( x > 999 ) x = 999; while( x >= 100 ){ x -= 100; x100++; } if( x100 == 0 ) x100 = 17; while( x >= 10 ){ x -= 10; x10++; } tablo[0] = tm1637translator[x10]; tablo[1] = tm1637translator[x] + 128; tablo[3] = _degree; tm1637out(tablo, 5); delay(1000); tablo[0] = 0; x = new_pwm; x100 = x10 = 0; if( x > 999 ) x = 999; while( x >= 100 ){ x -= 100; x100++; } if( x100 == 0 ) x100 = 17; while( x >= 10 ){ x -= 10; x10++; } tablo[1] = tm1637translator[x100]; tablo[2] = tm1637translator[x10]; tablo[3] = tm1637translator[x]; tm1637out(tablo, 5); }
Пояснения по коду - отражается температура на входе, потом на выходе, затем уровень PWM сигнала, доли от 256. Алгоритм расчета уровня PWM - вычитаем из выходной температуры входящую, из разницы вычитаем 10, если больше 0, то умножаем на 4. Замер температуры идёт с максимальной точностью - 0.5 градуса. Из приколов сперва мерял температуру один раз, разброс был до трёх градусов:
Ещё из интересных фич - при сбросе уровня он снижается за одну итерацию на 1/8 + 1 пункт. Это сделано для плавного уменьшения шума, эффект от этого сугубо положительный. Итог радует:
По итогу устройство выполняет все необходимые функции и при необходимости легко перепрошивается под новые условия.