ШИМ, энкодер, кнопки и EEPROM

wowscheg
Offline
Зарегистрирован: 14.02.2012

Здравствуйте!

Помогите написать код к моему проекту

Вот суть:

Есть один аналоговый выход, на нем сидит светодиод. Есть энкодер подключенный к плате. И есть, например, десяток кнопок, подключенные к оставшимся ножкам контроллера. Задача следующая: При вращении энкодера значение на выходе меняется от 0 до 255, при выключении питания что бы значение записывалось в EEPROM и при подаче питания значение оставалось таким же. Кнопки: при длительном нажатии, например больше секунды, запоминал текущее значение на выходе а при кратковременном, на ту же кнопку, возвращал из любого значения на то что сохранил.

На этом форуме нашел код для работы с энкодером:


/*
** Энкодер
** Для управлением яркостью LED используется энкодер
*/
int brightness = 120;       // яркость LED, начинаем с половины
int fadeAmount = 10;        // шаг изменения яркости LED
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 8;       // канал А энкодера на pin 8
const int pin_B = 7;       // канал В энкодера на pin 7
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
 
void setup()  {
  // declare pin 9 to be an output:
  pinMode(11, OUTPUT);         // устанавливаем pin 11 как выход
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  currentTime = millis();
  loopTime = currentTime;
}
 
void loop()  {
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц)
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода А энкодера   
    if((!encoder_A) && (encoder_A_prev)){    // если состояние изменилось с положительного к нулю
      if(encoder_B) {
        // выход В в полож. сост., значит вращение по часовой стрелке
        // увеличиваем яркость, не более чем до 255
        if(brightness + fadeAmount <= 255) brightness += fadeAmount;              
      }  
      else {
        // выход В в 0 сост., значит вращение против часовой стрелки    
        // уменьшаем яркость, но не ниже 0
        if(brightness - fadeAmount >= 0) brightness -= fadeAmount;              
      }  
 
    }  
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла
     
    analogWrite(11, brightness);   // устанавливаем яркость на 11 ножку
    
    loopTime = currentTime;
  }
 }

 

 А вот что делать дальше я не знаю.

Есть один момент, после каждого изменения значения на выходе записывать в EEPROM нельзя, крутить будут много и быстро можно убить микросхему. Поэтому выход из положения я вижу так:

Считываем значение из памяти, если совпадает с значением на выходе то ничего не трогаем а если значение изменилось, ждем 5 секунд и перезаписываем значение в EEPROM.

Помогите пожалуйста.

maksim
Offline
Зарегистрирован: 12.02.2012

Кнопки при нажатии должны замыкать пин на землю(GND). В примере только 2 кнопки, остальные пишите по аналогии.
 

// //////////////////////////////////////////////////////////
#include <EEPROM.h> 

#define BUTTON_1 2  // Определяем к каким выводам подключены кнопки
#define BUTTON_2 3

int old_brightness = 0;     
boolean state_EEwrt, state_Btn_1, state_Btn_2 = 0;
unsigned long TimeOut_EEwrt, TimeOut_Btn_1, TimeOut_Btn_2;
// ///////////////////////////////////////////////////////////

/*
** Энкодер
 ** Для управлением яркостью LED используется энкодер
 */
int brightness = 120;       // яркость LED, начинаем с половины
int fadeAmount = 10;        // шаг изменения яркости LED
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 8;       // канал А энкодера на pin 8
const int pin_B = 7;       // канал В энкодера на pin 7
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;

void setup()  {
  // declare pin 9 to be an output:
  pinMode(11, OUTPUT);         // устанавливаем pin 11 как выход
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  currentTime = millis();
  loopTime = currentTime;

  // ////////////////////////////////////
  digitalWrite(BUTTON_1, 1);   // Подтягиваем вывод к +5В
  digitalWrite(BUTTON_2, 1);   // Подтягиваем вывод к +5В
  brightness = EEPROM.read(0); // Считываем значение яркости из ЕЕПРОМ по адресу 0
  // //////////////////////////////////// 

}

