Загорелся идеей таки прикрутить к сабжу энкодер - напрашивается поставить доп. контролер, чеб он имитировал нажатие кнопок "+", "-". У сабжа большая плата, ей бы дисплей 3,2" да энкодер.
Нашел в сети одну реализацию:
https://github.com/kuwatay/AVR/tree/mas ... for-dso138
но приспичило попытаться самому. Мутить как мутить - дополнил еще кнопкой ходить по режимам в обратную сторону (пять "нажатий" на SEL). И чтоб быстрый поворот энкодера отрабатывался как удержание кнопки для "прыжков".
Делается или покупается маленькая платка с attiny13 / attiny85 / atmega328.
МК, стабилизатор и минимум обвязки (в корпусе приклеиваем рядом с энкодером).
К платке: 2 провода от энкодера, 1 - от кнопки, 1 - их общий корпусной;
с платы сабжа: корпусной, +V и от кнопок "+", "-", "SEL".
Пока прошивку написал только под atmega328p (Mini Pro, других у меня пока нет), во фьюзах изменил один бит - включил прескалер на 8. Писал в eclipse. В свойствах проекта: atmega328p, частота 2000000. Не все еще гладко, для эргономики надо с задержками поиграться, да и 60-ю сабжевую надо попробовать поковырять - время удержания кнопки уменьшить до секунды и "прыжок" увеличить с 10 до 20-25 точек.
Спойлер
/*энкодер для dso138
пока только на Mini Pro atmega328p 16MГц/8 в фьюзах включен бит деления на 8
имитация нажатия кнопок "+","-","sel"
быстрый поворот энкодера - имитируется удержание кнопки на 2сек.
доп. кнопка - 5 раз имитируется нажатие кн."sel"
подключение к кнопкам прямое, без развязывающих транзистеров
0, 1, 2 линии порта C - энкодер и доп. кнопка
0, 1, 2 линии порта В - в параллель к кнопкам "+","-","sel"
таймер 0 - исп. для определения насколько шустро крутанулся энкодер
таймер watchdog (собака) - для секундного удержания кнопки,
имеется счетчик "прыжков" - напр., 3 быстрых поворота - около трех "нажатий" с удержанием - прыжки
*/
#include <avr/io.h>
#include <avr/interrupt.h>
//#include "bits_macros.h"
#include "util/delay.h"
#include "avr/wdt.h"
#define ENC_F1 (1 << 0) // опрос. фаза энкодера F1
#define ENC_F2 (1 << 1) // опрос. фаза энкодера F2
#define BOTT_F (1 << 2) // опрос. кнопки "5 раз на SEL"
#define UP (1 << 0) // линия на кнопку "+"
#define DOWN (1 << 1) // линия на кнопку "-"
#define SEL (1 << 2) // линия на кнопку "sel"
#define Pin_ENC_F1 (PINC & ENC_F1)
#define Pin_ENC_F2 (PINC & ENC_F2)
#define Pin_BOTT (PINC & BOTT_F)
#define Pin_UP (PINB & UP)
#define Pin_DOWN (PINB & DOWN)
enum { State0, StateA, StateB, StateAB }; //состояния энкодера
static char EncPrev; //предыдущее состояние энкодера
static char EncPrevPrev; //пред-предыдущее состояние энкодера
volatile uint8_t F1=0; // флаг по таймеру опроса
volatile uint8_t F2=0; // флаг по таймеру удержания (таймер watchdog'a)
volatile int8_t Cj=0; // счетчик прыжков
volatile uint8_t Enc=128; // признак по энкодеру
volatile uint8_t Bott=0; // признак по кнопке
#define TCNT0_const 0 // начальное значение таймера опроса (максимальная длительность), счетчик 8-битный
//------------------------- Опрос энкодера и кнопки: ------------------------------
void PinScan(void)
{
PORTB |= (1 << 5); // светодиод зажечь - индикация опроса
if(!Pin_BOTT) Bott=1; // проверка кнопки
else {
// for (int i=0; i<2; i++) { //t1 увеличение длительности опроса, 2 - 3 прохода таймера
F1=0;
TCCR0B |=(1<<CS02)|(1<<CS00); // запуск таймера на опрос
while (F1==0){ // опрос энкодера в цикле
char EncCur = 0;
if(!Pin_ENC_F1) EncCur = StateA; //опрос фазы 1 энкодера
if(!Pin_ENC_F2) EncCur |= StateB; //опрос фазы 2 энкодера
if(EncCur != EncPrev) {
if(EncPrev == StateAB && //если предыдущее состояние StateAB
EncCur != EncPrevPrev ) { //и текущее и пред-предыдущее не равны,
if(EncCur == StateB) //если текущее состояние StateB,
Enc++; //шаг вверх
else //иначе
Enc--; //шаг вниз
}
EncPrevPrev = EncPrev; //сохранение пред-предыдущего состояния
EncPrev = EncCur; //сохранение предыдущего состояния
}
}
// } //коментировать/раскоментировать вместе со строкой выше (t1)
EncPrev = State0;
EncPrevPrev = State0;
}
if(!Pin_BOTT) Bott=1; // после таймера, еще раз проверка кнопки
PORTB &= ~(1 << 5); // светодиод потушить
}
ISR(WDT_vect){ // обработчик таймера удержания кнопки (watchdog)
wdt_reset();
wdt_disable(); // выключение таймера удержания
F2=1; // выставляем признак - таймер оттикал
}
ISR(TIMER0_OVF_vect) { // обработчик таймера опроса энкодера
TCCR0B = 0b00000000; // таймеру - стоп
F1=1; // выставляем признак - таймер оттикал
}
//______________
int main( void )
{
MCUSR = 0x00; //очистка собачих флагов (watchdog'a) - на нем таймер удержания
//настройка портов
DDRB = (1 << 5); // штатный светодиод платки Mini Pro - горит во время опроса
DDRB = 0; // ноги порта В - вход
// DDRB &= ~(UP | DOWN | SEL); // оно же, но только для определенных ног
DDRC &= ~(ENC_F1 | ENC_F2 | BOTT_F); //настройка порта на ввод
PORTC |= ENC_F1 | ENC_F2 | BOTT_F; //включение подтягивающих резисторов
//инициализация таймера т0 (опросный)
TCNT0 = TCNT0_const;
TCCR0A = 0b00000000;
TCCR0B = 0b00000000;
TIMSK0 |= (1<<TOIE0);
F2=0; //обнуление признака
EncPrev = State0; // и статусов энкодера
EncPrevPrev = State0;
//ClearBit(PORTB, 5);
sei(); // разрешение прерываний
while(1)
{
Bott=0;
Enc= 128;
PinScan(); // уходим на опрос обнулив признаки
//--------Обработка - что принес опрос---------------------------
if ((Bott == 1) & (Cj == 0)) { //если кнопка нажата и прыжков нет
Enc = 128; // обнуляем энкодер - игнорируем
for (int i=0; i<5; i++){ // ногодрыг по линии кнопки sel, 5 раз
DDRB |= (SEL); // нога режим - выход
PORTB &= ~(SEL); // в линию "0"
_delay_ms(50);
DDRB &= ~(SEL); // возвращаем по ноге режим - вход
_delay_ms(50);
}
_delay_ms(30); // еще чуток ждем
}
if (Cj !=0) _delay_ms(260); // эргономика. задержка перед следующим опросом, если уже есть прыжки
if (Enc != 128){ //если было вращение энкодера
if (Enc>129) Cj++; // добавляем прыжок на счетчике, направление "+"
if (Enc<127) Cj--; // добавляем прыжок на счетчике, направление "-"
if ((Enc==129)&(Cj == 0)) { // если на энкодере один шаг и нет прыжков имитируем кнопку
DDRB |= (UP); // линию на выход
PORTB &= ~(UP); // в линию "0"
_delay_ms(50);
DDRB &= ~(UP); // возвращаем по ноге режим - вход
_delay_ms(60);
}
if ((Enc==127)&(Cj == 0)) { // щаг в другую сторону - имитируем другую кнопку
DDRB |= (DOWN);
PORTB &= ~(DOWN);
_delay_ms(50);
DDRB &= ~(DOWN);
_delay_ms(60);
}
}
if (Cj > 0) { // если счетчик прыжков выше нейтрали :
if (~(!Pin_UP) & (F2==0)) { // если еще нет удержания и нет признака от таймера
DDRB |= (UP); // линию на выход
PORTB &= ~(UP); // в линию "0"
wdt_enable(WDTO_2S); // таймер (watchdog) на 2сек
WDTCSR=(1<<WDIE); // старт и разрешение прерывания от таймера
}
if (F2==1) { // если есть признак, что таймер отработал :
DDRB &= ~(UP); // возвращаем по ноге режим - вход
F2=0; // очищаем признак
Cj--; // счетчик -1
_delay_ms(60); // пауза между "нажатиями"
}
}
if (Cj < 0) { // если счетчик прыжков ниже нейтрали :
if (~(!Pin_DOWN) & (F2==0)) { // аналогично для другой линии
DDRB |= (DOWN);
PORTB &= ~(DOWN);
wdt_enable(WDTO_2S);
WDTCSR=(1<<WDIE);
}
if (F2==1) {
DDRB &= ~(DOWN);
F2=0;
Cj++;
_delay_ms(60);
}
}
} //while
return 0;
}
Да и если кто свое предложит - милости просим.
В архиве: прошивка и main.c


