Помогите подправить скетч!

aleks_22
Offline
Зарегистрирован: 18.04.2016

Доброго времени!

Помогите пожалуйста с редактированием кода! Имеется блок питания 0-20в и 0-10А. Мне нужно чтобы ардуино нано 328 управляла 2 независимых друг от друга канала ШИМ, под управлением 1 энкодера. В программе есть 3 режима (Стандарт, Ограничения тока, Защита). При выборе в меню режима (Стандарт) работал и регулировался первый канал ШИМ. а при выборе режима (Ограничения тока) второй канал ШИМ. Режим (Защиты) нужно вывести на свободный пин +5в реле. При регулировки энкодером первого канала ШИМ второй канал был в положении того состояния что и до переключения режима. При нажатии кнопки V/A нужно переключать один из режимов (Стандарт или Ограничения тока)

Помогите пожалуйста очень нужно. Я в этом НОВИЧОК!

/*
Лабораторный блок питания под управлением arduino
*/

#include <LiquidCrystal.h>;
#include <EEPROM.h>
LiquidCrystal lcd(11, 6, 5, 4, 3, 2); //rs, e, d4, d5, d6, d7

// задаем константы

float umax = 20.00; //максимальное напряжение
float umin = 0.00; //минимальное напряжение
float ah = 0.0000; //Cчетчик Ампер*часов
const int down = 10;     //выход валкодера 1/2
const int up =  8;       //выход валкодера 2/2
const int pwm = 9;       //выход ШИМ 
const int power = 7;     //управление релюхой
long previousMillis = 0; //храним время последнего обновления дисплея
long maxpwm = 0;         //циклы поддержки максимального ШИМ
long interval = 500;     // интервал обновления информации на дисплее, мс
int mig = 0;             //Для енкодера (0 стоим 1 плюс 1 минус)
float level = 100;         //"уровень" ШИМ сигнала
float com = 100;
long com2 = 0;
int mode = 0;            //режим (0 обычный, спабилизация тока, защита по току)
float Ioutmax = 1.0;     //заданный ток
int set = 0;             //пункты меню, отображение защиты...
int knopka_a = 0;        //состояние кнопок
int knopka_b = 0;
int knopka_ab = 0;
boolean off = false;
boolean red = false;
boolean blue = false;
float counter = 5;       // переменная хранит заданное напряжение
int disp = 0;            //режим отображения 0 ничего, 1 мощьность, 2 режим, 3 установленный ток, 4 шим уровень
float Uout ;             //напряжение на выходе


int incomingByte;


void EEPROM_float_write(int addr, float val) // запись в ЕЕПРОМ
{  
  byte *x = (byte *)&val;
  for(byte i = 0; i < 4; i++) EEPROM.write(i+addr, x[i]);
}

float EEPROM_float_read(int addr) // чтение из ЕЕПРОМ
{    
  byte x[4];
  for(byte i = 0; i < 4; i++) x[i] = EEPROM.read(i+addr);
  float *y = (float *)&x;
  return y[0];
}

void setup() {          
cli();
DDRB |= 1<<1 | 1<<2;
PORTB &= ~(1<<1 | 1<<2);
TCCR1A = 0b00000010;
//TCCR1A = 0b10100010;
TCCR1B = 0b00011001;
ICR1H = 255;
ICR1L = 255;
sei();
int pwm_rez = 13;
pwm_rez = pow(2, pwm_rez);
ICR1H = highByte(pwm_rez);
ICR1L = lowByte(pwm_rez);

Serial.begin(9600);  

  pinMode(pwm, OUTPUT);  
  pinMode(down, INPUT);  
  pinMode(up, INPUT);  
  pinMode(12, INPUT); 
  pinMode(13, INPUT); 
  pinMode(power, OUTPUT); 
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  // поддерживаем еденицу на входах от валкодера
  digitalWrite(up, 1); 
  digitalWrite(down, 1);
  //поддерживаем еденицу на контактах кнопок
  digitalWrite(12, 1); 
  digitalWrite(13, 1);
  //запуск дисплея
  lcd.begin(16, 2);     
  lcd.print("    WELCOME!    ");

  //загружаем настройки из памяти МК
  counter = EEPROM_float_read(0);
  Ioutmax = EEPROM_float_read(4);
  mode = EEPROM_float_read(12);
  disp = EEPROM_float_read(10);
  //Если в памяти еще нет настроек - задаем что нибудь кроме нулей
  if(counter==0) counter = 5; //5 вольт
  if(Ioutmax==0) Ioutmax = 2; //2 ампера
  
  //включаем реле
  digitalWrite(power, 1);
}

