Программная реализация двухпозиционного графического переключателя для сенсорного интерфейса

Сенсорний дисплей

Пример программной разработки графического элемента для сенсорного дисплея

Основные элементы и структуры для создания графического элемента

На базе тестовой отладочные платы, которая рассматривалась в предыдущей статье «Разработка графического сенсорного интерфейса», в текущей работе будет демонстрироваться программная реализация графического элемента на примере создания двухпозиционного переключателя. Вся программная часть реализована на языке Си, среда программирования – IAR.

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

-> Украинская версия <-

Для начала нам нужно сделать основные объявления структурных шаблонов, на которых будет базироваться вся программная реализация. Лучше всего такие объявления делать в отдельном (header) файле.

Первая конструкция, которая нам нужна – это перечисленный тип данных для хранения идентификаторов отдельного графического элемента. Представляет собою инкрементный список констант с нужным названием. Здесь индексы, начиная с 1-цы и дальше указывать не обязательно, так как данный тип автоматически может осуществлять задания значения с инкрементом.

 

 

 

Следующая конструкция – это структура-шаблон, содержащая две переменных для хранения координат положения графического элемента на дисплее.

 

 

 

Далее – структура-шаблон, содержащая данные о создаваемый графический элемент.

 

 

 

Рассмотрим переменные, входящие в последнюю структуру.

Переменная ControlPTR – указатель неопределенного типа на другую структуру-шаблон графического компонента что создается. Последняя, для текущего примера, будет рассматриваться ниже.

Переменная ControlType – это переменная, содержащая идентификатор графического элемента, который создается. Идентификатор объявляется в предварительно рассматриваемом перечислении данных типа ControlType_TypeDef.

Переменная ControlCoord – это указатель на предварительно рассмотренную структуру-шаблон ControlCoord_TypeDef.

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

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

 

 

 

В последнюю структуру входят следующие переменные.

PageName[CONTROL_MAX_NAME_LEN] – указатель на текстовую строку, что описывает имя. Данная текстовая переменная по количеству символов не должна превышать максимальную длину, задаваемой константой CONTROL_MAX_NAME_LEN.

PageActive – переменная, что указывает состояние создаваемой страницы – активная или нет. Используется при отображении последней. В качестве значений, которые принимает последняя переменная, используются битовые значения ‘0’ и ‘1’.

PageVisible – переменная, что указывает текущее состояние страницы (отображается / не отображается). В качестве значений, которые принимает последняя переменная, используются битовые значения ‘0 ‘и ‘1’.

ControlCount – переменная, что указывает количество графических элементов на текущей странице.

PageColor – переменная, что указывает код цвета фона текущей страницы.

PageTochActive – переменная, что указывает ли активная страница для обработки событий прикосновения к сенсорному экрану. В качества значений, которые принимает последняя переменная, используются битовые значения ‘0 ‘и ‘1’.

*PageControls[CONTROL_MAX_COUNT] – массив указателей на структуру типа PageControl_TypeDef, которая рассматривалась выше.

(*ShowPage)(Page_TypeDef*, uint8_t) – указатель на функцию отображения данной страницы. В качестве параметров последняя функция передает указатель на только что рассматриваемую структуру типа Page_TypeDef и значения, что включает или выключает события прикосновения к сенсорному экрану. В качестве значений, которые принимает последняя переменная, используются битовые значения ‘0 ‘и ‘1’.

Последняя структура, которую будем использовать в текущем примере – это структура собственно нужного нам графического двухпозиционного переключателя ControlTwoStateSwich_Struc.

 

 

 

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

ID – это переменная-идентификатор создаваемого графического элемента.

IsTwoStateSwich_Touched – переменная, что указывает, был ли текущий графический элемент активирован событием прикосновения. В качества значений, которые принимает последняя переменная используются битовые значения ‘0 ‘и ‘1’.

TwoStateSwich_Enable – переменная, что указывает будет ли текущий графический элемент активен до событий прикосновения. В качестве значений, которые принимает последняя переменная, используются битовые значения ‘0 ‘и ‘1’.

TwoStateSwich_Visible – переменная, что указывает, будет ли текущий графический элемент отображаться по умолчанию на заданной странице. В качестве значений, которые принимает последняя переменная, используются битовые значения ‘0 ‘и ‘1’.

TwoStateSwich_CheckState – переменная, что указывает в каком состоянии находится текущий графический элемент (включен / выключен).