void loop()  {
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц)
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода А энкодера   
    if((!encoder_A) && (encoder_A_prev)){    // если состояние изменилось с положительного к нулю
      if(encoder_B) {
        // выход В в полож. сост., значит вращение по часовой стрелке
        // увеличиваем яркость, не более чем до 255
        if(brightness + fadeAmount <= 255) brightness += fadeAmount;              
      }  
      else {
        // выход В в 0 сост., значит вращение против часовой стрелки    
        // уменьшаем яркость, но не ниже 0
        if(brightness - fadeAmount >= 0) brightness -= fadeAmount;              
      }  

    }  
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла

    analogWrite(11, brightness);   // устанавливаем яркость на 11 ножку

    // /////////////////////////////////////////////////////////////////////////////////////
    if(brightness != old_brightness){ //Если старое значение яркости не равно новому, то                      
      old_brightness = brightness; // Старому значению присваиваем новое                        
      state_EEwrt = 0;// сбрасываем Флаг того, что записи в ЕЕПРОМ еще не было                          
      TimeOut_EEwrt = millis(); // Записываем текущее значение таймера                            
    }                                                  
    else if(millis()-TimeOut_EEwrt > 5000 && !state_EEwrt){ // Если текущее значение таймера превысило 5000 млс относительно сохраненного и запись в ЕЕПРОМ еще не производилась, то
      EEPROM.write(0, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 0                        
      state_EEwrt = 1;  // Устанавливаем флаг о том, что была произведена запись в ЕЕПРОМ                      
    }                                                          
    // /////////////////////////////////////////////////////////////////////////////////////////

    loopTime = currentTime;
  }

  // /////////////////////////////////////////////////////////////////////////////////////////
  if(!digitalRead(BUTTON_1) && !state_Btn_1){ // Если кнопка нажата и флаг сброшен 
    TimeOut_Btn_1 = millis(); // Записываем текущее значение таймера
    delay(150); // Ждем 150 млс
    while(!digitalRead(BUTTON_1)){ // Цикл пока кнопка нажата
      if(millis()-TimeOut_Btn_1 > 2000){ // Если текущее значение таймера превысило 2000 млс относительно сохраненного, то
        EEPROM.write(1, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 1                                   
      }    
    }
    brightness = EEPROM.read(1); // Читаем текущее значение яркости из ЕЕПРОМ по адресу 1
    state_Btn_1 = 1; // Устанавливаем флаг о том, что кнопка нажамалась
  }  
  if(digitalRead(BUTTON_1)){ // Если кнопка не нажата, то
    state_Btn_1 = 0; // Сбрасываем флаг о том, что кнопка нажамалась
  }


  if(!digitalRead(BUTTON_2) && !state_Btn_2){
    TimeOut_Btn_2 = millis();
    delay(150);
    while(!digitalRead(BUTTON_2)){
      if(millis()-TimeOut_Btn_2 > 2000){
        EEPROM.write(2, brightness);                                       
      }    
    }
    brightness = EEPROM.read(2);
    state_Btn_2 = 1;
  }
  if(digitalRead(BUTTON_2)){
    state_Btn_2 = 0;
  }
  // /////////////////////////////////////////////////////////////////////////////////////////

}

Работспособность не проверял, если что не так отпишитесь. 

wowscheg
Offline
Зарегистрирован: 14.02.2012

Да работает, спасибо!

Но есть одна проблемка, с вашим кодом светодиод не гаснет полностью, то есть ШИМ не проседает до нуля.

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

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

maksim
Offline
Зарегистрирован: 12.02.2012

Так это не с моим кодом, за яркость светодиода отвечает ваша часть кода я ее не трогал, в 56 строке попробуйте поменять 0 на -10

	        if(brightness - fadeAmount >= -10) brightness -= fadeAmount;   

Коменты добавил в код выше.

wowscheg
Offline
Зарегистрирован: 14.02.2012

Вот еще один момент, не "запоминало" на чем выключилось, то есть "запоминало" но не "вспоминало" при подаче питания (извините за каламбур) решил вопрос так

int brightness = EEPROM.read(0);    //установка значения из памяти при включении

но в ноль ШИМ так и не становится, пытаюсь выловить багу но не могу

а если в 56 строке выставить -10, то в положении когда должен выключится, он наоборот светит с полной силой!

За коментарии отдельное спасибо!

Итого, вот как выглядит на данный момент

// //////////////////////////////////////////////////////////
#include <EEPROM.h> 

#define BUTTON_1 2  // Определяем к каким выводам подключены кнопки
#define BUTTON_2 3

int old_brightness = 0;     
boolean state_EEwrt, state_Btn_1, state_Btn_2 = 0;
unsigned long TimeOut_EEwrt, TimeOut_Btn_1, TimeOut_Btn_2;
// ///////////////////////////////////////////////////////////

/*
** Энкодер
 ** Для управлением яркостью LED используется энкодер
 */
int brightness = EEPROM.read(0);       //установка значения из памяти при включении
int fadeAmount = 10;        // шаг изменения яркости LED
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 8;       // канал А энкодера на pin 8
const int pin_B = 7;       // канал В энкодера на pin 7
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;

void setup()  {
  // declare pin 9 to be an output:
  pinMode(11, OUTPUT);         // устанавливаем pin 11 как выход
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  currentTime = millis();
  loopTime = currentTime;

  // ////////////////////////////////////
  digitalWrite(BUTTON_1, 1);   // Подтягиваем вывод к +5В
  digitalWrite(BUTTON_2, 1);   // Подтягиваем вывод к +5В
  brightness = EEPROM.read(0); // Считываем значение яркости из ЕЕПРОМ по адресу 0
  // //////////////////////////////////// 

}

void loop()  {
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц)
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода А энкодера   
    if((!encoder_A) && (encoder_A_prev)){    // если состояние изменилось с положительного к нулю
      if(encoder_B) {
        // выход В в полож. сост., значит вращение по часовой стрелке
        // увеличиваем яркость, не более чем до 255
        if(brightness + fadeAmount <= 255) brightness += fadeAmount;              
      }  
      else {
        // выход В в 0 сост., значит вращение против часовой стрелки    
        // уменьшаем яркость, но не ниже 0
        if(brightness - fadeAmount >= -10) brightness -= fadeAmount;              
      }  

    }  
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла

    analogWrite(11, brightness);   // устанавливаем яркость на 11 ножку

    // /////////////////////////////////////////////////////////////////////////////////////
    if(brightness != old_brightness){ //Если старое значение яркости не равно новому, то                      
      old_brightness = brightness; // Старому значению присваиваем новое                        
      state_EEwrt = 0;// сбрасываем Флаг того, что записи в ЕЕПРОМ еще не было                          
      TimeOut_EEwrt = millis(); // Записываем текущее значение таймера                            
    }                                                  
    else if(millis()-TimeOut_EEwrt > 5000 && !state_EEwrt){ // Если текущее значение таймера превысило 5000 млс относительно сохраненного и запись в ЕЕПРОМ еще не производилась, то
      EEPROM.write(0, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 0                        
      state_EEwrt = 1;  // Устанавливаем флаг о том, что была произведена запись в ЕЕПРОМ                      
    }                                                          
    // /////////////////////////////////////////////////////////////////////////////////////////

    loopTime = currentTime;
  }

  // /////////////////////////////////////////////////////////////////////////////////////////
  if(!digitalRead(BUTTON_1) && !state_Btn_1){ // Если кнопка нажата и флаг сброшен 
    TimeOut_Btn_1 = millis(); // Записываем текущее значение таймера
    delay(150); // Ждем 150 млс
    while(!digitalRead(BUTTON_1)){ // Цикл пока кнопка нажата
      if(millis()-TimeOut_Btn_1 > 2000){ // Если текущее значение таймера превысило 2000 млс относительно сохраненного, то
        EEPROM.write(1, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 1                                   
      }    
    }
    brightness = EEPROM.read(1); // Читаем текущее значение яркости из ЕЕПРОМ по адресу 1
    state_Btn_1 = 1; // Устанавливаем флаг о том, что кнопка нажамалась
  }  
  if(digitalRead(BUTTON_1)){ // Если кнопка не нажата, то
    state_Btn_1 = 0; // Сбрасываем флаг о том, что кнопка нажамалась
  }


  if(!digitalRead(BUTTON_2) && !state_Btn_2){
    TimeOut_Btn_2 = millis();
    delay(150);
    while(!digitalRead(BUTTON_2)){
      if(millis()-TimeOut_Btn_2 > 2000){
        EEPROM.write(2, brightness);                                       
      }    
    }
    brightness = EEPROM.read(2);
    state_Btn_2 = 1;
  }
  if(digitalRead(BUTTON_2)){
    state_Btn_2 = 0;
  }
  // /////////////////////////////////////////////////////////////////////////////////////////

}

 

