Форум обсуждения систем  

Вернуться   Форум обсуждения систем "Умный дом", проектов Ардуино, OpenWRT и других DIY устройств > Форум умного дома > Сделай сам

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
Старый 11.08.2018, 20:06   #1
Tohin
Moderator
 
Регистрация: 20.07.2014
Адрес: МСК
Сообщений: 991
Вес репутации: 1031
Tohin is a jewel in the roughTohin is a jewel in the roughTohin is a jewel in the rough
По умолчанию ШИМ для LED-лент энкодером

Поглядев на код с левитацией родилась дикая помесь прямого управления регистрами с функциями wiring:
Код:
/*   Управление 3 группами светодиодных лент
 *  Чтобы не забыть что делаю.
 *  нажатие - включить - выключить свет в комнате
 *  поворот в течении 3 секунд после включения - включение/выключение групп лент (не реализовано)
 *  нажатие в первые 3 секунды - переход к регулировки яркости(не реализовано)
 *  поворот после 3 секунд - регулировка яркости
 */


// Выводы ЭНКОДЕРА
#define CLK 5  // Clock Подключаем к INT1
#define DT 6  // второй вывод энкодера
#define SW 7  // switch кнопка энкодера

//#define debug 1

#define Min 0 // минимальное значение 
#define Max 255 //максимальное значение
#define step_bri 30       // шаг изменения яркости

#define set_bit(reg,value) reg |= (_BV(value))
#define set_2bit(reg,value, value2) reg |= ((_BV(value))|(_BV(value2)))
#define unset_bit(reg,value) reg &= ~(_BV(value))
#define unset_2bit(reg,value, value2) reg &= ~((_BV(value))|(_BV(value2)))
#define test_bit(reg,value) (reg & (1 << value))

int led = 9;           // the PWM pin the LED is attached to
int brightness = 0;    // how bright the LED is
volatile uint8_t ReadPortD;  //текущее состояние энкодера
volatile uint8_t ReadPortD_last; // начальное состояние энкодера
boolean power_sw =0; // последнее состояние энкодера



ISR(PCINT2_vect){      // сработало прерывание по энкодеру
  unset_bit (PCICR,PCIE2);  //отключаем прерывание, во избежании повторных срабатываний
  ReadPortD=PIND;   //записываем состояние порта B
}

void setup()  
{
  pinMode(CLK,INPUT_PULLUP); // Clock Подключаем к INT1, нельзя переназначать
  pinMode(DT, INPUT_PULLUP); // второй вывод энкодера
  pinMode(SW, INPUT_PULLUP); // кнопка энкодера
  pinMode(led, OUTPUT);    // управление симистором

 ReadPortD_last = PIND;         // весь порт D
#ifdef debug
    Serial.begin(9600);
    while (!Serial);
#endif
  set_bit (PCICR,PCIE2);//Включаем прерывание PCINT16-23 (PortD) PCIE2, регистр PCICR принимает значение  0b00000100;
  PCMSK2 |= (_BV(PCINT23)| _BV(PCINT22) | _BV(PCINT21)); //Указываем, что надо реагировать только на пины 5,7 (PD5,7, они же 5,7 на ардуине) 5 энкодер CLK(PCINT21), 7 кнопка энкодера
  // для порта D соответствуют pcint 16-23
    sei();//включаем прерывания
#ifdef debug
  Serial.println(PCMSK2,BIN);
  Serial.println("ready");
#endif
  analogWrite(led, 255);
  delay(1000);
  analogWrite(led, 0);
 

}


void loop()
{
  if (ReadPortD) {  // если сюда что-то записано, значит был поворот или нажатие кнопки, прерывания отключены. Надо бы не забыть их включить.
#ifdef debug
  Serial.println("int detect");
      Serial.print("Pind: ");
      Serial.println(ReadPortD,BIN);
#endif
    if (!test_bit(ReadPortD,SW)){ //а если кто-то нажал кнопку энкодера. Пины подтянуты к +5, значит нужно проверить переход бита в 0
#ifdef debug
      Serial.println("SW");
#endif
      on_off();
    }
    if ((!test_bit(ReadPortD,CLK))&&(test_bit(ReadPortD,DT))){   //не нравится мне 2 одинаковых if, но по другому я не придумал. тут мы проверяем, что сработал именно поворот, а не кнопка. Пины подтянуты к +5, значит нужно проверить переход бита в 0
                                                               // если пятый бит (CLK) равен 0, а 6 бит (DT) - еденице, значит вращение по часовой стрелке
        brightness += step_bri;    // прибавить яркость
      }
    if ((test_bit(ReadPortD,CLK))&&(!test_bit(ReadPortD,DT))){ //  если пятый бит (CLK) равен 1, а 6 бит (DT) - 0, значит вращали против часовой
        brightness -= step_bri;    // убавить яркость
      }
    if ((!test_bit(ReadPortD,CLK))||(!test_bit(ReadPortD,DT))){   
        brightness=constrain(brightness,0,255); //проверяем, что яркость находится в допустимых значениях
#ifdef debug
        Serial.println(brightness); //для дебага выводим значения яркости в консоль
#endif
        analogWrite(led, brightness); //и записываем измененную яркость в таймер.
    }

   ReadPortD=0; //мы все отработали, значит можно обнулить переменную
  }
  else{ // переменная равна нулю,
    if (!(test_bit (PCICR,PCIE2))&& PIND==ReadPortD_last){ //прерывания отключены, порт d стал равен состоянию при запуске, а значит все отпущено и можно работать дальше
      set_bit (PCICR,PCIE2);  //включаем прерывание. Вроде не забыл
    }
  }

}


void on_off(){
  power_sw =!power_sw;
  if (!power_sw){
    unset_2bit (PCMSK2,PCINT21,PCINT22); //перестаем реагировать на повороты энкодера
    analogWrite(led,0); //гасим всех
  }
  else{
     set_2bit (PCMSK2,PCINT21,PCINT22); // прерывания от Энкодера 
     analogWrite(led, brightness); 
  }
#ifdef debug
  Serial.print("PCMSK2: ");
  Serial.println(PCMSK2,BIN);
#endif
}
Отличия:
Мой энкодер оказался с глюком, поэтому пришлось использовать прерывание и на CLK и на DT


Удлинение провода от экодера
потерпело фиаско. При прямом подключении энкодера к дуине все хорошо. Но уже на 1.5 метрах начинаются пропуски срабатывания, при быстром вращении. Неужели емкость провода так сильно может влиять? Тот же Clunet имеет гораздо большую частоту и, по идее, от длинной трассы должен страдать больше.
При нажатии иногда бывают ложные срабатывания.
Придется заказывать еще пару promini и делать clunet или колдовать над кодом. Подумываю записывать состояние порта D в прерывании PCCINT в динамический буфер и потом выводить в Serial. Чтобы увидеть реальную картину.

Последний раз редактировалось Tohin; 11.08.2018 в 20:08.
Tohin вне форума   Ответить с цитированием
Старый 12.08.2018, 01:42   #2
Admin
Administrator
 
Аватар для Admin
 
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,618
Вес репутации: 9823
Admin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant futureAdmin has a brilliant future
По умолчанию

Цитата:
Неужели емкость провода так сильно может влиять?
Скорее емкости нужно бы подвесить на CLK и DT, Примерно от 0,01 до 0,1 мкФ
Admin вне форума   Ответить с цитированием
Ответ


Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход


Текущее время: 02:07. Часовой пояс GMT +3.


Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Яндекс.Метрика