TwoStateSwich_Width – переменная, задающая размер по ширине текущего графического элемента.

TwoStateSwich_Heght – переменная, задающая размер по высоте текущего графического элемента.

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

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

(*EventHandler)(uint8_t) – указатель на функцию обработки события прикосновения к текущему графическому элементу. В качестве параметров, передает последняя функция – это текущее состояние графического элемента (включен / выключен).

 

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

 

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

 

 

В качестве параметров, передаваемых для последней функции, используются большинство переменных и указателей описанных для структуры ControlTwoStateSwich_Struc:

  • переменная-идентификатор создаваемого графического элемента ID;
  • переменная, что указывает в каком состоянии находится текущий графический элемент (включен / выключен) PressState;
  • переменная, задающая размер по ширине текущего графического элемента Width;
  • переменная, задающая размер по высоте текущего графического элемента Height;
  • указатель, указывающий на массив, который сохраняет данные изображения текущего графического элемента, в состоянии включен *ImageOn;
  • указатель, указывающий на массив, который сохраняет данные изображения текущего графического элемента, в состоянии выключен *ImageOff;
  • указатель на функцию обработки события прикосновения к текущему графическому элементу (*pEventHandler)(uint8_t);
  • переменная, что указывает, ли текущий графический элемент активен до событий прикосновения Enable;
  • переменная, что указывает или текущий графический элемент будет отображаться по умолчанию на заданной странице Visible.

В качестве параметра, что возвращает текущая функция, используется указатель на новую созданную структуру типа PageControl_TypeDef.

Коротко рассмотрим действия, которые выполняются здесь. Для начала объявляем переменные-указатели *pPageControl типа PageControl_TypeDef и *pControl типа ControlTwoStateSwich_TypeDef.

 

 

 

Далее для переменной-указателя pControl выделяем оперативную память размером, который нужен для структуры типа ControlTwoStateSwich_TypeDef.

 

 

 

Если выполняется проверка условия if (pControl){}, это означает, что память выделена без ошибок. Далее можно инициализировать переменные, входящие в только что созданную структуру. Для операции инициализации используется следующее обращение к структуре через указатель.

 

 

 

Далее аналогично предыдущим операциям для переменной-указателя pPageControl выделяем оперативную память размером, который нужен для структуры типа PageControl_TypeDef.

 

 

 

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

 

 

 

В данном случае, задаем следующие параметры, – это указатель на структуру выше созданного графического элемента (void*)pControl, константу-тип CONTROL_TYPE_TWO_STATE_SWITCH из перечня типа ControlType_TypeDef и указатель на функцию, который используется для визуализации текущего графического элемента TwoStateSwichVisible_Func.

Далее рассмотрим функцию для создания отдельной графической страницы CreatePage_Func.

 

 

 

В качестве параметров, передаваемых для последней функции, используются следующие, – это указатель на предварительно объявленную структуру типа Page_TypeDef и код цвета фона текущей страницы. Параметр, что возвращает функция – это идентификатор удачного выполнения операций (‘0 ‘или ‘1’).

Рассмотрим описание самой функции. Для начала программа проверяет созданный в памяти указатель типа Page_TypeDef условием if (!pPage){}. Если проверка выполнена успешно, дальше проверяется не превышено ли заданное максимальное количество создаваемых страниц условием if (PageCounter++< PAGES_MAX_COUNT){}. После чего проводим инициализацию структуры типа Page_TypeDef. В качестве указателя на функцию, которая будет отражать текущую страницу, задаем ShowPage_Func, она будет общей для всех страниц. Ее писание рассмотрим позже. Для массива указателей PageControls типа PageControl_TypeDef выделяем оперативную память размером равным размеру структуры типа PageControl_TypeDef в заданном максимальном количестве графических элементов на страницу.

 

 

 

Рассмотрим, что здесь происходит. В качестве параметров, что получает данная функция, используются указатель *pControl на структуру типа PageControl_TypeDef и указатель pCoords на структуру типа ControlCoord_TypeDef.

Далее создаем переменную-указатель типа ControlTwoStateSwich_TypeDef и записываем сюда значение указателя на структуру графического элемента с соответствующей полученной структуры типа PageControl_TypeDef.

 

 

Следующее условие проверяет, есть ли текущий графический элемент видимым или невидимым.

 

 

 