maksim
Offline
Зарегистрирован: 12.02.2012

wowscheg пишет:

Вот еще один момент, не "запоминало" на чем выключилось, то есть "запоминало" но не "вспоминало" при подаче питания (извините за каламбур) решил вопрос так

int brightness = EEPROM.read(0);    //установка значения из памяти при включении

В 37 строке происходит тоже самое:

brightness = EEPROM.read(0); // Считываем значение яркости из ЕЕПРОМ по адресу 0

Так что у вас два раза присваивается brightness одно и тоже значение. Может вы просто выключали питание не дождавшись 5 секунд и значение не сохранялось.

По поводу ШИМа - замените кусок кода с 48 по 57 строки включительно вот на этот кусок:

      if(encoder_B) {
        // выход В в полож. сост., значит вращение по часовой стрелке
        // увеличиваем яркость, не более чем до 255
        brightness += fadeAmount; 
        brightness = min(brightness, 255);
      }  
      else {
        // выход В в 0 сост., значит вращение против часовой стрелки    
        // уменьшаем яркость, но не ниже 0
        brightness -= fadeAmount; 
        brightness = max(brightness, 0);        
      } 

 

wowscheg
Offline
Зарегистрирован: 14.02.2012

Maksim, огромное Вам спасибо! Все заработало как надо.

wowscheg
Offline
Зарегистрирован: 14.02.2012

А как организовать индикацию записи в память для кнопочек?

 

maksim
Offline
Зарегистрирован: 12.02.2012

А как вы хотите? 

wowscheg
Offline
Зарегистрирован: 14.02.2012

Ну даже не знаю, в принципе можно мигнуть светодиодом а можно пискнуть бипером, но я думаю светодиодом нагляднее будет

наверное как то так, начиная с 84 строки

if(millis()-TimeOut_Btn_1 > 2000){ // Если текущее значение таймера превысило 2000 млс относительно сохраненного, то
        EEPROM.write(1, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 1 
 digitalWrite(13, HIGH);   // зажигаем светодиод
  delay(1000);              // ждем секунду
  digitalWrite(13, LOW);    // гасим светодиод

 

maksim
Offline
Зарегистрирован: 12.02.2012
// //////////////////////////////////////////////////////////
#include <EEPROM.h> 

#define BUTTON_1 2  // Определяем к каким выводам подключены кнопки
#define BUTTON_2 3

int old_brightness = 0;     
boolean state_EEwrt, state_Btn_1, state_Btn_2 = 0;
unsigned long TimeOut_EEwrt, TimeOut_Btn_1, TimeOut_Btn_2;
// ///////////////////////////////////////////////////////////

/*
** Энкодер
 ** Для управлением яркостью LED используется энкодер
 */
int brightness = EEPROM.read(0); //установка значения из памяти при включении
int fadeAmount = 10;        // шаг изменения яркости LED
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 8;       // канал А энкодера на pin 8
const int pin_B = 7;       // канал В энкодера на pin 7
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;

void setup()  {
  // declare pin 9 to be an output:
  pinMode(11, OUTPUT);         // устанавливаем pin 11 как выход
  pinMode(pin_A, INPUT);
  pinMode(pin_B, INPUT);
  currentTime = millis();
  loopTime = currentTime;

  // ////////////////////////////////////
  digitalWrite(BUTTON_1, 1);   // Подтягиваем вывод к +5В
  digitalWrite(BUTTON_2, 1);   // Подтягиваем вывод к +5В
  brightness = EEPROM.read(0); // Считываем значение яркости из ЕЕПРОМ по адресу 0
  // //////////////////////////////////// 

}

void loop()  {
  currentTime = millis();
  if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц)
    encoder_A = digitalRead(pin_A);     // считываем состояние выхода А энкодера
    encoder_B = digitalRead(pin_B);     // считываем состояние выхода А энкодера   
    if((!encoder_A) && (encoder_A_prev)){    // если состояние изменилось с положительного к нулю
      if(encoder_B) {
        // выход В в полож. сост., значит вращение по часовой стрелке
        // увеличиваем яркость, не более чем до 255
        brightness += fadeAmount; 
        brightness = min(brightness, 255);
      }  
      else {
        // выход В в 0 сост., значит вращение против часовой стрелки    
        // уменьшаем яркость, но не ниже 0
        brightness -= fadeAmount; 
        brightness = max(brightness, 0);        
      }  

    }  
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла

    analogWrite(11, brightness);   // устанавливаем яркость на 11 ножку

    // /////////////////////////////////////////////////////////////////////////////////////
    if(brightness != old_brightness){ //Если старое значение яркости не равно новому, то                      
      old_brightness = brightness; // Старому значению присваиваем новое                        
      state_EEwrt = 0;// сбрасываем Флаг того, что записи в ЕЕПРОМ еще не было                          
      TimeOut_EEwrt = millis(); // Записываем текущее значение таймера                            
    }                                                  
    else if(millis()-TimeOut_EEwrt > 5000 && !state_EEwrt){ // Если текущее значение таймера превысило 5000 млс относительно сохраненного и запись в ЕЕПРОМ еще не производилась, то
      EEPROM.write(0, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 0                        
      state_EEwrt = 1;  // Устанавливаем флаг о том, что была произведена запись в ЕЕПРОМ                      
    }                                                          
    // /////////////////////////////////////////////////////////////////////////////////////////

    loopTime = currentTime;
  }

  // /////////////////////////////////////////////////////////////////////////////////////////
  if(!digitalRead(BUTTON_1) && !state_Btn_1){ // Если кнопка нажата и флаг сброшен 
    TimeOut_Btn_1 = millis(); // Записываем текущее значение таймера
    delay(150); // Ждем 150 млс
    while(!digitalRead(BUTTON_1)){ // Цикл пока кнопка нажата
      if(millis()-TimeOut_Btn_1 > 2000){ // Если текущее значение таймера превысило 2000 млс относительно сохраненного, то
        EEPROM.write(1, brightness); // Записываем текущее значение яркости в ЕЕПРОМ по адресу 1  
        Miganie();        
      }    
    }
    brightness = EEPROM.read(1); // Читаем текущее значение яркости из ЕЕПРОМ по адресу 1
    state_Btn_1 = 1; // Устанавливаем флаг о том, что кнопка нажамалась
  }  
  if(digitalRead(BUTTON_1)){ // Если кнопка не нажата, то
    state_Btn_1 = 0; // Сбрасываем флаг о том, что кнопка нажамалась
  }


  if(!digitalRead(BUTTON_2) && !state_Btn_2){
    TimeOut_Btn_2 = millis();
    delay(150);
    while(!digitalRead(BUTTON_2)){
      if(millis()-TimeOut_Btn_2 > 2000){
        EEPROM.write(2, brightness); 
        Miganie();         
      }    
    }
    brightness = EEPROM.read(2);
    state_Btn_2 = 1;
  }
  if(digitalRead(BUTTON_2)){
    state_Btn_2 = 0;
  }
  // /////////////////////////////////////////////////////////////////////////////////////////

}

void Miganie(){
  digitalWrite(11, 0);
  delay(100);
  digitalWrite(11, 1);
  delay(200);
  digitalWrite(11, 0);
  delay(100);
  digitalWrite(11, 1);
  delay(200);
  digitalWrite(11, 0);
  analogWrite(11, brightness);
}

 Должен при записи моргнуть два раза.

wowscheg
Offline
Зарегистрирован: 14.02.2012

Ага, я не так выразился, я имел в виду дополнительный светодиод, подключенный к 13 пину (в принципе уже запаян в ардуино) а управляймым светодиодом моргать нельзя. Вобщем я сделал так, все работает. Спасибо!

 

void Miganie(){
  digitalWrite(13, 0);
  delay(100);
  digitalWrite(13, 1);
  delay(200);
  digitalWrite(13, 0);
  delay(100);
  digitalWrite(13, 1);
  delay(200);
  digitalWrite(13, 0);
  analogWrite(13, brightness);
}

 кстати, в таком случае не нужна последняя строчка: 

analogWrite(13, brightness);

если ее оставить то светодиод индикации не гас

maksim
Offline
Зарегистрирован: 12.02.2012

wowscheg пишет:
 

 кстати, в таком случае не нужна последняя строчка: 

analogWrite(13, brightness);

если ее оставить то светодиод индикации не гас

Так естественно, эта строка была нужна для того, что бы после мигания значиние осталось таким же как и до мигания.

wowscheg
Offline
Зарегистрирован: 14.02.2012

дадада, maksim, я уже понял, а вот как это выглядит http://www.youtube.com/watch?v=4B58Yb4TG5s

vworld
vworld аватар
Offline
Зарегистрирован: 26.09.2011

очень нужная тема! искал везде в инете, а нашел в итоге у нас на форуме

от себя добавлю, что у меня код заработал только тогдла, когда добавил кусок

  digitalWrite(11, HIGH); // канал А энкодера на pin 11
  digitalWrite(10, HIGH);// канал В энкодера на pin 10

 

serega374
Offline
Зарегистрирован: 10.08.2015

Вот у меня такая задачка на дисплей вывожу температуру и влажность с датчика. А энкодером регулирую скорость вращения вентилятора. Температура и влажность выводяться постоянно. Хочу что бы при вращении энкодера выводилась скорость вращения вентилятора в процентах на какоето время а после окончания вращения опять индиицироваллась темература и влажность. Написал код вроде в протеус работает но как то криво (хотя может беда в протеусе) иногда иероглифы начинает выводить а затем пустой дисплей. 

Если не сложно глянте код подскажите новичку что улучшить

#include <LiquidCrystal.h>
#include <dht11.h>

int encoderPin1 = 2;
int encoderPin2 = 3;
int pwmv = 5;

volatile int lastEncoded = 0;
volatile int encoderValue = 200;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

dht11 DHT;               // Объявление переменной класса dht11
#define DHT11_PIN 6      // Датчик DHT11 подключен к цифровому пину номер 6
byte degree[8] =         // Битовая маска символа градуса
{
  B00111,
  B00101,
  B00111,
  B00000,
  B00000,
  B00000,
  B00000,
};   

// Подключаем LCD
LiquidCrystal lcd(12, 11, 10, 9, 8, 7 );

void setup()
{  
 lcd.begin(16, 2);// задаем размерность дисплея
  lcd.createChar(1, degree);        // Создаем символ под номером 1
  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);
  pinMode(pwmv, OUTPUT);
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);
}


