Перейти к содержанию

Управление меню с помощью трёх кнопок (Си)


-=FISHER=-

Рекомендуемые сообщения

11 минут назад, -=FISHER=- сказал:

Обычно я это делаю вот такими функциями

Только настоятельно рекомендую делать из static - в целях экономии памяти. И подавление дребезга (если _delay_ms(3) служит этому) лучше делать прямо в get_button.

12 минут назад, -=FISHER=- сказал:

как при таком подходе мне отловить длительно нажатие?

Да так же, как и ранее: в get_code анализируйте длительность сохранения одинакового кода, возвращаемого get_bгttons, и реагируйте соответственно.

 

Дополнительно и альтернативно предлагаю рассмотреть вариант с программными (или аппаратными, если есть) таймерами, вы раньше делали такое уже.

Настраиваете один такой таймер на 100 Гц, и в его функции опрашиваете состояние пинов кнопок, помещая результат в глобальную переменную. Это и будет состояние кнопок, дополнительно уже не надо дребезг давить, он уже будет подавлен.

uint8_t btn_state; // это та самая переменная с кодом нажатых кнопок из таймерной функции

typedef enum{
  CMD_NONE,
  CMD_SET_HOUR,
  CMD_SET_MIN,
  ...
} command_t;

command_t get_command(void){
  static uint8_t prev_btn;

  if(btn_state != prev_btn){
    prev_btn = btn_state;
    if(btn_state == 0){
      stop_timer(LONG_PRESS_TMR);
      return CMD_NONE;
    }
    start_timer(LONG_PRESS_TMR);
    // здесь надо вычислить команду по значению btn_state и вернуть его
    // для примера я считаю, что команда совпадает со значением btn_state
    return btn_state;
  }
  if(!timeout_timer(LONG_PRESS_TMR)) return CMD_NONE;
  // здесь надо вычислить команду по длительному удержанию кнопок в btn_state и вернуть эту команду
  // заодно можно сделать автоповтор путем перезапуска таймера
  return ...
}

Написал сгоряча такую функцию - вроде должна работать...

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

14 часов назад, -=FISHER=- сказал:

но я совсем не могу придумать, как при таком подходе мне отловить длительно нажатие?

 

добавить повторный опрос портов через заданный интервал, если значение не изменилось значит долгое нажатие и изменяем значение code простым добавлением какого либо числа большего чем максимальное значение к примеру 0х0F(если используется младшие разряды порта и не больше 4-х), либо 1 при условии НЕ использования 0-го разряда порта.    Потом в функции по значению определяете имя команды. Что-то вроде этого (в синтаксисе могут быть ошибки).

uint8_t get_button(void)
{
    return PINB;
}

uint8_t get_code(void) //опрос портов
{
    code=get_button();
    _delay_ms(3);
    if(code!=get_button()){code=ERROR;}
    else {_delay_ms(10);
        if(code == get_button()){ code = code + 0xF0; //или code++;
         }; };
    return code;
}

//*****************************************

coDcoM = get_code();
switch (coDcoM) {
    case 0x01: command=KN1;  // короткое нажатие
    break;
    case 0xF1: command=KN1L;  // долгое нажатие
    break;
       .........
    }; 

 

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

16 часов назад, ARV сказал:

Написал сгоряча такую функцию - вроде должна работать...

Мне кажется что при такой логике, сначала в любом случае выполнится действие от короткого нажатия, а потом если кнопку не отпускать то от длинного. Поправьте пожалуйста, если не прав.

Мне кажется нужно выполнять действие от короткого нажатия при отпускании кнопки, а от длинного при нажатии.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Организация питания на основе надежных литиевых аккумуляторов EVE и микросхем азиатского производства

Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Именно так. Я ранее писал, что вариант "реакция на отпускание" проще, но для пользователя менее удобен. Представьте себе, как бы писали текст, если бы буквы появлялись при отпускании клавиш...

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

33 минуты назад, -=FISHER=- сказал:

Мне кажется нужно выполнять действие от короткого нажатия при отпускании кнопки, а от длинного при нажатии

Даже любопытно, каким именно способом вы обнаружите начало длинного нажатия, чтобы среагировать на него в момент нажатия :) 

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока (материалы вебинара)

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

На вебинаре мы представили информацию не только по линейкам аккумуляторной продукции EVE, но и по решениям для управления ею, что поможет рассмотреть эти ХИТ в качестве дополнительной альтернативы для уже выпускающихся изделий. Также рассмотрели нюансы работы с производителем и сервисы, предоставляемые Компэл по данной продукции. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

1 час назад, ARV сказал:

Даже любопытно, каким именно способом вы обнаружите начало длинного нажатия,

По-моему это как раз просто, нажали кнопку - начали считать длинное нажатие, досчитал допустим до 0.5 секунды - выполнили действие, а когда отпустили, если не было длинного нажатия, значит произошло короткое.

1 час назад, ARV сказал:

Именно так.

Это вы на первое мое "мне кажется" написали или на второе?

1 час назад, ARV сказал:

 Я ранее писал, что вариант "реакция на отпускание" проще, но для пользователя менее удобен.

Я согласен полностью, но мне кажется что ещё более неудобно, если пользователь хочет выполнить действие от длительного нажатия, но сначала получает от короткого, а потом от длинного. 

Или я чего-то не понял, поясните пожалуйста.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

19 минут назад, -=FISHER=- сказал:

По-моему это как раз просто, нажали кнопку - начали считать длинное нажатие, досчитал допустим до 0.5 секунды - выполнили действие, а когда отпустили, если не было длинного нажатия, значит произошло короткое.

Ничего не понял. Условие: короткое нажатие при отпускании, а длинное в момент нажатия - вы же так писали ранее? Но короткое тоже начинается с нажатия! Как же вы отличие эти нажатия друг от друга?

Я надавил кнопку - в этот момент, по вашему, МК должен прочесть мои мысли и, если я собрался жать долго, то сразу сработать, а если я собрался отпустить кнопку быстро, то МК должен дождаться этого момента и потом уж срабатывать. :)

19 минут назад, -=FISHER=- сказал:

ещё более неудобно, если пользователь хочет выполнить действие от длительного нажатия, но сначала получает от короткого, а потом от длинного. 

А вы продумайте интерфейс так, чтобы это не было неудобным. В клавиатуре компьютера такое поведение же вас устраивает?

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

17 минут назад, ARV сказал:

Ничего не понял.

1. Нажали кнопку - считаем время, если кнопка нажата более 0.5 секунды, выполняем действие по длинному нажатию.

2. Отпустили кнопку - смотрим, сколько кнопка была в нажатом состоянии, если меньше полсекунды, то выполняем действие по короткому нажатию, если же полсекунды, то ничего не делаем.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

То есть всё-таки оба варианта по отпусканию... Но 0,5 сек это совсем не долгое нажатие. Долгое это не менее 2 сек.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

@ARV Я кажется почти придумал как избавиться от длинных нажатий: кнопка set заходит в меню, далее + и - навигация по пунктам меню, что бы зайти в выбранный пункт нажимаем опять set, далее + и - настраиваем выбранный параметр. Потом опять нажимаем set, выходим в меню, пролистываем кнопкой + до последнего пункта и выходим из меню и попадаем в режим отображения.

Все нажатия короткие. Достаточно эргономично?..

6 минут назад, ARV сказал:

То есть всё-таки оба варианта по отпусканию... 

Да почему же? Длинное нажатие срабатывает когда кнопка удерживается нажатой определенное время.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Я бы на вашем месте с многоуровневым меню вообще не заморачивался. Нажали Set - что-то замигало, надо изменить - меняем плюсом и минусом, не надо - жмем Set ещё раз, начинает мигать что-то другое... И так далее.

Вместо загадочных символов показывать сразу эффект, например...

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

