free hit counter code

КОНТРОллер ветрогенератора

Схема устройства

Принципы работы контроллера

Контроллер предназначен для управления зарядом батареи от ветрогенератора, предотвращая ее возможный перезаряд, одновременно защищая ветрогенератор от возможного "ухода в разнос" в случае полного заряда батареи, отсутствия нагрузки или сильного ветра, показывает напряжение батареи, зарядный ток и мощность, отдаваемую ветрогенератором в батарею и нагрузку. Предусмотрена индикация режимов работы на LCD-дисплее, а также с помощью светодиода, изменяющего свой цвет от зеленого через желтый в красный в зависимости от тока ветрогенератора и режима работы контроллера. Контроллер управляет внешним вентилятором обдува, который включается в случае переброски части энергии ветрогенератора во внешнюю нагрузку. Подсветка индикатора может быть включена постоянно, либо включаться по нажатию кнопки и выключаться через определенное время (задается в меню). Настройки параметров контроллера, а также все необходимые калибровки производятся с помощью текстового меню, управляемого единственной кнопкой.

 

Основной принцип работы контроллера заключается в постоянном измерении напряжения на батарее, а также тока, поступающего от ветрогенератора. Одновременно измеряется текущая мощность, отдаваемая ветрогенератором в батарею и нагрузку. Подсчитывается также количество электроэнергии в Ватт-часах, выработанной ветрогенератором и переданной в нагрузку или использованной для заряда батареи. В случае достижения напряжения на батарее определенного порога (задается в меню) контроллер включает ШИМ-генератор, с помощью которого подключает к ветрогенератору внешнюю нагрузку, которая отбирает часть мощности на себя и притормаживает ветрогенератор, не давая ему "уйти в разнос" при сильном ветре и полном заряде батареи. Скважность ШИМ постепенно увеличивается, увеличивая таким образом нагрузку на генератор до тех пор, пока напряжение на батарее не упадет ниже указанного предела. Предусмотрено также принудительное включение тормоза с помощью выключателя S1.

Описание принципиальной схемы

Ветрогенератор подключается к разъему J1 с обязательным соблюдением полярности. То есть можно подключать только ветрогенератор который дает выпрямленное (постоянное) напряжение. Резисторы R1 и R4 образую делитель для измерения напряжения, вырабатываемого ветрогенератором. Цепочка R1 C6 образует ФНЧ с частотой среза менее 50 Гц для исключения радиопомех и наводок от сети переменного тока. В текущей прошивке напряжение на выходе ветрогенератора измеряется, но не используется. Измерительная цепь оставлена на будущее.

 

Аналогичная измерительная цепь служит для измерения напряжения батареи (R3, R5, C7). 

 

Диоды D1 и D2 служат для защиты аккумуляторной батареи от разряда внешней нагрузкой, а также от короткого замыкания при подключении ветрогенератора. Аккумуляторная батарея подключается к разъему J2 также с обязательным соблюдением полярности.

 

Модуль U2 - импульсный понижающий преобразователь напряжения, который формирует стабилизированное напряжение +5В, используемое для питания модуля Arduino Pro Mini. Напряжение +5В подается на вход RAW модуля Arduino. Опорное напряжение +3.3В формируется внутренним стабилизатором модуля Arduino и снимается с вывода Vcc.

 

Измерение тока производится модулем U1, собранным на микросхеме ACS712-5 в стандартном включении. Цепочка R2 C3 образует ФНЧ с частотой среза менее 50 Гц.

 

Нагрузка-шунт подключается к разъему J3. Мощность шунта должна быть не менее номинальной мощности ветрогенератора. В моем случае используется ветрогенератор с номинальной мощностью 200 Вт. В качестве шунта используются три параллельно включенные 12-вольтовые лампы-споты мощностью 75 Вт каждая. Подключение нагрузки производится с помощью ШИМ-управляемого ключа, собранного на транзисторах Q1 и Q2. Транзистор Q2 необходимо установить на небольшой радиатор. С помощью выключателя S1 можно подключить шунт к ветрогенератору минуя управляющий ключ. В случае использования резистивного шунта меньшей мощности может понадобиться дополнительный обдув шунта. Вентилятор подключается к разъему J4 и управляется ключом на транзисторе Q3. 

 