void TempHum()
{
// Выводим показания влажности и температуры
  lcd.setCursor(0, 0);              // Устанавливаем курсор в начало 1 строки
  lcd.print("Humidity =    % ");     // Выводим текст
  lcd.setCursor(11, 0); 
  lcd.print(DHT.humidity, 1);
  lcd.setCursor(0, 1);              // Устанавливаем курсор в начало 2 строки
  lcd.print("Temp     =   \1C ");    // Выводим текст, \1 - значок градуса
  lcd.setCursor(11, 1);             
  lcd.print(DHT.temperature,1);  
  
  int chk; 
  chk = DHT.read(DHT11_PIN);    // Чтение данных
  switch (chk){
  case DHTLIB_OK:  
    break;
  case DHTLIB_ERROR_CHECKSUM:  
    lcd.clear(); 
    lcd.print("Checksum error");  
    break;
  case DHTLIB_ERROR_TIMEOUT:
    lcd.clear(); 
    lcd.print("Time out error");
    break;
  default:
    lcd.clear(); 
    lcd.print("Unknown error");
    break;
  }

 
}

void loop()
{

  TempHum();
}
	
void updateEncoder(){
  int MSB = digitalRead(encoderPin1);
  int LSB = digitalRead(encoderPin2);
  int encoded = (MSB << 1) |LSB;
  int sum  = (lastEncoded << 2) | encoded;
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) 
  {    
    encoderValue ++;
     if (encoderValue==254 || encoderValue > 254)
    {
    encoderValue = 254 ;
    }
        }
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
  {
    
    encoderValue --;
    if (encoderValue==0 || encoderValue < 0)
    {
    encoderValue = 0 ;
    }
        }

  lastEncoded = encoded;
  
    analogWrite(pwmv, encoderValue);
      lcd.clear(); 
    lcd.setCursor(0, 0);              // Устанавливаем курсор в начало 1 строки
  lcd.print("SpeedFAN =    % ");     // Выводим текст
  lcd.setCursor(11, 0); 
  lcd.print(encoderValue/255*100, 1);
        
}

 