@ARV А ещё Вы можете пояснить момент с тем, что если опрашивать состояние кнопок в прерывании с частотой 100 Гц, то антидребегз в таком случае не нужен?

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Так за 10 мс дребезг успеет окончиться...

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

3 часа назад, -=FISHER=- сказал:

если же полсекунды, то ничего не делаем

зачем же? пусть будет больше или равно.

2 часа назад, ARV сказал:

Я бы на вашем месте с многоуровневым меню вообще не заморачивался. Нажали Set - что-то замигало, надо изменить - меняем плюсом и минусом

именно это я ему выше расписал - не меню, а просто список параметров.

27 минут назад, -=FISHER=- сказал:

если опрашивать состояние кнопок в прерывании с частотой 100 Гц, то антидребегз в таком случае не нужен?

да, бороться с дребезгом не нужно.

я при опросе кнопок увеличиваю счетчик кнопки. даже если из-за дребезга будет пропуск нажатого состояния (и то в самый момент нажатия), счетчик все равно накопит некоторое число.

но у меня длинное нажатие сделано 1 секунда или более.

потом в главном цикле проверяю счетчик кнопки. и у меня 3 варианта проверки:

1. при отпущенной кнопке - если есть в счетчике число, то это было короткое нажатие, и выполняем работу по короткому нажатию.

2. при нажатой кнопке - если число >= 100, то было длинное нажатие, и выполняем работу по длинному нажатию.

3. при нажатой кнопке - если число меньше 100, то ничего не делаем (а вдруг это еще длится короткое нажатие?).

таким образом, у меня короткое нажатие - от 1 до 99. правда, трудно себе представить, что кто-то умудрился сделать нажатие менее 20 мс.

3 часа назад, -=FISHER=- сказал:

Я кажется почти придумал как избавиться от длинных нажатий: кнопка set заходит в меню, далее + и - навигация по пунктам меню, что бы зайти в выбранный пункт нажимаем опять set, далее + и - настраиваем выбранный параметр. Потом опять нажимаем set, выходим в меню

именно это я тебе выше подробно расписал. причем, вообще без длинных нажатий.

и, в данном случае, выход не из меню, а из настройки параметра.

Мудрость приходит вместе с импотенцией...

Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.

Ссылка на комментарий
Поделиться на другие сайты

Понимаете, в чем дело, я хочу, чтобы было именно меню.

То есть нажимая + и - в обычном режиме отображения, чтобы по кругу менялись часы, температура и вольтметр.

А если нажать SET, то открывается меню и от + и - уже по кругу меняются пункты меню, с названиями настроек.

Там соответственно на выбранной настройке нажимаем SET и открывается мигающие численное значение параметра ну или мигающие часы.

А что касается антидребезга, ведь нужно все равно какой-то счётчик заводить, чтобы после первого же вхождения в get_code не срабатывало действие, а только после второго или третьего предположим. Или нет? Нельзя же допускать запуска процедуры после первого же полученного кода?

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

13 часов назад, -=FISHER=- сказал:

То есть нажимая + и - в обычном режиме отображения, чтобы по кругу менялись часы, температура и вольтметр.

А если нажать SET, то открывается меню и от + и - уже по кругу меняются пункты меню, с названиями настроек.

ну и чем отличается твое желания от описанного мною алгоритма работы?

13 часов назад, -=FISHER=- сказал:

Нельзя же допускать запуска процедуры после первого же полученного кода?

если не будет длинных нажатий, то можно запускать от первого найденного нажатия. но при этом нужно ставить флаг блокировки клавиатуры, чтобы не было повторной обработки нажатой кнопки.

а флаг блокировки клавиатуры сбрасывать только когда все кнопки отпущены.

Мудрость приходит вместе с импотенцией...

Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, Starichok сказал:

если не будет длинных нажатий, то можно запускать от первого найденного нажатия. но при этом нужно ставить флаг блокировки клавиатуры, чтобы не было повторной обработки нажатой кнопки.

а флаг блокировки клавиатуры сбрасывать только когда все кнопки отпущены