//функции при вращении енкодера
void uup(){ //енкодер +
  if(set==0){//обычный режим - добавляем напряжения
     if(counter<umax) { 
      counter = counter+0.1;//добавляем
     }
  }
  if(set==1){ //переключаем режим работы вперед
   mode = mode+1;
   if(mode>2) mode=2;
  }
  if(set==2){ //настройка тока, добавляем ток
   iplus();
  }
  
    if(set==3){//сброс счетчика А*ч
ah = 0;
set = 0;
disp = 5;
  }

  if(set==4){//сохранение текущих настроек в память
save();
  }
}

void udn(){ //валкодер -
  if(set==0){
   if(counter>umin+0.1)counter = counter-0.1; //убавляем напнряжение
  }
  if(set==1){
   mode = mode-1; //переключаем режим работы назад
   if(mode<0) mode=0;
  }  
  if(set==2){//убавляем ток
   iminus();
  }
}

void iplus(){ 
    Ioutmax = Ioutmax+0.01;
   if(Ioutmax>0.2) Ioutmax=Ioutmax+0.04;
   if(Ioutmax>1) Ioutmax=Ioutmax+0.05;
   
   
   if(Ioutmax>10.00) Ioutmax=10.00;
}

void iminus(){ 
  Ioutmax = Ioutmax-0.01;
   if(Ioutmax>0.2) Ioutmax=Ioutmax-0.04;
   if(Ioutmax>1) Ioutmax=Ioutmax-0.05;
   
   
   if(Ioutmax<0.03) Ioutmax=0.03;
}

void save(){
      lcd.clear();
    lcd.setCursor (0, 0);
    lcd.print(" S A V E  -  OK ");

     EEPROM_float_write(0, counter);
     EEPROM_float_write(4, Ioutmax);
     EEPROM_float_write(12, mode);
     EEPROM_float_write(10, disp);
     //мигаем светодиодами
    digitalWrite(A2, 1);  
    digitalWrite(A3, 1);  
     delay(500);
    digitalWrite(A2, 0); 
    digitalWrite(A3, 0);   
     set = 0; //выходим из меню
}

void loop() //основной цикл работы МК
{
  
  unsigned long currentMillis = millis(); 
  
  /* Вншнее управление */
  if (Serial.available() > 0) {  //если есть доступные данные
        // считываем байт
        incomingByte = Serial.read();
 
    }else{
      incomingByte = 0;
    }
    
    if(incomingByte==97){ //a
    if(counter>umin+0.1)counter = counter-0.1; //убавляем напнряжение
    
    }   
        if(incomingByte==98){ //b
  
    if(counter<umax)       counter = counter+0.1;//добавляем
     
    }
    
     if(incomingByte==99){ //c   
iminus();
     }
     
      if(incomingByte==100){ //d
         iplus();
      }

  if(incomingByte==101) mode = 0;
  if(incomingByte==102) mode = 1; 
  if(incomingByte==103) mode = 2;
  if(incomingByte==104) save();
  if(incomingByte==105){
    digitalWrite(power, 1); //врубаем реле если оно было выключено
     delay(100);
  digitalWrite(A2, 0); //гасим красный светодиод 
       Serial.print('t');
    Serial.print(0);
    Serial.print(';');
  off = false;
  set = 0;//выходим из меню
  }
  
   if(incomingByte==106) off = true;
   if(incomingByte==107) ah = 0;
   
   /* конец внешнего управления */
   
   
  
  //получаем значение напряжения и тока в нагрузке
  float Ucorr = -0.09; //коррекция напряжения, при желании можно подстроить
  float Uout = analogRead(A1) * ((5.0 + Ucorr) / 1023.0) * 5.0; //узнаем напряжение на выходе
  

  
  
  float Iout = analogRead(A0) / 100.00; // узнаем ток в нагрузке
  
  if(Iout==0.01) Iout =  0.03; else 
  if(Iout==0.02) Iout =  0.04; else
  if(Iout==0.03) Iout =  0.05; else
  if(Iout==0.04) Iout = 0.06; else
  if(Iout>=0.05) Iout = Iout + 0.02;
  if(Iout>=0.25)Iout = Iout + 0.01;
  //if(Iout>=1)Iout = Iout * 1.02;
  
  
  
  
  /* ЗАЩИТА и выключение */
  
  if (((Iout>(counter+0.3)*2.0) | Iout>10.1  | off) & set<4 & millis()>100 ) // условия защиты

   {  
     digitalWrite(power, 0); //вырубаем реле
     level = 8190; //убираем ШИМ сигнал
     digitalWrite(A2, 1);      
                
    Serial.print('I0;U0;r1;W0;');
    Serial.println(' ');
     set = 6;
     
    }
    
    
    //Зашита от длительного максимального шим
    if (level==0 & off==false)
    {  
      if(set<4)//если уже не сработала защита
      { 
        maxpwm--; //добавляем +1 к счетчику
        digitalWrite(A2, 1); //светим красным для предупреждения о максимальном ШИМ
      }  
    }
    else //шим у нас не максимальный, поэтому поубавим счетчик
    {
      maxpwm++;
      if(maxpwm>8190)//если счетчик дошел до нуля
      {
        maxpwm = 8190; //таким его и держим
        if(set<4) digitalWrite(A2, 0); // гасим красный светодиод. Перегрузки нет.
      }
    }
  
  
  /* ЗАЩИТА КОНЕЦ */
  
  
  // считываем значения с входа валкодера
  boolean regup = digitalRead(up);
  boolean regdown = digitalRead(down);
  
  if(regup<regdown) mig = 1; // крутится в сторону увеличения
  if(regup>regdown) mig = 2; // крутится в сторону уменшения
  if(!regup & !regdown) //момент для переключения
  { 
    if(mig==1) uup();//+
    if(mig==2) udn(); //-
    mig = 0; //сбрасываем указатель направления
  }

if(mode==0 | mode==1) //если управляем только напряжением (не режим стабилизации тока)
{ 
  
  //Сравниваем напряжение на выходе с установленным, и принимаем меры..
  if(Uout>counter)
  {
    float raz = Uout - counter; //на сколько напряжение на выходе больше установленного...
    if(raz>0.05)
    {
      level = level - raz * 20; //разница большая управляем грубо и быстро!
    }else{
       if(raz>0.015)  level = level -  raz * 3 ; //разница небольшая управляем точно
    }
  }
  if(Uout<counter)
  {
    float raz = counter - Uout; //на сколько напряжение меньше чем мы хотим
    if(raz>0.05)
    {
      level = level + raz * 20; //грубо
    }else{
      if(raz>0.015)  level = level + raz * 3 ; //точно
    }
  }

  if(mode==1&&Iout>Ioutmax) //режим защиты по току, и он больше чем мы установили
  { 
   digitalWrite(power, 0); //вырубаем реле
        Serial.print('t');
    Serial.print(2);
    Serial.print(';');
   
   //зажигаем красный светодиод
   digitalWrite(A2, 1);   
   level = 8190; //убираем ШИМ сигнал
   set=5; //режим ухода в защиту...
  }
  
}
else{ //режим стабилизации тока

  if(Iout>=Ioutmax)
  {
    //узнаем запас разницу между током в нагрузке и установленным током
    float raz = (Iout - Ioutmax); 
    if(raz>0.3) //очень сильно превышено (ток больше заданного более чем на 0,3А)
    {
      level = level + raz * 20; //резко понижаем ШИМ
    }else{    
      if(raz>0.05) //сильно превышено (ток больше заданного более чем на 0,1А)
      {
        level = level + raz * 5; //понижаем ШИМ
      }else{
        if(raz>0.00) level = level + raz * 2; //немного превышен (0.1 - 0.01А) понижаем плавно
      }
    }
  
   
  //зажигаем синий светодиод
  digitalWrite(A3, 1); 
}else{ //режим стабилизации тока, но ток у нас в пределах нормы, а значит занимаемся регулировкой напряжения
digitalWrite(A3, 0);//синий светодиод не светится

  //Сравниваем напряжение на выходе с установленным, и принимаем меры..

  }
  if(Uout<counter)
  {
    float raz = counter - Uout; //на сколько напряжение меньше чем мы хотим
    float iraz = (Ioutmax - Iout); // 
    if(raz>0.1 & iraz>0.1)
    {
      level = level - raz * 20; //грубо
    }else{
      if(raz>0.015)  level = level - raz ; //точно
    }
  }
 }
}//конец режима стабилизации тока