vworld
vworld аватар
Offline
Зарегистрирован: 26.09.2011

>serega374

я бы предложил доработать алгоритм

я вижу так:

1) на ЖК экран всегда выводятся все текущие показания - температура, влажность скорость вращения в процентах

2) нажимаем кнопку (короткое нажатие и мигнет светодиод один раз) - показывает текущую скорость вращения в процентах и энкодером меняем её

3) нажимаем кнопку (долгое нажатие и мигает светодиод до тех пор пока кнопка нажата) - идет запись в EEPROM нового значения

nevkon
Offline
Зарегистрирован: 20.01.2015

Нужная тема. Можно ли оперативно регулировать частоту ШИМ и если можно, то как?

serega374
Offline
Зарегистрирован: 10.08.2015

Итак маленько подработал я код. EEPROM и кнопку пока не подключал. Возникла проблема с вычислением процентов от "int encoderValue" Я в начале написал "lcd.print(encoderValue/255*100, 1);" но LCD всегда показывал "0%", потом допер что int целые числа и заменил "volatile int encoderValue = 255;" на "volatile long encoderValue = 255;" LCD стал показывать либо "0%" либо "100%".

Вот хочу спросить у знающих как отобразить мне проценты? Еще вопрос почему ШИМ меняеться с шагом 4 (сейчас на LCD я отображаю непоредственное значение ШИМ и при повороте энкодера на один "щелчок" значение encoderValue изменяеться на 4? И последенее в коде есть переменная "long lastencoderValue = 0;" не могу понять что она занчит? Код я честно признаюсь где-то "спёр" может и тут  сильно не пипнайте я только учусь)

#include <LiquidCrystal.h>
#include <dht11.h>

int encoderPin1 = 2; // подключаем энкодер к пину D2
int encoderPin2 = 3; // подключаем энкодер к пину D3
int pwmv = 11; // выход ШИМ D11

volatile int lastEncoded = 0;
volatile int encoderValue = 255; // начальное значение ШИМ
long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

dht11 DHT;               // Объявление переменной класса dht11
#define DHT11_PIN 10      // Датчик DHT11 подключен к цифровому пину номер 10
byte degree[8] =         // Битовая маска символа градуса
{
  B00111,
  B00101,
  B00111,
  B00000,
  B00000,
  B00000,
  B00000,
};   

// Подключаем LCD
LiquidCrystal lcd(9, 8, 7, 6, 5, 4 );