LCD-дисплей 16х2 подключается к модулю Arduino по интерфейсу I2C. Светодиод LED1 содержит внутри два раздельно управляемых светодиода красного и зеленого цветов. LED 1 светится зеленым цветом в случае, если ветрогенератор вырабатывает энергию, достаточную для заряда батареи или питания полезной нагрузки. Диод загорается в случае, если ток от ветрогенератора превышает 50 мА и интенсивность свечения пропорциональна току. При включении торможения ветрогенератора загорается красный светодиод и интенсивность его свечения пропорциональна степени торможения.

 

Кнопка S1 служит для управления контроллером, перевода его в режим установок и изменения параметров.

 

Разъем J5 используется при программировании контроллера.

Меню и настройка параметров контроллера

В обычном состоянии подсветка дисплея выключена. Для включения подсветки необходимо однократно нажать кнопку управления. В течение некоторого времени подсветка будет включена, после чего автоматически выключится.

 

 


(С) 2018 Victor Luchansky RK3BX

При использовании материалов ссылка на авторство и первоисточник обязательны

Файлы проекта

Скачать
Схема контроллера ветрогенератора v 2.0
в формате PDF
Controller-20180114_2.pdf
Adobe Acrobat документ 78.8 KB
Скачать
Схема контроллера ветрогенератора v 2.0
в формате Multisim 13
Controller.ms13
exe Файл 656.4 KB
Скачать
Откомпилированный софт
Можно лить прямо в контроллер
WindController.ino.eightanaloginputs.hex
Текстовый документ 39.8 KB

Используемые библиотеки:

Скачать
Библиотека Ticker
Ticker-master.zip
Сжатый архив в Zip формате 7.6 KB
Скачать
Библиотека OneButton
OneButton-master.zip
Сжатый архив в Zip формате 12.3 KB
Скачать
Библиотека LicquidCrystal_I2C
LiquidCrystal_I2C_V112.zip
Сжатый архив в Zip формате 19.4 KB

Скетч для Arduino Pro-mini


#include <LiquidCrystal_I2C.h>
#include "Ticker.h"
#include "OneButton.h"
#include <EEPROM.h>

#define PWMpin 11
#define FANpin PD2
#define redPWMpin PD5
#define greenPWMpin PD6
#define buttonpin PD7

enum cStates : uint8_t{SNOOZ=0, BULK=1, FLOAT=2};
cStates cState = SNOOZ;
const char* cStatesNames[3]={"SNOOZ","BULK ","FLOAT"};

enum mStates : uint8_t{noMENU=0, MenuVFloat=1,MenuBLTimer=2, MenuI0Calib=3,\
MenuVInCalib=4, MenuVBattCalib=5, MenuClearPM=6, MenuReset=7};
mStates mState = noMENU;

enum dStates : uint8_t{DISP1 = 0, DISP2 = 1};
dStates dState = DISP1;

float vBatt=12.0;
float vIn;
float iIn;
float pIn, pCharge;
uint8_t blTimer=20;
float vFloat = 13.8;
uint16_t iShift = 509;
float iScale = 0.0264;
float vInScale = 14.333;
float vBattScale = 6.458;
uint8_t backCounter;
uint8_t PWM=255;

void Tick1s();
void Tick5s();
void Tick10s();
void TickBL();
void stopMenu();
void SaveData();
void Display1();
void Display2();

LiquidCrystal_I2C lcd(0x27,16,2);
OneButton leftButton(PD7, true);
Ticker timer1s(Tick1s, 1000,0, MILLIS);
Ticker timer5s(Tick5s, 5000,0, MILLIS);
Ticker timer10s(Tick10s, 10000,0, MILLIS);
Ticker timerBL(TickBL, blTimer*1000,1, MILLIS);
Ticker timerMenu(stopMenu, 5000,1, MILLIS);
Ticker timer1h(SaveData, 60*60*1000,0, MILLIS);

