Доброго времени суток Всем.
Поскольку в этой теме энкодер уже обсуждался, а резистивные кнопки - это основа конструкции: выложу пока здесь... Доведу до конечного вида - положу в "манипуляторы"
... короче джойстик i-Drive из говна и палок:
- Ардуино ПроМикро
- жменька радиодеталек
- энкодер за 50 рублей
- крутилка
Функционал и принцип - на картинках. Имеет два режима работы, распознает длительность нажатия, в итоговом варианте имеет подсветку кнопок и индикацию режима работы. На фото прототип, созданный для проверки догадочек и отладки кода. Сам скетч:
PHP код:
#include <avr/wdt.h>
#include <Mouse.h>
#include <Keyboard.h>
#include <Tablet.h>
// ----- пины Ардуино -----------------
#define KeyAppPin 0 // кнопка APPs
#define KeyModePin 1 // кнопка Mode
#define KeyEncPin 2 // кнопка энкодера
#define EncAcPin 3 // энкодер - канал А
#define EncBcPin 5 // энкодер - канал В
#define KeysPin A0 // кнопки управления
#define MousePin A1 // кнопки джойстика
#define LedPin 6 // светодиод медиа-режима
// ----- рабочие переменные -----------
unsigned long EventStart = 0; // момент нажатия
unsigned long TimePress = 0; // длительность нажатия
// ----- различные флаги --------------
volatile bool RightMove = false; // направления вращения энкодера
volatile bool LeftMove = false;
volatile bool EncPress = false; // нажатия кнопки энкодера
volatile bool AppPress = false; // кнопки APPs
volatile bool MediaMode = false; // кнопки MODE
// ----- обработчики прерываний -------
void EncoderMove() { // вращение энкодера
if (digitalRead(EncBcPin) == HIGH) {
RightMove = true;
}
else {
LeftMove = true;
}
}
void KeyEncPress() { // кнопка энкодера
EncPress = true;
}
void KeyAppPress() { // кнопка APPs
AppPress = true;
}
void KeyModePress() { // кнопка MODE
MediaMode = !MediaMode;
if (MediaMode){
digitalWrite(LedPin, HIGH);
}
else {
digitalWrite(LedPin, LOW);
}
}
void setup() {
pinMode(KeyModePin, INPUT_PULLUP); // кнопка "Mode" - управляем интерфейсом / медиа-функциями
attachInterrupt(digitalPinToInterrupt(KeyModePin), KeyModePress, FALLING);
pinMode(KeyAppPin, INPUT_PULLUP); // кнопка "APP" - при нажатии список запущеных приложений (ALT/TAB)
attachInterrupt(digitalPinToInterrupt(KeyAppPin), KeyAppPress, FALLING);
pinMode(KeyEncPin, INPUT_PULLUP); // кнопка энкодера - при нажатии PLAY/PAUSE либо ENTER/ESCAPE
attachInterrupt(digitalPinToInterrupt(KeyEncPin), KeyEncPress, FALLING);
pinMode(EncAcPin, INPUT_PULLUP); // канал-А энкодера - для отслеживания вращения
attachInterrupt(digitalPinToInterrupt(EncAcPin), EncoderMove, FALLING);
pinMode(EncBcPin, INPUT_PULLUP); // канал-В энкодера - для определения направления вращения
pinMode(LedPin, OUTPUT);
digitalWrite(LedPin, LOW);
analogReference(DEFAULT); // Aref = 5V, подтягивающий резистор на линии кнопок - 4,7 кОм
Keyboard.begin(); // инициализация USB-HID интерфейсов
Mouse.begin();
wdt_enable(WDTO_4S); // Активируем сторожевой таймер с интервалом 4 секунд
}
void loop() {
static bool FindKey; // признак найденной кнопки
static int DataKey; // значение ADC-кнопки
if (RightMove) { // обработка вращения энкодера: если вращаем вправо - увеличить громкость/стрелка вверх
if (MediaMode) {
Tablet.vol_up();
Tablet.clear();
}
else {
Keyboard.press(KEY_UP_ARROW);
Keyboard.release(KEY_UP_ARROW);
}
RightMove = false;
}
if (LeftMove) { // если вращаем влево - уменьшаем громкость/стрелка вниз
if (MediaMode) {
Tablet.vol_down();
Tablet.clear();
}
else {
Keyboard.press(KEY_DOWN_ARROW);
Keyboard.release(KEY_DOWN_ARROW);
}
LeftMove = false;
}
if (AppPress) { // кнопка "APPs"
Keyboard.press(KEY_LEFT_ALT);
while (digitalRead(KeyAppPin) == LOW) {
Keyboard.press(KEY_TAB);
Keyboard.release(KEY_TAB);
delay(1000);
wdt_reset();
}
Keyboard.release(KEY_LEFT_ALT);
AppPress = false;
}
if (analogRead(MousePin) > 800 && analogRead(KeysPin) > 800 && !EncPress) { // пока кнопки не нажаты взводим на всякий случай таймер обработки нажатия
EventStart = millis();
}
if (EncPress) { // обнаружили факт нажатия кнопки энкодера - определяем длительность нажатия
delay(20);
while (digitalRead(KeyEncPin) == LOW) { // пока не отпустим -
TimePress = millis() - EventStart; // считаем время нажатия
delay(10);
wdt_reset();
}
if (TimePress <= 200) { // действуем по длительности нажатия, если короткое:
if (MediaMode) { // в медиа-режиме - play/pause
Tablet.play_pause();
Tablet.clear();
}
else {
Keyboard.press(KEY_RETURN); // в режиме интерфейса - enter
Keyboard.release(KEY_RETURN);
}
}
else { // если длинное:
if (MediaMode) { // в медиа-режиме - mute
Tablet.mute();
Tablet.clear();
}
else { // в режиме интерфейса - escape
Keyboard.press(KEY_ESC);
Keyboard.release(KEY_ESC);
}
}
EncPress = false; // сбрасываем флаг нажатия
}
if (analogRead(MousePin) < 800) { // обнаружили факт нажатия кнопки джойстика
delay(20);
FindKey = false;
DataKey = analogRead(MousePin);
if (DataKey < 100 && !FindKey) { // кнопка "UP" - резистор 1 кОм
if (MediaMode) {
Tablet.forward();
Tablet.clear();
delay(100);
}
else {
Mouse.move(0, -10, 0);
}
FindKey = true;
}
if (DataKey < 350 && !FindKey) { // кнопка "LEFT" - резистор 2 кОм
if (MediaMode) {
Tablet.previous();
Tablet.clear();
delay(100);
}
else {
Mouse.move(-10, 0, 0);
}
FindKey = true;
}
if (DataKey < 600 && !FindKey) { // кнопка "RIGHT" - резистор 3,9 кОм
if (MediaMode) {
Tablet.next();
Tablet.clear();
delay(100);
}
else {
Mouse.move(10, 0, 0);
}
FindKey = true;
}
if (DataKey < 800 && !FindKey) { // кнопка "DOWN" - резистор 10 кОм
if (MediaMode) {
Tablet.rewind();
Tablet.clear();
delay(100);
}
else {
Mouse.move(0, 10, 0);
}
}
}
if (analogRead(KeysPin) < 800) { // обнаружили факт нажатия кнопки управления
delay(20);
FindKey = false;
DataKey = analogRead(KeysPin);
while (analogRead(KeysPin) < 800) {
TimePress = millis() - EventStart;
delay(10);
wdt_reset();
}
if (DataKey < 100) { // кнопка "Home/Menu" - на землю
if (TimePress <= 200) {
Tablet.home();
Tablet.clear();
}
else {
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_ESC);
Keyboard.releaseAll();
}
FindKey = true;
}
if (DataKey < 350 && !FindKey) { // кнопка "Enter/Esc" - резистор 1 кОм
if (TimePress <= 200) {
Mouse.click(MOUSE_LEFT);
}
else {
Mouse.click(MOUSE_RIGHT);
}
}
}
wdt_reset(); // производим периодический сброс таймера
}
За код не пинайте сильно - это ПЕРВАЯ моя программа для Ардуино в жизни. Скетч немножко не соответствует прототипу, а соответствует заказанным в Китае платам, уже скоро доедут
Исходники все здесь:
информация по пульту управления