void setup()
{  
 lcd.begin(16, 2);// задаем размерность дисплея
  lcd.createChar(1, degree);        // Создаем символ под номером 1
  pinMode(encoderPin1, INPUT); 
  pinMode(encoderPin2, INPUT);
  pinMode(10, INPUT);
  pinMode(pwmv, OUTPUT);
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);
  analogWrite(pwmv, encoderValue); // записываем начальное значение ШИМ при включении
}


void TempHumSpeedFan()
{
// Выводим показания влажности и температуры
  lcd.clear(); 
  lcd.setCursor(0, 0);              // Устанавливаем курсор в начало 1 строки
  lcd.print("Humidity =    % ");     // Выводим текст
  lcd.setCursor(11, 0); 
  lcd.print(DHT.humidity, 1);
  lcd.setCursor(0, 1);              // Устанавливаем курсор в начало 2 строки
  lcd.print("Temp     =   \1C ");    // Выводим текст, \1 - значок градуса
  lcd.setCursor(11, 1);             
  lcd.print(DHT.temperature,1);    
  delay (1000);
  lcd.clear(); 
  lcd.setCursor(0, 0);              // Устанавливаем курсор в начало 1 строки
  lcd.print("SpeedFAN =    % ");     // Выводим текст
  lcd.setCursor(11, 0); 
  lcd.print(encoderValue, 1);
  delay (1000);
  int chk; 
  chk = DHT.read(DHT11_PIN);    // Чтение данных
  switch (chk){
  case DHTLIB_OK:  
    break;
  case DHTLIB_ERROR_CHECKSUM:  
    lcd.clear(); 
    lcd.print("Checksum error");  
    break;
  case DHTLIB_ERROR_TIMEOUT:
    lcd.clear(); 
    lcd.print("Time out error");
    break;
  default:
    lcd.clear(); 
    lcd.print("Unknown error");
    break;
  }

 
}

void loop()
{

  TempHumSpeedFan();
}
  
void updateEncoder(){
  int MSB = digitalRead(encoderPin1);
  int LSB = digitalRead(encoderPin2);
  int encoded = (MSB << 1) |LSB;
  int sum  = (lastEncoded << 2) | encoded;
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) 
  {    
    encoderValue ++;
     if (encoderValue==255 || encoderValue > 255)
    {
    encoderValue = 255 ;
    }
        }
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
  {
    
    encoderValue --;
    if (encoderValue==0 || encoderValue < 0)
    {
    encoderValue = 0 ;
    }
        }

  lastEncoded = encoded;
  
    analogWrite(pwmv, encoderValue);     
        
}

 

nevkon
Offline
Зарегистрирован: 20.01.2015

Измени логику рассчета - сначала умножь, а потом уже дели.

Где-то уже проскакивало в темах проблема с делением когда все переменные объявлены как целочисленные.

nevkon
Offline
Зарегистрирован: 20.01.2015

Я бы советовал выкинуть все лишнее из прерывания. Запись нового ШИМ уровня лучше все-таки делать в loop. В прерывании стоит оставлять только если это критично для задачи (сериал или вывод на экран сильно может затормозить программу).

Какой вы используете энкодер? По программе не скажешь что значение скачет по 4. Просто энкодер может быть очень чувствительный.

serega374
Offline
Зарегистрирован: 10.08.2015

Вот такой энкодер. Мне это некритично (изменение шим с шагом 4) я думал это в особенностях контролера заложено

nevkon
Offline
Зарегистрирован: 20.01.2015

Попробуйте отрабатывать каждый 10 ход энкодера (encodervalue от 0 до 2550, а при выводе на ШИМ делите на 10). Можно будет кртуть быстрее.

Попробуйте код с 2 светиками который предлагают китайцы - http://ru.aliexpress.com/item/Free-shipping-KEYES-Rotary-encoder-module-for-arduino-with-demo-code/1743367243.html?spm=2114.031020208.3.2.DvtsZW&ws_ab_test=searchweb201556_1_71_72_73_61_74_75,searchweb201527_4,searchweb201560_9