PCCar.ru - Ваш автомобильный компьютер

PCCar.ru - Ваш автомобильный компьютер (http://pccar.ru/index.php)
-   Дополнительные устройства (http://pccar.ru/forumdisplay.php?f=177)
-   -   Резистивные кнопки под андроид (http://pccar.ru/showthread.php?t=18478)

mazay66 06.03.2019 21:03

Цитата:

Сообщение от Alex15BV (Сообщение 408005)
Сам скетч:
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(LedPinHIGH);
  }
  else {
    
digitalWrite(LedPinLOW);
  }
}

void setup() {
  
pinMode(KeyModePinINPUT_PULLUP);                                          // кнопка "Mode" - управляем интерфейсом / медиа-функциями
  
attachInterrupt(digitalPinToInterrupt(KeyModePin), KeyModePressFALLING);
  
pinMode(KeyAppPinINPUT_PULLUP);                                           // кнопка "APP" - при нажатии список запущеных приложений (ALT/TAB)
  
attachInterrupt(digitalPinToInterrupt(KeyAppPin), KeyAppPressFALLING);
  
pinMode(KeyEncPinINPUT_PULLUP);                                           // кнопка энкодера - при нажатии PLAY/PAUSE либо ENTER/ESCAPE
  
attachInterrupt(digitalPinToInterrupt(KeyEncPin), KeyEncPressFALLING);
  
pinMode(EncAcPinINPUT_PULLUP);                                            // канал-А энкодера - для отслеживания вращения
  
attachInterrupt(digitalPinToInterrupt(EncAcPin), EncoderMoveFALLING);
  
pinMode(EncBcPinINPUT_PULLUP);                                            // канал-В энкодера - для определения направления вращения
  
pinMode(LedPinOUTPUT);
  
digitalWrite(LedPinLOW);

  
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, -100);
      }
    
FindKey true;
    }
    if (
DataKey 350 && !FindKey) {       // кнопка "LEFT" - резистор 2 кОм
      
if (MediaMode) {
        
Tablet.previous();
        
Tablet.clear();
        
delay(100);
      }
      else {
        
Mouse.move(-1000);
      }
    
FindKey true;
    }
    if (
DataKey 600 && !FindKey) {       // кнопка "RIGHT" - резистор 3,9 кОм
      
if (MediaMode) {
        
Tablet.next();
        
Tablet.clear();
        
delay(100);
      }
      else {
        
Mouse.move(1000);
      }
    
FindKey true;
    }
    if (
DataKey 800 && !FindKey) {       // кнопка "DOWN" - резистор 10 кОм
      
if (MediaMode) {
        
Tablet.rewind();
        
Tablet.clear();
        
delay(100);
      }
      else {
        
Mouse.move(0100);
      }
    }
  }
  
  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();                            // производим периодический сброс таймера



Подскажите, с какой целью в скетч добавлена функция watchdog? Механизм watchdog встроен в контроллеры Atmega, но, не всякий загрузчик (bootloader) Arduino правильно обрабатывает эту функцию и система заходит в жестокий bootloop. Как в этой ситуации ведет себя про микро?

Alex15BV 06.03.2019 21:21

Цитата:

Сообщение от mazay66 (Сообщение 409107)
Подскажите, с какой целью в скетч добавлена функция watchdog? Механизм watchdog встроен в контроллеры Atmega, но, не всякий загрузчик (bootloader) Arduino правильно обрабатывает эту функцию и система заходит в жестокий bootloop. Как в этой ситуации ведет себя про микро?

Добрый вечер.
Добавлена именно по прямому назначению: сбросить контроллер в случае зависания программы. Когда начал заниматься этим вопросом - тоже помучался. И оптибут пробовал, и МК убивал, и читал кучу статей всяких разных...
А потом товарищ показал, как он сделал у себя: я повторил, и оно заработало "как есть" - с оригинальным бутлоадером и вышеизложеным скетчем.

mazay66 06.03.2019 21:57

Т.е оптибут не обязательно? Оригинальный бутлоадер не уйдет в bootloop? А насколько часто зависает устройства без отсутствия этой функции?
P.S. Я вот думаю, что mic5219 можно исключить из схемы, если питать устройство стабилизированным напряжением планшета или mp1584. ИХМО, это тот случай, когда на плате про микро предусмотрена возможность замыкания перемычки J1

Alex15BV 06.03.2019 22:13

Цитата:

Сообщение от mazay66 (Сообщение 409109)
Т.е оптибут не обязательно? Оригинальный бутлоадер не уйдет в bootloop? А насколько часто зависает устройства без отсутствия этой функции?
P.S. Я вот думаю, что mic5219 можно исключить из схемы, если питать устройство стабилизированным напряжением планшета или mp1584. ИХМО, это тот случай, когда на плате про микро предусмотрена возможность замыкания перемычки J1

1. Когда в первый раз добавил собаку - МК ушёл в бутлуп, пришлось перешивать через программатор. Прошил оптибут - вообще Дуню убил, восстанавливал путем подмены файлов в системных папках ИДЕ и ручного редактирования конфигов. Вернул всё назад и отказался от ВДТ... А потом вдруг заработало само. За всё время экспериментов зависания были два раза (оно было на промежуточных версиях, но "береженого Бог бережёт"). На крайней версии скетча глюков не было пока.
2. Я просто перенёс на плату Дуню один-в-один. Можно, конечно, питание сделать по нормальному - но я просто не задумался об этом (коли за 200 рублей мне дают полный набор комплектующих)...

skanch 07.03.2019 00:32

Цитата:

Сообщение от mazay66 (Сообщение 409109)
... Я вот думаю, что mic5219 можно исключить из схемы, если питать устройство стабилизированным напряжением планшета или mp1584...

С Pro Micro работал мало, в основном с Pro Mini, но стабилизаторы на этих китайских платах стоят как правило одинаковые. И если сравнивать потребление платой (Pro Mini) на родном стабилизаторе и от MP1584, то mic5219 - это почти 25-30 мА, а MP1584 9-12мА. И ещё один момент: по даташиту максимальное напряжение на mic5219 до 20В, но почему-то мрут уже на 14В... Поэтому если делаешь с "нуля", лучше питание на MP1584.

mazay66 07.03.2019 10:30

skanch, Это все верно, если питать схему джойстик от бортовой сети авто. Но как я понял, в данном случае, устройство питается от хаба. Т.е. получает уже стабилизированное напряжение +5В. И далее по схеме модуля Про Микро, через диод Шотки идет на понижающий стабилизатор 5В - MIC5219. Получается "масло масляное". А вот если питать джойстик от бортовой сети, а не от хаба, то понижающий стабилизатор нужен.

skanch 07.03.2019 11:08

Цитата:

Сообщение от mazay66 (Сообщение 409119)
skanch, Это все верно, если питать схему джойстик от бортовой сети авто. Но как я понял, в данном случае, устройство питается от хаба. Т.е. получает уже стабилизированное напряжение +5В. И далее по схеме модуля Про Микро, через диод Шотки идет на понижающий стабилизатор 5В - MIC5219. Получается "масло масляное". А вот если питать джойстик от бортовой сети, а не от хаба, то понижающий стабилизатор нужен.

Если ProMicro используется по назначению в виде "джойстика", то питание идёт по линии USB и при этом любое внешнее питание должно быть отключено. На "фирменных" платах Arduino Micro стоят ключи автоматического отключения линии внешнего питания при подключении USB штеккера. На китайских клонах этого нет. Если повторить трассировку печатной платы китайского клона, то просто стабилизатор не использовать, а линии питания VCC, VCC1, AVCC, AVCC1, UVCC и VBUS должны быть соединены и питание заводить по линии от HUB-а. Или делать отдельный DC-DC преобразователь прямо на плате, но линию "плюс" от USB нужно разрывать.

mazay66 14.05.2019 12:34

Вложений: 4
Цитата:

Сообщение от Alex15BV (Сообщение 408012)
Если честно, я выкладываю свои поделки скорее как "идеи", нежели как "проекты"... Как их использовать (копировать полностью, или брать только нужное, а или игнорировать вовсе) - это уж каждый сам решает.

Отпишусь и я по результатам теста собранного изделия. За основу взята идея уважаемого Алексея (Alex15BV). Немного изменена схема питания платы (убрал лишние, на мой взгляд, элементы, добавил пару диодов). Вообщем ничего существенного. Частично изменил функционал и назначение кнопок, для чего пришлось "поковырять" скетч. В результате, получилось, что 9 кнопок и энкодер выполняют более 25 различных задач, которые полностью перекрыли мои "хотелки". Зафиналил два изделия. Распаивал параллельно две платы в надежде на то, что хоть одна да заработает. Заработали обе, нигде не "накосячил".
Подобрал корпус. На мой взгляд, немного не эстетично. Тут, ИХМО, лучше встраивать плату в обшивку/отделку автомобиля, предварительно определившись с местом в авто. Сейчас, в Рено Колеос, это выглядит как на фото. Есть желание убрать корпус и разместить плату джойстика в этой же нише, закрыв её. Ну и что бы "разбавить сухой" текст, выкладываю несколько фото и ссылку на видео получившегося устройства.
P.S. После того, как были потрачено много времени, нервов и денег в поисках подходящего устройства ( на фото только некоторые из них) для управления автомобильным планшетом, наконец-то обрел то, что хотел. Основные недостатки трекбола, клавиатуры и пр. кнопок - не полный функционал управления, не эстетичный вид и габариты, опасность/невозможность использования в движении, т.к. требуется концентрация внимания на устройстве. В получившемся джойстике управление интуитивно понятно и не требует отвлечения. Еще раз спасибо Алексею за идею.

Alex15BV 24.05.2019 13:29

Цитата:

Сообщение от mazay66 (Сообщение 410060)
Отпишусь и я по результатам теста собранного изделия. За основу взята идея уважаемого Алексея (Alex15BV). Немного изменена схема питания платы (убрал лишние, на мой взгляд, элементы, добавил пару диодов). Вообщем ничего существенного. Частично изменил функционал и назначение кнопок, для чего пришлось "поковырять" скетч. В результате, получилось, что 9 кнопок и энкодер выполняют более 25 различных задач, которые полностью перекрыли мои "хотелки"...

Приветствую.
Отличная реализация! Самому пока не получается заниматься... Полно бытовых проблем. Прочитал сообщение, увидел фразу "... более 25 различных задач..." - посетила идея: ведь кнопка "MODE" может по кругу переключать флаг режима. В итоге имеем "страничную" систему, уползаем с if на case - и получаем индивидуальную работу пульта под разные ситуации. :unsure2:

mazay66 24.05.2019 15:23

Я ограничился тремя режимами MODE - мышь, клавиатура и медиа. Причем, case - не стал использовать, что бы не переключаться "по кругу". У меня короткое нажатие всегда переключает между режимом мыши и клавиатурой. Длинное нажатие всегда включает режим МЕДИА (из любого положения). Так, показалось, удобнее.


Часовой пояс GMT +4, время: 14:35.

Работает на vBulletin® версия 3.8.4.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot