реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Редактирование строки на ЖКИ., Ввод времени в RTC
alux
сообщение Dec 14 2007, 16:53
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Простая, казалось бы на первый взгляд задача... Но вот уже вторые сутки ломаю голову. Не могу придумать как это лучше сделать. Хочу, как в мобильном телефоне настраивать время. Вот мой кусок кода:
Код
void EditTime_Func(void)
{
  unsigned char temp;
  rtc_get_time(0x99);      //значение времени в yr, mn, dt, dy, hr, min, sec
  ClearScreen();    // display clear      
  GotoXY(0,0);    
  sprintf_P(lcd_buf,"%d/%d/%d %d  %02d:%02d:%02d", yr, mn, dt, dy, hr, min, sec);
  PutStr(lcd_buf);
  w=CharWidth(*plcd_buf)-2;
  start_Timer(TIMER_0, 500, blink, TIMER_CYCLE);

  for(;;)
  {
    temp=key_get();
    switch(temp)          //key_code.scan
    {
        case LEFT:        //k_esc
            {......}
             break;
        case RIGHT:       //k_enter
             {......}
             break;
        case DOWN:        //k_left
             {......}
             break;
        case UP:          //k_right
              {......}
             break;  
        default:          // 0...9
             {......}
             break;            
    }
    
    if(key_code.scan == LEFT)  //выход из функции
    {
       stop_Timer(TIMER_0);
       break;
    }
  }
}

//------------------------------------------------------------------------------
void blink(void)
{
  InvertRect(x, y, w, 9);
}

Идея такая. Вывожу на экран значение времени в виде строки:
"2007/12/24 1 12:32:00"
Ф-ция start_Timer() запускает каждые 0,5 сек ф-цию blink(), которая в свою очередь инвертирует заданный прямоугольник. Т.е. должно мигать текущее знакоместо. Кнопками UP, DOWN выбираю следующее, предыдущее знакоместо. Ввод числа осуществляется с клавиатуры 4х4. Это все у меня работает. Проблема еще в том, что символы имеют переменную ширину. Поэтому после каждого ввода символа необходимо ,наверное, перерисовывать всю строку. После нажатия ENTER новые значения переменных необходимо записать в RTC. Как сделать ввод чисел только в заданные места, т.е. пропускать '/' , ' ' , ':' ? Меня не покидает чувство, что изобретаю велосипед.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 14 2007, 17:27
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Я реализовывал такую задачу. Правда на ассемблере и на х51 процессоре.
Я поступал следующим образом (правда у меня было много меню с различными зонами, возможно несколькими, на экране)

И я строил меню, как структуру, где указывал тип зоны ввода, левый край и размер, а также максимальное и минимальное возможное значение. В самом меню использую псевдо-символы управления курсором по принципу терминала. Это даёт возможность грамотного управления и редактирования. Приведу кусок хидера своей библиотеки.
Код
// Управляющие символы дисплея LCD

#define    CR_BS            8                                // BackSpace        /b
#define    CR_TAB            9                                // TAB                /t
#define    CR_LF            0xa                                // LF                /a
#define    CR_NEW            0xc                                // CLR                /f
#define    CR_ENTER        0xd                                // ENTER            /r
#define    CR_LEFT            0x11                            // LEFT                /x11
#define    CR_RIGHT        0x12                            // RIGHT            /x12
#define    CR_UP            0x13                            // UP                /x13
#define    CR_DOWN            0x14                            // DOWN                /x14
#define    CR_HOME            0x15                            // HOME                /x15
#define    CR_BEEP            0x17                            // BEEP                /x17
#define    CR_CURHIDE        0x18                            // HIDE                /x18
#define    CR_CURSHOW        0x19                            // SHOW                /x19
#define    CR_CURDIRECT    0x1b                            // Direct Cursor    /x1b

// Прототипы    функций