Я короче не правильно понимал дребезг контактов. Ведь сама по себе кнопка нажиматься не может, поэтому вполне можно реагировать сразу на первое же нажатие. Другое дело что во время первого нажатия от дребезга в течении короткого времени появляются ещё хаотичные отжатия и нажатия, пока кнопка не устаканится в нажатом положении. И если проверять состояние кнопки раз в 10 мс, то получается что пока придёт время следующей проверки, кнопка уже устаканится.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

кста энкодер заменяет 3 кнопки. Конструкцию можно сделать более компактной. Другое дело, что обработка энкодера немного отлична от кнопок

В поисках работы..

Looking for job

Ссылка на комментарий
Поделиться на другие сайты

16 минут назад, fuckir сказал:

кста энкодер заменяет 3 кнопки.

Да вы правы, но я делаю плату в уже существующие автомобильные часы, а там именно 3 кнопки

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Тогда вам следует изучить MicroMenu в качестве примера одного из подходов в создании многоуровневых меню, или примеры вашего покорного слуги - ссыли ранее давал, но можно и из других моих проектов, правда, придетс поискать :)

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

On 4/9/2020 at 1:41 PM, -=FISHER=- said:

как сделать чтобы кнопка понимала что в настройках минут, нужно менять только от 0 до 59

Можно вот так, например. В главном цикле 20 раз в секунду опрашиваем кнопки get_button() и передаём код нажатой кнопки для исполнения в do_button().

Spoiler

#define BUT_UP        1 << 0     // кнопка на PIN0
#define BUT_DOWN    1 << 1    // кнопка на PIN1
#define BUT_SET        1 << 2    // кнопка на PIN2
#define ANY_K        (BUT_UP | BUT_DOWN | BUT_UP)

// Перечисляем все возможные состояния
enum Mode{MODE_TIME_VIEW, MODE_VOLT_VIEW, MODE_TEMP_VIEW, MODE_SET_HOURS, MODE_SET_MINUTES, ....}

int mode = MODE_TIME_VIEW;

int main()
{
    int but;
    
    while(1)
    {
        but = get_button();
        do_button(but);
        delay_ms(50);
    }
}

int get_button()    // для кнопок при нажатии PIN = 1, при отпускании PIN = 0
{
    static int old_but = 0;
    int res;
    int new_but;

    new_but = PINB & ANY_K;        // считать состояние кнопок
    res = old_but ^ new_but;     // изменилось состояние кнопок?
    res &= new_but;                // выделяем фронт нажатия
    old_but = new_but;            // сохраняем состояние кнопок для следующего раза
    
    return res; // возвращает 0 если нет фронта нажатия, или возвращает BUT_UP, BUT_DOWN, BUT_SET
}

void do_button(int but)
{

    if(but == 0) return;
    
    switch(mode)
    {
         case MODE_TIME_VIEW:
            if(but == BUT_UP) mode = MODE_VOLT_VIEW;
            if(but == BUT_DOWN) mode = MODE_TEMP_VIEW;
            if(but == BUT_SET) mode = MODE_SET_HOURS;
            break;                

        case MODE_TEMP_VIEW:
            .......
            break;
            
        case MODE_VOLT_VIEW:
            ......
             break;    
            
       case MODE_SET_HOURS:
            if(but == BUT_UP) 
            {
                if(hours<23)hours++;
                else hours = 0;
            }
            if(but == BUT_DOWN)
            {
                if(hours>0)hours--;
                else hours = 23;
            }
            if(but == BUT_SET) mode = MODE_SET_MINUTES;
            break;

        case MODE_SET_MINUTES:
            if(but == BUT_UP)
            {
                if(minutes<59) minutes++;
                else minutes == 0;
            }
            if(but == BUT_DOWN)
            {
                if(minutes>0)minutes--;
                else minutes = 59;
            if(but == BUT_SET) mode = MODE_TIME_VIEW;
            break;
        
        ......
    }
}


 

 

Ссылка на комментарий
Поделиться на другие сайты

1 - Почитайте этот цикл. Цикл статей Татарчевского

2 - http://easyelectronics.ru/organizaciya-drevovidnogo-menyu.html

Меню я сделал так: названия взял с easyelectronics, но за основу взял оригинал 1 версия. Есть 2 версия. Деталей уже не помню, потому как несколько лет назад наткнулся. Сейчас пользуюсь собственной переработкой этих проектов. Могу выложить проект-пример, но на это нужно время.

Ссылка на комментарий
Поделиться на другие сайты

С обработкой нажатий разобрался, использовал функцию, которую прошлым летом мне показал @ARV. За что ему огромное спасибо ещё раз!))

Скрытый текст

uint8_t get_button(void)
{
	static unsigned char but_code;
		
	but_code=PIN_BTN & BUTTONS;
	_delay_ms(5);
	if(but_code==(PIN_BTN & BUTTONS))
	{
		return but_code;
	}
	else
	{
		return ERROR;
	}
}

char Key_Repeater(char kk) //функция повторения нажатий
{
	static char old_kk; //предыдущее сочетание клавишь
	char result = 0; //результат возврата
	if(kk==NO_BUTTON_PRESS) //если ни одна кнопка не нажата
	{
		StopTimer(&Timer_KK);
	}
	else
	{
		if(old_kk!=kk) //если пришло новое нажатие
		{
			StartTimer(&Timer_KK, ACTIVE, 0.5*second, NULL); //запустим таймер с периодом 0,5 сек
			result = kk; //при первом входе сразу же вернули полученое сочетание клавишь
		}
		else //если данное сочетание пришло не впервые
		{
			if(TimeoutTimer(&Timer_KK)) //если время таймера вышло
			{
				result = kk; //повторим сочетание клавишь через 1 сек
				StartTimer(&Timer_KK, ACTIVE, 0.3*second, NULL); //запустим новый таймер с периодом 0,3 сек
			}
		}
	}
	old_kk = kk; //запомним предыдущее нажатие
	return result;
}

int main(void)
{
	while(1)
    {
    	key = Key_Repeater(get_button()); 
    }
}

 

Но теперь уперся в другое "узкое место" моей программы, а именно вывод символов на четырёхразрядный семисегментный индикатор. Для его управления я использую драйвер MAX7219.

Дак вот, основная проблема в том что в разных режимах, существуют разные правила отображения:

  • в режиме часов - нужно моргать точкой между часами и минутами;
  • в режиме температуры, отображать символ градуса и выводить минус при отрицательном значении;
  • в режиме вольтметра выводить символ U;
  • в режиме отображения пунктов меню, просто выводить определённые символы;
  • в режиме настройки моргать параметром.

MAX7219 подключен по SPI и символы я вывожу с помощью двух основных функций:

Скрытый текст