Если элемент является невидимым и в программе объявлена ​​директива FILL_UNVISIBLE_CONTROL_ATTAY, область размещения текущего элемента изображается в цвет фона страницы с помощью функции DrawFullRect_Func. Для этого последней в качестве параметров передаются координаты размещения графического элемента, его размеры и код цвета фона данной страницы.

Функции, касающиеся системной работы с самим дисплеем, например выше рассмотрена DrawFullRect_Func, описываться в текущей статье не будут. Их реализация в определенной степени также зависит от конкретной модели дисплея, который используется.

В противном случае, если элемент является видимым, проверяется следующее условие.

 

 

 

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

Если графический элемент активный далее программа делает следующую проверку

 

 

Тут TWO_STATE_SWITCH_OFF – это директива-константа, объявленная выше в программе или в файле дополнительных типов и констант. В данном случае эта констант принимает значение логический ‘0’.

Если описанное выше условие выполняется, дальше программа выполняет функцию DrawControl_Func.

 

DrawControl_Func((uint8_t)pCoords.StartX, (uint16_t)pCoords.StartY, (uint8_t)pTemp->TwoStateSwich_Width,(uint16_t)pTemp->TwoStateSwich_Heght, (uint16_t*)pTemp->TwoStateSwich_ImageOff);

 

Последняя выполняет визуализацию графического элемента в заданных координатах (uint8_t)pCoords.StartX, (uint16_t)pCoords.StartY и размером (uint8_t)pTemp->TwoStateSwich_Width,(uint16_t)pTemp->TwoStateSwich_Heght. Изображение элемента задается указателем на массив данных (uint16_t*)pTemp->TwoStateSwich_ImageOff), в данном случае это изображение элемента в состоянии выключен. функция DrawControl_Func является системной функцией вывода изображения и в текущей статье рассматриваться не будет.

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

 

 

 

Следующая функция – это функция отображения заданной страницы и всех графических элементов, что для нее заданы ShowPage_Func.

 

 

 

Если последнее условие выполняется, то это значит, что структура, на которую указывает указатель pPage типа Page_TypeDef, была создана удачно и текущая страница до этого не отображалась.

Следующее условие проверяет, была ли предыдущая страница активна. Текущая активная страница задается переменной-указателю ActivePage типа Page_TypeDef.

 

 

 

Если описанное выше условие выполняется, далее для предыдущей активной страницы переменную PageVisible устанавливаем в значение FALSE или ‘0’.

Далее для структуры страницы, которую отображаем, задаем значение, отвечающие за отображение текущей активной страницы PageVisible и активную или неактивную функцию обработки событий прикосновения к графическим элементам PageTochActive. А также перезаписываем указатель страницы, что отображаем, в переменную-указатель текущей страницы ActivePage.

 

 

 

Следующая системная функция ClearScreen_Func делает заливку экрана в цвет, который был задан в качестве фонового для данной страницы PageColor.

 

 

 

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

В нашем случае будет вызвана выше рассматриваемая функция TwoStateSwichVisible_Func.

 

 

 

Очередная функция – функция добавления созданного графического элемента к выбранной странице AddPageControl_Func.

 

 

 

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

В начале тела функции объявляем указатель неопределенного типа pTemp. Далее делаем проверку указателя pControl.

 

 

 

Следующее условие проверяет, не превышена ли максимальное количество графических элементов для заданной страницы.

 

 

 

Если последнее условие выполняется, дальше объявляем динамическую структуру ControlCoord типа ControlCoord_TypeDef и выделяем для нее нужный размер оперативной памяти.

 

 

 

Далее оператором switch делаем проверку на тип элемента, на структуру которого указывает указатель pControl.

 

 

 

В нашем случае выше рассмотрен выбор остановится на нашем двухпозиционным переключателем.

 

 

 

Ниже делаем инициализацию указателя pTemp,
приведя его к типу ControlTwoStateSwich_TypeDef, и записываем в него адрес, что указывает на структуру текущего графического элемента ControlPTR.

 

 

 

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

 

 

 

При удачной последней проверке инициализируем поля, входящие в выше созданную структуру ControlCoord, записав туда координаты графического элемента, которые были получены в входных параметрах.

 

 

 

Последние действия текущей функции – это инициализация поля ControlCoord структуры на которую указывает указатель pControl типа PageControl_TypeDef, и инициализация полей PageControls и ControlCount структуры на которую указывает указатель pPage типа Page_TypeDef, записывая туда указатель на структуру pControl и инкрементоване значение поля ControlCount соответственно.

 

 

 

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

 

 

 