void LoadFromEEProm(){
   int eeAddress = 0;
   uint8_t firstByte;
   EEPROM.get(eeAddress, firstByte);
   if (firstByte==17){
     lcd.clear();
     lcd.print("LOADING");
     lcd.setCursor(0,1);
     lcd.print("FROM EEPROM");
     delay(1000);
     eeAddress+=sizeof(uint8_t);
     EEPROM.get(eeAddress,pCharge);
     eeAddress+=sizeof(float);
     EEPROM.get(eeAddress,blTimer);
     eeAddress+=sizeof(uint8_t);
     EEPROM.get(eeAddress,vFloat);
     eeAddress+=sizeof(float);
     EEPROM.get(eeAddress,iShift);
     eeAddress+=sizeof(uint16_t);
     EEPROM.get(eeAddress,vInScale);
     eeAddress+=sizeof(float);
     EEPROM.get(eeAddress,vBattScale);
   }
   else{
     lcd.clear();
     lcd.print("RESETTING");
     lcd.setCursor(0,1);
     lcd.print("TO DEFAULT");
     delay(2000);
     blTimer=20;
     vFloat=13.8;
     iShift=509;
     vInScale=14.333;
     vBattScale=6.458;
     SaveToEEProm();
   }
}

void SaveToEEProm(){
   int eeAddress = 0;
   uint8_t firstByte = 17;
   lcd.clear();
   lcd.print("SAVING");
   lcd.setCursor(0,1);
   lcd.print("TO EEPROM");
   delay(2000);
   EEPROM.put(eeAddress, firstByte);
   eeAddress+=sizeof(uint8_t);
   EEPROM.put(eeAddress,pCharge);
   eeAddress+=sizeof(float);
   EEPROM.put(eeAddress,blTimer);
   eeAddress+=sizeof(uint8_t);
   EEPROM.put(eeAddress,vFloat);
   eeAddress+=sizeof(float);
   EEPROM.put(eeAddress,iShift);
   eeAddress+=sizeof(uint16_t);
   EEPROM.put(eeAddress,vInScale);
   eeAddress+=sizeof(float);
   EEPROM.put(eeAddress,vBattScale);
}

void SaveData(){
   int eeAddress = 0;
   uint8_t firstByte = 17;
   EEPROM.put(eeAddress, firstByte);
   eeAddress+=sizeof(uint8_t);
   EEPROM.put(eeAddress,pCharge);
}

void Tick5s()
{
  if (dState==DISP1){
  dState=DISP2;
  }
  else{
  dState=DISP1;
  }
}

void Tick10s()
{
pCharge+=(pIn/360);
}

void TickBL()
{
  lcd.noBacklight();
  timerBL.stop();
}

void ClearRow(uint8_t row){
  lcd.setCursor(0,row);
  lcd.print("                ");
}

void Display1(){
  lcd.setCursor(0,0);
  lcd.print("Vb:      ");
  lcd.setCursor(3,0);
  lcd.print(String(vBatt,1)+"V");
  lcd.setCursor(9,0);
  lcd.print(cStatesNames[cState]);
  lcd.setCursor(0,1);
  lcd.print(" I:      ");
  lcd.setCursor(3,1);
  lcd.print(String(iIn,2)+"A");
  lcd.setCursor(9,1);
  lcd.print("P:      ");
  lcd.setCursor(11,1);
  lcd.print(String(pIn,1)+"W");
}

void Display2(){
  lcd.setCursor(0,0);
  lcd.print("CHARGED:        ");
  lcd.setCursor(9,0);
  lcd.print(String(pCharge,0)+"Wh");
  lcd.setCursor(0,1);
  lcd.print("LOADPWM:        ");
  lcd.setCursor(9,1);
  lcd.print(String(255-PWM,DEC));
}

void DisplayMenu1(){
  lcd.setCursor(0,0);
  lcd.print("FLOAT VOLTAGE:  ");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print((String(vFloat,1))+" V");
  timerMenu.start();  
}

void DisplayMenu2(){
  lcd.setCursor(0,0);
  lcd.print("BACKLIT TIMEOUT:");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print((String(blTimer))+" s");
  timerMenu.start();  
}

void DisplayMenu3(){
  lcd.setCursor(0,0);
  lcd.print("ZERO CURRENT:   ");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print((String(iIn,2))+" A, dI:"+String(iShift));
  timerMenu.start();  
}

void DisplayMenu4(){
  lcd.setCursor(0,0);
  lcd.print("INPUT VOLTG CAL:");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print((String(vIn,3))+" V:"+String(vInScale,3));
  timerMenu.start();  
}