unsigned char segchar (unsigned char seg, unsigned char number) //функция перевода цифры в символ на дисплее
{
	unsigned char result;
	switch(number)
	{
		case 1: result = 0b00110000; break; //цифра 1
		case 2: result = 0b01101101; break; //цифра 2
		case 3: result = 0b01111001; break; //цифра 3
		case 4: result = 0b00110011; break; //цифра 4
		case 5: result = 0b01011011; break; //цифра 5
		case 6: result = 0b01011111; break; //цифра 6
		case 7: result = 0b01110000; break; //цифра 7
		case 8: result = 0b01111111; break; //цифра 8
		case 9: result = 0b01111011; break; //цифра 9
		case 0: result = 0b01111110; break; //цифра 0
		
		case 10: result = 0b00000001; break; // знак -
		case 11: result = 0b00000000; break; // пустое место
		case 12: result = 0b01100011; break; // символ для показаний температуры
		case 13: result = 0b00000000; break; //знак пустоты
	}
	
	switch(mode) //в зависимости от режима, меняем правила отображения
	{
		case MODETIMEVIEW:
		{
			if(animation_flag)
			{
				
				if((seg==2)&&(animation_flag==1)){result=0;} //если четвертый разряд и режим анимации, выведем пустоту
				if((seg==3)&&((animation_flag==1)||(animation_flag==2))){result=0;} //если четвертый разряд и режим анимации, выведем пустот
				if((seg==4)&&(number==0)){result=0;} //если в четвертом разряде приходит цифра 0, выведем пустоту на дисплей
			}
			else
			{
				if((seg==4)&&(number==0)){result=0;} //если в четвертом разряде приходит цифра 0, выведем пустоту на дисплей
				if (seg==3){if(PIN_SWQ&(1<<SQW)){result|=(1<<7);}} //если пришло время мигнуть точкой, подмешаем её в символ				
			}
			break;			
		}
		
		case MODETEMPVIEW:
		{
			if(seg==1){result = 0b01100011;} //допишем значек градуса после показаний температуры
		
			if(seg==3){if((number==0)&&(Cminus==0)){result=0;}} //если в третьем разряде приходит цифра  0, выведем пустоту на дисплей
			
			if(seg==4){if((number==0)&&(Cminus==0)){result=0;}} //если в четвертом разряде приходит цифра 0, выведем пустоту на дисплей			
	
			break;	
		}
			
		case MODEVOLTVIEW:
		{
			if (seg==1){result = 0b00111110;} //допишем букву U после значения напряжения
						
			if (seg==3){result|=(1<<7);} //точка разделитель десятой части вольта
			
			if ((seg==4)&&(number==0)){result=0;} //если в четвертом разряде приходит 0, то пишем пустое место			
			break;	
		}
			
	}
		return result;
}

void ledprint_7219 (unsigned int number) //функция, которая выводит в каждый разряд свой символ из числа
{
	Send_7219(1, segchar(1, number%10));
	Send_7219(2, segchar(2, number%100/10));
	Send_7219(3, segchar(3, number%1000/100));
	Send_7219(4, segchar(4, number/1000));
}

 

Однако мне кажется что функция segchar уже на данном этапе чрезмерно перегружена и уродлива)) (или нет?) может быть вы подкинете парочку идей как сделать этот участок кода более логичным красивым и коротким?

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Снова рискну предложить вариант, ставший для меня основным.

Следует разделить функцию обновления индикатора и функцию вывода на индикатор. Принцип тот же, как и в любом дисплее: дисплей сам показывает то, что на него вывели, знать не знает, зачем.

Итак, делаем "экранную область" - массив scr, содержащий коды символов, отображаемых на индикаторе. Делаем знакогенератор - массив zgen, содержащий битовые карты светящихся сегментов для каждого символа. Делаем функцию, которая берет символы из экранной области, по их кодам извлекает битовые карты сегментов из знакогенератора и отправляет это на дисплей:

void refresh_scr(void){
  for(uint8_t i=0; i<SCR_SZ; i++)
    spi_send(zgen[scr[i]]);
}

Функцию refresh_scr можно вызывать по таймеру, предположим, 10 раз в секунду, тогда можно считать, что любой символ, который мы поместили в экранную область тут же (с задержкой не более 0,1 сек) появляется на индикаторе.

Такой подход позволяет просто выводить в экранную область то, что надо: захотели вывести минус в третьем разряде индикатора - записали в массив экранной области в третью ячейку код символа минус - и всё: scr[2] = CHAR_MINUS;

Мигание - отдельная тема. Если мигать должно целое знакоместо, то, при количестве знакомест не более 8, можно использовать отдельный байт (назовем его blink), превратив его биты в маску мигающих разрядов. Функция вывода экранной области на индикатор для этого случая должна измениться:

void refresh_scr(void){
  static uint8_t entry;
  uint8_t mask = 1;
  for(uint8_t i=0; i<SCR_SZ; i++){
    spi_send(zgen[(blink & mask) && entry ? CHAR_SPACE : scr[i]]);
    mask <<= 1;
  }
  entry = !entry;
}