Рассмотрим описание выше указанной функции. Последняя функция не принимает и не возвращает никаких дополнительных параметров. В начале тела функции объявляются переменные, используемые функцией, назначение которых будет рассматриваться дальше.

Первое действие – это временная циклическая задержка, которая была введена для задания периодичности между каждой последующей проверкой событий. Переменная DelayIndex – счетчик задержки, который задерживает выполнение функции на количество итераций, задается константой CONTROL_TOUCH_DELAY.

 

 

 

Функция ConvertPos_Func является системной функцией считывания данных с драйвера сенсорной панели и рассмотрению в текущей статье не подлежит. Последняя функция выполняет задачи считывания координат с драйвера в определенной последовательности с последующим фильтрованием полученных чисел и проверку на ошибки.

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

 

 

 

При каждой следующей итерации цикла программа с помощью оператора switch делает проверку на тип графического элемента, которому соответствует индекс Index итерации.

 

 

 

В нашем случае программа выполнит следующее условие при проверке на тип графического элемента USE_TWO_STATE_SWITCH.

 

 

 

Следующие действия программы – это инициализация переменной-указателя pTemp на структуру текущего графического элемента, что соответствует индексу итерации Index, и размеров элемента для чего используются выше объявленные переменные ControlWidth и ControlHeight.

 

 

Далее программа проверяет является ли текущий элемент активен и видим, для чего используются поля структуры элемента TwoStateSwich_Enable и TwoStateSwich_Visible.

 

 

Следующая проверка выполняет вызов функции CheckCoordBeyong_Func, для которой передаются следующие параметры, – это координаты текущего графического элемента, что соответствует индексу итерации Index, и размеры этого элемента.

 

 

 

Последняя функция осуществляет проверку на принадлежность полученных координат прикосновения, к активным границ графического элемента, рассматриваться в текущей статье не будет. В случае принадлежности точки соприкосновения в пределы данного элемента программа в цикле while начнет непрерывно выполнять функцию IsTochPress_Func.

 

 

 

системная функция IsTochPress_Func выполняет проверку на присутствие активного сигнала прикосновения к сенсорной панели с драйвера последней.

В вышеописанном цикле осуществляются те же действия, что были описаны в начале рассмотрения функции ProcessInputData_Func – это считывания координат прикосновения и проверка на принадлежность полученных координат к текущему графическому элементу, что соответствует индексу итерации Index. Эти действия выполняются для того чтобы отслеживать событие отжима от сенсорной панели или выхода точки соприкосновения с активных границ графического элемента без отжима от последней. То есть если говорить на языке программирования – мы отслеживаем событие «KeyUp» и «MoveOut». При этом если точка соприкосновения выйдет из пределов текущего графического элемента, активное событие для него заканчивается, и функция ProcessInputData_Func завершает свою работу. В случае отжима точки соприкосновения на активной площади графического элемента происходит обработка события прикосновения, что рассмотрим далее.

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

 

 

 

Далее, если последнее условие выполняется, сначала программа изменяет значение поля структуры элемента TwoStateSwich_CheckState на активный или включен, для чего используется константа TWO_STATE_SWITCH_ON, дальше происходит вызов уже известной нам функции TwoStateSwichVisible_Func. Завершает работу вызов предварительно заданной функции-обработчика события прикосновения, для которой в качестве параметра передается активное состояние нашего переключателя.

 

 

 

В случае, если описанная выше условие не выполняется, программа осуществляет все те же операции только уже с использованием константы TWO_STATE_SWITCH_OFF.

 

 

Применение разработанной библиотеки в основной программе

 

Теперь рассмотрим, как применить все вышерассмотренные функции в основной программе для создания одной страницы и одного двухпозиционного переключателя.

Для начала в нашей программе нужно глобально объявить структуру новой страницы типа Page_TypeDef.

 

 

Далее в любой функции динамично создаем структуру, которая описывает, в данном случае, наш двухпозиционный переключатель.

 

 

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

Следующее действие – инициализация выше объявленной страницы Page1 и, с помощью функции AddPageControl_Func добавления к ней созданного выше переключателя.

 

 

 

Последнее, что остается – это отразить нашу страницу с добавленным ​​к ней переключателем, вызовом функции ShowPage с структуры созданной страницы.

 

 

 

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

 

 

Автор: Сергей Корсун, ХНУ (2010 г. вып.), г.  Хмельницк.