void DisplayMenu5(){
  lcd.setCursor(0,0);
  lcd.print("BATTERY VLTG CAL");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print((String(vBatt,3))+" V:"+String(vBattScale,3));
  timerMenu.start();  
}

void DisplayMenu6(){
  lcd.setCursor(0,0);
  lcd.print("CLEAR PWR METER ");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print(String(backCounter,DEC));
}

void DisplayMenu7(){
  lcd.setCursor(0,0);
  lcd.print("RESET TO DEFAULT");
  ClearRow(1);
  lcd.setCursor(0,1);
  lcd.print(String(backCounter,DEC));
}

void startMenu(){
  timer5s.stop();
  timerBL.stop();
  lcd.backlight();
  mState=MenuVFloat;
  DisplayMenu1();
}

void stopMenu(){
  timer1s.stop();
  lcd.clear();
  switch(mState){
    case MenuClearPM:{
      lcd.print("CLEARING");
      lcd.setCursor(0,1);
      lcd.print("POWER METER");
      delay(1000);
      pCharge=0.0;
      SaveToEEProm();
      mState=noMENU;
      timer1s.start();
      timer5s.start();
      timerBL.setInterval(blTimer*1000);  
      if(blTimer>0){timerBL.start();}
      break;
    }
    case MenuReset:{
      lcd.print("RESETTING");
      lcd.setCursor(0,1);
      lcd.print("TO DEFAULT");
      delay(1000);
      uint8_t firstByte = 0;
      EEPROM.put(0,firstByte);
      LoadFromEEProm();
      SaveToEEProm();
      mState=noMENU;
      timer1s.start();
      timer5s.start();
      timerBL.setInterval(blTimer*1000);  
      if(blTimer>0){timerBL.start();}
      break;
    }
  }
  mState=noMENU;
  SaveToEEProm();
  timer1s.start();
  timer5s.start();
  timerBL.setInterval(blTimer*1000);  
  if(blTimer>0){timerBL.start();}
}

void Tick1s(){
  switch(mState){
    case noMENU:{
      switch (dState){ 
        case DISP1:{Display1();break;}
        case DISP2:{Display2();break;}
        }break;
      }
    case MenuClearPM: {backCounter-=1;DisplayMenu6();break;}
    case MenuReset: {backCounter-=1;DisplayMenu7();break;}
    }
}

void lbClick(){
  switch(mState){
  case noMENU:{
    lcd.backlight();  
    if(blTimer>0){timerBL.start();}
    break;}
  case MenuVFloat:{if(vFloat>0.0){vFloat-=0.1;DisplayMenu1();break;}}  
  case MenuBLTimer:{
    if (blTimer!=0){
      blTimer--;
      DisplayMenu2(); 
      break; 
    }
    break;
    }  
  case MenuI0Calib:{
    if (iShift>0){iShift--;}
    DisplayMenu3();
    break;  
    }
  case MenuVInCalib:{
    if(vInScale>=0.001){vInScale-=0.001;}
    DisplayMenu4();
    break;  
    }
  case MenuVBattCalib:{
    if(vBattScale>=0.001){vBattScale-=0.001;}
    DisplayMenu5();
    break;  
    }
  }
}

void lbDoubleClick(){
  switch(mState){
  case MenuVFloat:{vFloat+=0.1;DisplayMenu1();break;}  
  case MenuBLTimer:{
    if (blTimer<30){
      blTimer++;
      DisplayMenu2(); 
      break; 
    }
    break;
    }  
  case MenuI0Calib:{
    if (iShift<1023){iShift++;}
    DisplayMenu3();
    break;  
    }
  case MenuVInCalib:{
    vInScale+=0.001;
    DisplayMenu4();
    break;  
    }
  case MenuVBattCalib:{
    vBattScale+=0.001;
    DisplayMenu5();
    break;  
    }
  }
}

void lbLongPressStart(){
  switch(mState){
  case noMENU:{startMenu();break;}  
  case MenuVFloat:{mState=MenuBLTimer; DisplayMenu2();break;}
  case MenuBLTimer:{mState=MenuI0Calib; DisplayMenu3();break;}
  case MenuI0Calib:{mState=MenuVInCalib; DisplayMenu4();break;}
  case MenuVInCalib:{mState=MenuVBattCalib; DisplayMenu5();break;}
  case MenuVBattCalib:{mState=MenuClearPM; backCounter=5; DisplayMenu6();break;}
  case MenuClearPM:{mState=MenuReset; backCounter=5; DisplayMenu7();break;}
  case MenuReset:{mState=MenuVFloat; DisplayMenu1();break;}  
  }
}