Она будет просматривать эти биты, и для помеченных разрядов выводить "через раз" либо заданный символ, либо пробел - вот вам и автоматическое мигание. То есть если вы захотите замигать вторым разрядом индикатора, вы просто делаете blink |= _BV(1); - и он будет мигать до тех пор, пока этот бит в blink установлен. 

Как вам идея?

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, ARV сказал:

Как вам идея?

Похоже идея отличная. Давайте я по порядку буду разбирать.

1 час назад, ARV сказал:

Итак, делаем "экранную область" - массив scr, содержащий коды символов, отображаемых на индикаторе. Делаем знакогенератор - массив zgen, содержащий битовые карты светящихся сегментов для каждого символа.

 

Скрытый текст

#define DG 4 //кол-во используемых разрядов

uint8_t scr[DG], //"экранная область"
		zgen[]=  //"знакогенератор"
		{
			0b00110000, //цифра 1
			0b01101101, //цифра 2
			0b01111001, //цифра 3
			0b00110011, //цифра 4
			0b01011011, //цифра 5
			0b01011111, //цифра 6
			0b01110000, //цифра 7
			0b01111111, //цифра 8
			0b01111011, //цифра 9
			0b01111110, //цифра 0
		
			0b00000001, // знак -
			0b01100011, // символ для показаний температуры
         	 	0b00111110, //символ напряжения U
			0b00000000 //знак пустоты			
		};

 

Я правильно написал то что Вы предложили?

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

  • Сообщения

    • Приветствую. Ревер запустил, побаловался - ну, такое себе. Не именно качество пружинного ревера, а сама по себе идея эха не понравилась. Зачем? Хорошая гитара с хорошими активными звучками и так звучит отлично. Причем, довольно объемно и без эха. Наваял вот такой девайс для управления ревером по схеме отсюда: https://sound-au.com/project34.htm Схема такая: Данная схема приглянулась тем, что можно отдельно регулировать уровень "чистого" сигнала и добавлять к нему сигнал ревера. Все заработало с первого раза. Если кому-то интересно - выложу мой вариант схемы и печатку сюда. На моей схеме и плате (при помощи джамперов) предусмотрел возможность использования схемы с разными реверами согласно таблице: Данная схема не понравилась тем, что ревер в ней всегда работает "на всю мощь" - регулируется только его громкость. Мне кажется, если схему добавить возможность ограничения усиления перед ревером, то это даст возможность регулировать итенсивность эха. Или нет? Стоит по этому поводу заморочиться и дать схеме еще один шанс? Интерес к данному проекту я потерял, планирую попробовать цифровой ревер. Если кому-то интересно продолжить проект или просто поэкспериментировать - могу поделиться новым ревером и спаянной платой. Советы и замечания по прежнему принимаются - может я не туда копаю? Кстати, сам ревер установлен внутри комбика и совершенно не зависит от его громкости и вибрации корпуса. Как говорили выше. Опробовано на практике. Звук, да - как из консервной банки. Но я еще пока не занимался настройкой схемы и самим ревером.
    • Тут ещё какая штука- сечение от диаметра имеет квадратичную зависимость. Увеличение диаметра в 2 раза даёт увеличение сечения в 4. Поэтому ошибка получается очень большая.  ПЕРЕСЧЁТ ДИАМЕТРА ПРОВОДА НА ПОПЕРЕЧНОЕ СЕЧЕНИЕ.xls
    • Хорошо, если вам хочется называть проценты попугайчиками, то пожалуйста. Но, хотелось бы спросить. Вы всё-таки понимаете разницу между измерением напряжения 1 В с точностью +-0,1% и измерением отношения напряжений Х В и 0,5Х В с такой же точностью? 
    • Про R20 Я тоже думал поставить постоянный на 800 ом и 200 ом переменником крутить
    • Скажите в данный вольт-амперметр реально прикрутить дисплей на чипе ST7735/ST7789. так как экран на чипе SSD1309 стоит как колесо от боинга.
×
×
  • Создать...