if(off) level = 8190;
if(level<0) level = 0; //не опускаем ШИМ ниже нуля
if(level>8190) level = 8190; //не поднимаем ШИМ выше 13 бит
//Все проверили, прощитали и собственно отдаем команду для силового транзистора.
if(ceil(level)!=255) analogWrite(pwm, ceil(level)); //подаем нужный сигнал на ШИМ выход (кроме 255, так как там какая-то лажа)


/* УПРАВЛЕНИЕ */

if (digitalRead(13)==0 && digitalRead(12)==0 && knopka_ab==0 ) { // нажата ли кнопка a и б вместе
  knopka_ab = 1;

  //ah = 0.000;

  knopka_ab = 0;
}


if (digitalRead(13)==0 && knopka_a==0) { // нажата ли кнопка А (disp)
knopka_a = 1;
disp = disp + 1; //поочередно переключаем режим отображения информации
if(disp==6) disp = 0; //дошли до конца, начинаем снова
}

if (digitalRead(12)==0 && knopka_b==0) { // нажата ли кнопка Б (menu)
knopka_b = 1;
set = set+1; //
if(set>4 | off) {//Задействован один из режимов защиты, а этой кнопкой мы его вырубаем. (или мы просто дошли до конца меню)
off = false;
  digitalWrite(power, 1); //врубаем реле если оно было выключено
  delay(100);
  digitalWrite(A2, 0); //гасим красный светодиод 
    Serial.print('t');
    Serial.print(0);
    Serial.print(';');
      Serial.print('r');
    Serial.print(0);
    Serial.print(';');
  Serial.println(' ');
  set = 0;//выходим из меню
  }
  lcd.clear();//чистим дисплей
}

//сбрасываем значения кнопок или чего-то вроде того.
if(digitalRead(12)==1&&knopka_b==1) knopka_b = 0;
if(digitalRead(13)==1&&knopka_a==1) knopka_a = 0;





/* COM PORT */

if(currentMillis - com2 > com) {
    // сохраняем время последнего обновления
    com2 = currentMillis;  
    
    //Считаем Ампер*часы
    ah = ah + (Iout / 36000);

    Serial.print('U');
    Serial.print(Uout);
    Serial.print(';');
    
    Serial.print('I');
    Serial.print(Iout);
    Serial.print(';');
    
    Serial.print('i');
    Serial.print(Ioutmax);
    Serial.print(';');
    
    Serial.print('u');
    Serial.print(counter);
    Serial.print(';');
    
    Serial.print('W');
    Serial.print(level);
    Serial.print(';');
    
    Serial.print('c');
    Serial.print(ah);
    Serial.print(';');
    
    Serial.print('m');
    Serial.print(mode);
    Serial.print(';');
    
    Serial.print('r');
    Serial.print(digitalRead(A2));
    Serial.print(';');
    
    Serial.print('b');
    Serial.print(digitalRead(A3));
    Serial.print(';');
    

    
    Serial.println(' ');
  
  }  
  
  /* ИНДИКАЦИЯ LCD */