void LCDInit(void);                                        // Инициализация LCD дисплея. Вызывается из    модуля инициализации.
void GotoXY(uint8_t    x,uint8_t y);                        // Установит курсор в позицию X,Y.
int8_t cr_left(void);                                    // Курсор влево.
int8_t cr_right(void);                                    // Курсор вправо.
uint8_t    cr_up(void);                                    // Курсор вверх
uint8_t    cr_down(void);                                    // Курсор вниз.
void cr_home(void);                                        //    в начало строки
int16_t    putchar(int16_t    c_in);                            // Вывести символ    в кодировке    Win. с управляющими    символами
void spliter_init(void);                                // Инициализировать сплитер.
void spliter(uint8_t pos, uint8_t maxpos);                // Отобразить сплитер
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 14 2007, 18:16
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Разделите логически в программе ввод, вывод и редактирование, а потом совместите их. Т.е. с помощью клавиатуры вы будете редактировать какую-то переменную время/дата. И эту же переменную выводить на экран после каждой модификации полностью. Не нужно будет ломать голову как совместить видимую позицию курсора и редактируемый символ.
Go to the top of the page
 
+Quote Post
Baser
сообщение Dec 14 2007, 20:32
Сообщение #4


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(rezident @ Dec 14 2007, 20:16) *
Разделите логически в программе ввод, вывод и редактирование, а потом совместите их. Т.е. с помощью клавиатуры вы будете редактировать какую-то переменную время/дата. И эту же переменную выводить на экран после каждой модификации полностью. Не нужно будет ломать голову как совместить видимую позицию курсора и редактируемый символ.

rezident дело говорит. "В одну корзину класть не можно на яйца сверху серп и молот" smile.gif

Всегда делаю различные процедуры для индикации и обработки клавиатуры. Логически эти процедуры связаны только через переменную MenuNumber, которая указывает на номер текущего меню (на тип информации, выводимой на дисплей). Обработчик клавиатуры верхнего уровня ServiceKeys в зависимости от значения MenuNumber и нажатых кнопок производит нужные действия, напр.:
-выбор параметра для редактирования - перемещает мигающее поле на дисплее;
-вход в режим изменения параметра - копирует выделенную переменную в буфер редактора;
-изменение параметра - меняет переменную в буфере редактора;
-выход из режима изменения параметра - сохраняет переменную;

Процедура вывода на дисплей RedrawLCD вызывается раз в 1 сек и после обработки клавиатуры.
Эта процедура по значению MenuNumber выводит на дисплей нужные параметры, беря их или напрямую, или из буфера редактора. Эта процедура и занимается преобразованием бинарных переменных в ASCII коды.
Go to the top of the page
 
+Quote Post
alux
сообщение Dec 15 2007, 09:57
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(Baser @ Dec 15 2007, 00:32) *
Всегда делаю различные процедуры для индикации и обработки клавиатуры. Логически эти процедуры связаны только через переменную MenuNumber, ...

Можете привести для наглядности свой код?
Go to the top of the page
 
+Quote Post
Baser
сообщение Dec 15 2007, 16:15
Сообщение #6


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(alux @ Dec 15 2007, 11:57) *
Можете привести для наглядности свой код?

Какой то конкретный код привести вряд ли смогу, это все ненаглядно и громоздко.

Еще некоторые соображения по поводу вашего примера кода. Если вы не применяете RTOS и не запускаете эту процедуру как отдельную задачу, то у вас во время редактирования часов прибор ничего больше не делает (только прерывания). Я применяю несколько другой метод организации обработки клавиатуры и дисплея, который без RTOS обеспечивает выполнение алгоритмов кусками, отдельными состояниями конечного автомата (по сути это работа по флагам).

Общая структура следующая:
- Один таймер выделяется под системный, который обеспечивает регулярное прерывание, в котором выставляется флаг f10ms_Past.
- Этот флаг обрабатывается в основном цикле main, где формируются места, которые выполняются через равные промежутки: 10 мс, 1 сек, другие необходимые.
Код
//--------------------------------------------------------------//
//       10 milliseconds, One and Ten seconds Procedures        //
//--------------------------------------------------------------//
  if (f10ms_Past)                 // 10 ms past
    {
    f10ms_Past = 0;
    ReadKeys();
    RunADC();
    Task1_Service();
    Task2_Service();
    ...................
    if (++TenMilliSecCnt >= 100)  // 1 second past
        {
        TenMilliSecCnt = 0;
        poGreenLED ^= 1;        // Toggle green LED
        RedrawLCD();            // Redraw LCD module
        ....................
        if (++SecCnt >= 10)     // 10 seconds past
            {
            SecCnt = 0;
            .................
            }
        }
    }
//--------------------------------------------------------------//
//          Keys service Conditions Determination               //
//--------------------------------------------------------------//
    if (fShortKey || fLongKey)
        {
        ServiceKey();
        RedrawLCD();
        }
   .....................

- Каждые 10 мс выполняется процедура ReadKeys(); которая является драйвером клавиатуры нижнего уровня и занимается сканированием кнопок, обработкой дребезга, распознает длительность нажатия, автоповтор и т.д. Результат ее работы - значения регистров статуса и флаги нажатия.
- Обработчик клавиатуры верхнего уровня ServiceKeys(); вызывается по наличию флагов. Его работу я уже описал.
- Про функцию вывода на дисплей я уже тоже писал.

Важное замечание: вся эта структура будет хорошо работать только в том случае, если обеспечивается, что время работы любой функции не превышает 10 мс и хотя бы раз за 10 мс выполняется главный цикл. Но я обычно пишу так, что это условие всегда выполняется.
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 15 2007, 20:28
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Baser @ Dec 15 2007, 21:15) *
- Один таймер выделяется под системный, который обеспечивает регулярное прерывание, в котором выставляется флаг f10ms_Past.

А я делаю более логично. В "тиковом" прерывании инкрементирую переменную на величину периода "тика". Получается, что ее значение является временной меткой, выраженной в миллисекундах. 16-и битной переменной хватает для отсчета интервала времени больше минуты, а 32-х битная переменная переполняется только через почти полтора месяца.
Цитата(Baser @ Dec 15 2007, 21:15) *
Важное замечание: вся эта структура будет хорошо работать только в том случае, если обеспечивается, что время работы любой функции не превышает 10 мс и хотя бы раз за 10 мс выполняется главный цикл. Но я обычно пишу так, что это условие всегда выполняется.

Если имеется упомянутая мной выше переменная "миллисекундных тиков", то нет необходимости так строго выдерживать период "суперцикла". Ограничивать период выполнения суперцикла приходится лишь в том, случае в его теле вычисляется, например, управляющее воздействие, которое должно быть обязательно выдано за определенный промежуток времени.
Если же вернуться к теме топика, то при наличии ресурсов в ОЗУ формируется буфер экрана и все изменения, определяемые функциями меню, делаются в нем. Затем весь буфер одной функцией выводится на экран. При необходимости для ускорения вывода можно пропускать элементы изображения, которые не изменились за текущий цикл, а выводить на экран только изменения.
Клавиатура у меня обычно тоже имеет свой буфер в который помещаются заранее определенные коды клавиш. Обрабатываются кнопки, устраняется дребезг, формируются коды клавиш и заполняется буфер в том же самом "тиковом"прерывании.
Go to the top of the page
 
+Quote Post
Baser
сообщение Dec 15 2007, 21:49
Сообщение #8


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(rezident @ Dec 15 2007, 22:28) *
А я делаю более логично. В "тиковом" прерывании инкрементирую переменную на величину периода "тика". Получается, что ее значение является временной меткой, выраженной в миллисекундах. 16-и битной переменной хватает для отсчета интервала времени больше минуты, а 32-х битная переменная переполняется только через почти полтора месяца.

При таком решении мне немного не понятно, как можно без дополнительных флагов обеспечивать выполнение периодических процедур главного цикла ОДИН раз за их номинальный период. МК в моменты простоя может все время крутиться в main и пролетать через них сотни раз за время одного "тика" прерывания.
Цитата(rezident @ Dec 15 2007, 22:28) *
Если имеется упомянутая мной выше переменная "миллисекундных тиков", то нет необходимости так строго выдерживать период "суперцикла". Ограничивать период выполнения суперцикла приходится лишь в том, случае в его теле вычисляется, например, управляющее воздействие, которое должно быть обязательно выдано за определенный промежуток времени.

Ну, как показывает практика, даже пропадание 1-2-х 10 мс процедур никак не сказывается на нормальной обработке клавиатуры и дисплея. Дребезг то на уровне 50-70 мс, сами понимаете.
Цитата(rezident @ Dec 15 2007, 22:28) *
Клавиатура у меня обычно тоже имеет свой буфер в который помещаются заранее определенные коды клавиш. Обрабатываются кнопки, устраняется дребезг, формируются коды клавиш и заполняется буфер в том же самом "тиковом" прерывании.

В первых своих работах я тоже делал обработку клавиатуры в прерывании, а потом перестал, потому что нету смысла: обработка неспешная и нечего ей занимать драгоценное время прерываний.
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 15 2007, 22:21
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Baser @ Dec 16 2007, 02:49) *
При таком решении мне немного не понятно, как можно без дополнительных флагов обеспечивать выполнение периодических процедур главного цикла ОДИН раз за их номинальный период. МК в моменты простоя может все время крутиться в main и пролетать через них сотни раз за время одного "тика" прерывания.
Дык у каждого процесса своя переменная заданного периода. Простым вычитанием двух беззнаковых переменных определяется закончился требуемый процессу интервал времени или еще нет.
Код
switch (mnuFlag)
{ case MNU_LEVEL1:
    mnu_time=tickTime;  //фиксируем отметку времени
    mnuFlag=MNU_LEVEL2;
    break;
  case MNU_LEVEL2:
    if ((tickTime-mnu_time)<5000) break; //ждем окончания интервала времени 5сек
    else
    {
      ...
      mnuFlag=MNU_LEVEL3;
    }
    break;
  case MNU_LEVEL3:
    ...
    ....
}

Цитата(Baser @ Dec 16 2007, 02:49) *
Ну, как показывает практика, даже пропадание 1-2-х 10 мс процедур никак не сказывается на нормальной обработке клавиатуры и дисплея.
Ну да, со скоростью 100 раз в секунду ни одна супер-пупер-машинистка долбить по клаве не сможет. biggrin.gif
Цитата(Baser @ Dec 16 2007, 02:49) *
Дребезг то на уровне 50-70 мс, сами понимаете.
Это довольно плохие контакты. Я не припомню, чтобы мы применяли кнопки у которых дребезг превышал 10мс. Обычно не более единиц мс.
Цитата(Baser @ Dec 16 2007, 02:49) *
В первых своих работах я тоже делал обработку клавиатуры в прерывании, а потом перестал, потому что нету смысла: обработка неспешная и нечего ей занимать драгоценное время прерываний.
Хозяин-барин. Все от задачи зависит. Некоторые задачи вообще полностью в "тиковом" прерывании выполняются (исключая конечно же начальную инициализацию).
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 16 2007, 10:01
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alux @ Dec 14 2007, 18:53) *
Проблема еще в том, что символы имеют переменную ширину....
Как сделать ввод чисел только в заданные места, т.е. пропускать '/' , ' ' , ':' ?
наверное, завести массив структур на каждое редактируемое число, по структуре на редактируемое знакоместо. В структуре хранить смещение и размер редактируемого знакоместа (а возможно и допустимые значения). Размер, равный нулю, говорит о том, что знакоместа кончились.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 16 2007, 10:50
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Тоже делаю временные метки.
Сейчас сделаю отдельную тему и там выложу исходники по вводу с матричной клавиатурой и выводу на дисплей с примерами.
PS: Выложил в библиотеки. Если есть какие вопросы, то можно здесь
Go to the top of the page
 
+Quote Post
alux
сообщение Dec 16 2007, 11:47
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(Сергей Борщ @ Dec 16 2007, 14:01) *
наверное, завести массив структур на каждое редактируемое число, по структуре на редактируемое знакоместо. В структуре хранить смещение и размер редактируемого знакоместа (а возможно и допустимые значения). Размер, равный нулю, говорит о том, что знакоместа кончились.

Сложно все это как-то. Ширина символов у меня хранится в структуре шрифта. Эту ширину можно получить ф-цией CharWidth();Значение этой ф-ции прибавляю или отнимаю к текущей координате X, в которую необходимо переместить мигающий курсор и вводимый символ. Я думаю , может использовать ф-ции strtok или strtol. Только не знаю еще как. В общем, мне нужен пример ф-ции strEdit(); которая редактирует посимвольно строку в зависимости от нажатой кнопки. Неужели никто этого не делал? Только без всяких RTOS.
Цитата(SasaVitebsk @ Dec 16 2007, 14:50) *
PS: Выложил в библиотеки. Если есть какие вопросы, то можно здесь

