11.08.2018, 20:06 | #1 |
Moderator
Регистрация: 20.07.2014
Адрес: МСК
Сообщений: 991
Вес репутации: 1031 |
ШИМ для 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. |
12.08.2018, 01:42 | #2 | |
Administrator
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,618
Вес репутации: 9823 |
Цитата:
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1) | |
|
|