if(set==0){
  //стандартный екран  
    
  //выводим уснановленное напряжение на дисплей
  lcd.setCursor (0, 1);
  lcd.print("U>"); 
  if(counter<10) lcd.print(" "); //добавляем пробел, если нужно, чтобы не портить картинку
  lcd.print (counter,2); //выводим установленное значение напряжения
  lcd.print ("V"); //пишем что это вольты 
 
  //обновление информации
   
  /*проверяем не прошел ли нужный интервал, если прошел то
  выводим реальные значения на дисплей*/

  if(currentMillis - previousMillis > interval) {
    // сохраняем время последнего обновления
    previousMillis = currentMillis;  
    //выводим актуальные значения напряжения и тока на дисплей
  
    lcd.setCursor (0, 0);
    lcd.print("U=");
    if(Uout<9.99) lcd.print(" ");
    lcd.print(Uout,2);
    lcd.print("V I=");
    lcd.print(Iout, 2);
    lcd.print("A ");
  
    //дополнительная информация
    lcd.setCursor (8, 1);
    if(disp==0){  //ничего
      lcd.print("         ");
    }    
    if(disp==1){  //мощьность
      lcd.print(" ");
      lcd.print (Uout * Iout,2); 
      lcd.print("W   ");
    }  
    if(disp==2){  //режим БП
      if(mode==0)lcd.print   ("standart"); 
      if(mode==1)lcd.print  ("shutdown"); 
      if(mode==2)lcd.print ("    drop");
    }  
    if(disp==3){  //максимальный ток
       lcd.print (" I>"); 
       lcd.print (Ioutmax, 2); 
       lcd.print ("A ");
    }
    if(disp==4){  // значение ШИМ
      lcd.print ("pwm:"); 
      lcd.print (ceil(level), 0); 
      lcd.print ("  ");
    }
    if(disp==5){  // значение ШИМ
      if(ah<1){
        //if(ah<0.001) lcd.print (" ");
        if(ah<=0.01) lcd.print (" ");
        if(ah<=0.1) lcd.print (" ");
        lcd.print (ah*1000, 1); 
      lcd.print ("mAh  ");
      }else{
        if(ah<=10) lcd.print (" ");
      lcd.print (ah, 3); 
      lcd.print ("Ah  ");
      }
    }
  }
}

/* ИНДИКАЦИЯ МЕНЮ */
if(set==1)//выбор режима
{
 lcd.setCursor (0, 0);
 lcd.print("> MENU 1/4    ");
 lcd.setCursor (0, 1);
 lcd.print("mode: ");
 //режим (0 обычный, спабилизация тока, защита по току)
 if(mode==0)  lcd.print("normal          ");
 if(mode==1)  lcd.print("shutdown    ");
 if(mode==2)  lcd.print("drop        ");
}
if(set==2){//настройка тока
 lcd.setCursor (0, 0);
 lcd.print("> MENU 2/4   ");
 lcd.setCursor (0, 1);
 lcd.print("I out max: ");
 lcd.print(Ioutmax);
 lcd.print("A");
}
if(set==3){//спрашиваем хочет ли юзер сохранить настройки
 lcd.setCursor (0, 0);
 lcd.print("> MENU 3/4      ");
 lcd.setCursor (0, 1);
 lcd.print("Reset A*h? ->");
}

if(set==4){//спрашиваем хочет ли юзер сохранить настройки
 lcd.setCursor (0, 0);
 lcd.print("> MENU 4/4      ");
 lcd.setCursor (0, 1);
 lcd.print("Save options? ->");
}
/* ИНДИКАЦИЯ ЗАЩИТЫ */
if(set==5){//защита. вывод инфы
 lcd.setCursor (0, 0);
 lcd.print("ShutDown!        ");
 lcd.setCursor (0, 1);
 lcd.print("Iout");
 lcd.print(">Imax(");
 lcd.print(Ioutmax);
 lcd.print("A)"); 
 level=0;
 Serial.print('I0;U0;r1;W0;');
    Serial.println(' ');
}

 
 if(set==6){//защита. вывод инфы критическое падение напряжения
Serial.print('I0;U0;r1;W0;');
digitalWrite(A2, true);
    Serial.println(' ');
    level=0;
 lcd.setCursor (0, 0);
 if (off==false){ lcd.print("[   OVERLOAD   ]");
 lcd.setCursor (0, 1);
      //и обьясняем юзеру что случилось
    
     if((Iout>(counter+0.3)*2.0) | Iout>10.0){
           Serial.print('t');
    Serial.print(1);
    Serial.print(';');
      lcd.print("  Iout >= Imax  ");
     }
     
 }else{
   
   lcd.print("[      OFF     ]");
 lcd.setCursor (0, 1);
Serial.print('t');
    Serial.print(4);
    Serial.print(';');
 }
 }
 
}

 

aleks_22
Offline
Зарегистрирован: 18.04.2016

Вот проект в протеуте!

http://rghost.ru/private/7ZLwkbs8l/f744b29903c5325927be1635aa4f630b

 

uragan
Offline
Зарегистрирован: 23.02.2015

Так вы вопрос какой-то конкретный задайте. Просто сделайте мне хорошо это в другой раздел.

aleks_22
Offline
Зарегистрирован: 18.04.2016

В какой раздел? Если можно перенести и исправить тему как услуга.

 

aleks_22
Offline
Зарегистрирован: 18.04.2016

Удалите тему пожалуйста!