В каких библиотеках?
P.S. Я немного упростил задачу. Время вывожу в формате:
год : 2007
месяц : 12
дата : 14
день : 1
час : 13
минут : 30
Так даже наглядней будет. Строки переменных времени начинаются с коорд. X=50. Меняется коорд. Y для каждой переменной.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 16 2007, 11:55
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Сергей Борщ @ Dec 16 2007, 12:01) *
завести массив структур...

Усложняешь, Сергей sad.gif Когда нужно было сделать подобный ввод, то не мудурствуя лукаво
- была взята строка-шаблон;
- выведена на дисплей;
- курсор был воткнут на одно из редактируемых полей;
- символ под курсором анализировался на digit/ASCII/separator, то не позволяло вводить символы не характерные для данного шаблона и позволяло перемещаться курсором сквозь символы не являющиеся символами характерными для данного поля;
- при необходимости дополнительно можно было наложить дополнительные ограничения на перемещения курсора в пределах строки.
- полученная таким редактированием строка-шаблон прогонялась обратно через sscanf() и .. и все.

Все это оформлено ввиде достаточно универсальной функции редактирования строки работающей с указателем на редактируемую строку-шаблон, правой-левой границей в строке (это _не_ выделитель поля ввода), позицией курсора ( при первом запуске определеляет типа поля подлежащего редактированию) и, естественно, введенным символом.

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 16 2007, 12:16
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Дык алгоритм-то редактирования простейший.
1 уровень - "бегаем" по строке вправо-влево в заданных размером строки пределах. Если нажата кнопка, отличающаяся от "вправо"/"влево", то "проваливаемся" на второй уровень.
2 уровень - в зависимости от текущего положения курсора, редактируем какую-то конкретную переменную - year, month, day, hour, min, sec. Причем изменение ее (инкремент или декремент) идет на величину кратную положению курсора. Т.е. если редактируем вторую цифру минут, то декремент/инкремент переменной min при нажатии на кнопки "вверх"/"вниз" (или какие там у вас выделены для редактирования?) идет не на 1, а на 10. Естественно тут нужна проверка на выход за разрешенный для данной переменной диапазон значений. Например, 70 минут не бывает. Поэтому min может меняться только в пределах 0-59.
При нажатии на любую другую кнопку, кроме выделенных для редактирования, возвращаемся на первый уровень.
Go to the top of the page
 
+Quote Post
alux
сообщение Dec 16 2007, 12:47
Сообщение #15


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Цитата(rezident @ Dec 14 2007, 22:16) *
Разделите логически в программе ввод, вывод и редактирование, а потом совместите их. Т.е. с помощью клавиатуры вы будете редактировать какую-то переменную время/дата. И эту же переменную выводить на экран после каждой модификации полностью. Не нужно будет ломать голову как совместить видимую позицию курсора и редактируемый символ.

Переменную, наверное, необходимо сделать bin2bcd, чтобы редактировать каждую цифру числа. Пока не представляю как это все реализовать.
Цитата(rezident @ Dec 16 2007, 16:16) *
Дык алгоритм-то редактирования простейший.

Не вижу ничего простейшего! Наоборот. Вы что, в мобильном телефоне тоже так время настраиваете? Т.е. подводите курсор на нужный символ, затем нажимаете на кнопку, отличающаяся от "вправо"/"влево". Затем кнопками "вправо"/"влево" редактируете значение времени??? Если это так, то я вам сочувствую...
Если вы обратили внимание на мой код в первом посте, то у меня кнопки обрабатывается в одном уровне оператором switch. Т.е. если не нажата кнопка "вверх"/"вниз", то по умолчанию обрабатывается нажатие цифровых кнопок (если скан-код нажатой клавиши отличается от 0xff-нет нажатия).
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 17:13
Рейтинг@Mail.ru


Страница сгенерированна за 0.01537 секунд с 7
ELECTRONIX ©2004-2016