void lbLongPressStop(){
  switch(mState){
  case noMENU:{startMenu();break;} 
  } 
}

void setGreenLED(){
  if (iIn>0.05){
    int greenPWM = (iIn-0.05)*200;
    if (greenPWM>255) {greenPWM=255;}
    analogWrite(greenPWMpin,greenPWM);
  }
  else{
    analogWrite(greenPWMpin,0);
    
  }
}

void setPWM(){
  analogWrite(PWMpin,PWM);
  analogWrite(redPWMpin,(255-PWM)/4);
}

void doSNOOZ(){
  cState=SNOOZ;
  digitalWrite(FANpin,LOW);
  PWM=255;
  setPWM();  
}

void doBULK(){
  cState=BULK;
  digitalWrite(FANpin,LOW);
  PWM=255;
  setPWM();  
}

void doFLOAT(){
  cState=FLOAT;
  digitalWrite(FANpin,HIGH);
  PWM=255;
  setPWM();  
}

void setup()
{
  lcd.init();
  lcd.backlight();
  LoadFromEEProm();
  leftButton.attachClick(lbClick);
  leftButton.attachDoubleClick(lbDoubleClick);
  leftButton.attachLongPressStart(lbLongPressStart);
  leftButton.attachLongPressStop(lbLongPressStop);
  mState=noMENU;
  timer1s.start();
  timer5s.start();
  timer10s.start();
  timerBL.setInterval(blTimer*1000);  
  if(blTimer>0){timerBL.start();}
  timer1h.start();
  pinMode(FANpin, OUTPUT);
  doSNOOZ();
}

void loop(){
  timer1s.update();
  timer5s.update();
  timer10s.update();
  timerBL.update();
  timerMenu.update();
  timer1h.update();
  leftButton.tick();
  int average = 0;
  average=0;
  for(int i = 0; i < 10; i++) {
    average += analogRead(A0)-iShift;
    delay(1);
  }
  iIn=average*0.00264; 
  if (iIn<0){iIn=0;};

//  average=0;
//  for(int i = 0; i < 10; i++) {
//    average += analogRead(A1);
//    delay(1);
//  }
 // vIn=average;
 // vIn=vInScale*average*0.000323558162267839687194525904203;
  average=0;
  for(int i = 0; i < 10; i++) {
    average += analogRead(A2);
    delay(1);
  } 
  vBatt=vBattScale*average*0.000323558162267839687194525904203;
  pIn=vBatt*iIn;
  setGreenLED();
  // switch states here:
  switch(cState){
    case SNOOZ:{
      if (iIn>=0.05){
        doBULK();
        break;
      }
      break;
    }
    case BULK:{
      if (iIn<0.05){
        doSNOOZ();
        break;      
    } 
      if (vBatt>=vFloat){
        doFLOAT();
        break; 
      }
      break;
    }
    case FLOAT:{
      if (vBatt>=vFloat){if (PWM>0){PWM--;setPWM();break;}}
      else{if (PWM<255){PWM++;setPWM();break;} 
        else{if (PWM==255){doBULK();break;}}
        break;} 
      }
  }       
}

Оставить комментарий

Комментарии: 13
  • #1

    Алексей (Вторник, 13 Март 2018 13:57)

    Здравствуйте. А можно побольше информации по контроллеру для ветряка.

  • #2

    Алексей (Среда, 14 Март 2018)

    Скетч при компиляции выдает ошибку, связанную с Ticker.h. Что это может быть? В программировании полный ноль. Ответьте пожалуйста.

  • #3

    Виктор, RK3BX (Среда, 14 Март 2018 19:02)

    Алексей, возможно у Вас в Arduino IDE не установлена библиотека Ticker. Взять ее можно здесь:
    https://github.com/esp8266/Arduino/tree/master/libraries/Ticker
    Скорее всего вам также потребуется установить библиотеки LiquidCrystal_I2C и OneButton
    Ищутся Гуглем.

    73! Виктор

  • #4

    Алексей (Четверг, 22 Март 2018 03:52)

    Здравствуйте. А продолжение про меню будет? Самое интересное �

  • #5

    Виктор (Четверг, 29 Март 2018 14:05)

    Да, продолжение по меню будет на днях.

  • #6

    Алексей (Воскресенье, 29 Апрель 2018 15:13)

    ...А прошел месяц...

  • #7

    Сергей (Пятница, 23 Ноябрь 2018 19:03)

    как скачать библиотеку Ticker.h ?

  • #8

    Лучанский Виктор Борисович (Вторник, 27 Ноябрь 2018 22:04)

    Сергей, я выложил в разделе "Файлы проекта" архивы используемых библиотек, а также откомпилированную версию прошивки. Надеюсь, что это поможет. :)

  • #9

    Виталий (Воскресенье, 02 Декабрь 2018 15:45)

    Возможно-ли подправить скетч под аккумуляторы на 48 вольт.
    Заранее благодарен

  • #10

    Лучанский Виктор Борисович (Пятница, 07 Декабрь 2018 22:13)

    Контроллер можно переделать на работу как с 24, 36, так и 48-вольтовыми аккумуляторными батареями, но одним изменением скетча тут не обойтись.
    1. Нужно убедиться, что преобразователь напряжения U2 не крякнется от поданного на него с батареи напряжения. В противном случае нужно напряжение на входе преобразователя немного дополнительно подгасить, либо подавать его отдельно от одного аккумулятора, а не от всей сборки.
    2. Использовать вентилятор обдува нагрузки на 24 или 48 вольт, а не на 12 В. Как опция - подключить верхний вывод разъема J4 не ко всей аккумуляторной сборке, а к выводу "нижнего" аккумулятора, то есть подать туда 12 В.
    3. Поставить электролиты C1 и C9 на соответствующее напряжение.
    4. Возможно, что придется заменить транзисторы Q1 и Q2 на более высоковольтные.
    5. Изменить номиналы делителя напряжения батареи. Для 12В батареи номиналы в 51кОм/10 кОм дают коэффициенты деления 10/(10+51)=0.164 Для 24В батареи коэффициент деления нужно увеличить в два раза, т.е. д.б. 0.082 Для 36В батареи 0.055, а для 48В батареи 0.041
    6. То же самое нужно сделать с делителем входного напряжения R1, R4 (Коэффициенты деления можете сами посчитать).
    7. Балластную нагрузку контроллера нужно будет собирать на соответствующее напряжение.
    8. И, наконец, изменения в скетче:
    Достаточно поменять только одну строку (В том случае, если Вы сделали корректные изменения в делителе напряжения батареи):
    vBatt=vBattScale*average*0.000323558162267839687194525904203;
    Для 24В она будет иметь вид:
    vBatt=2*vBattScale*average*0.000323558162267839687194525904203;
    Для 36В она будет иметь вид:
    vBatt=3*vBattScale*average*0.000323558162267839687194525904203;
    Для 48В она будет иметь вид:
    vBatt=3*vBattScale*average*0.000323558162267839687194525904203;
    Можно также сразу заменить строку
    float vFloat = 13.8;
    на соответствие используемой батарее, а именно:
    float vFloat = 27.6; // для 24В батареи
    float vFloat = 41.4; // для 36В батареи
    float vFloat = 55.2; // для 48В батареи
    Перед использованием контроллера его надо будет откалибровать.

  • #11

    Лучанский Виктор Борисович (Пятница, 07 Декабрь 2018 22:15)

    Так как выходное напряжение с ветрогенератора в текущей версии прошивки никак не используется, делитель R1, R4 можно вообще не ставить, и, соответственно, не пересчитывать его на другие напряжения.

  • #12

    Лучанский Виктор Борисович (Пятница, 07 Декабрь 2018 22:17)

    Опечатался. Поправляю:
    Для 48В она будет иметь вид:
    vBatt=4*vBattScale*average*0.000323558162267839687194525904203;

  • #13

    Сергей (Понедельник, 10 Декабрь 2018 03:47)

    Виктор в каком компиляторе делали прошивку для контроллера, или возможно произвести компиляцию в программе прошивки ардуино. И если да то каким образом.