Передмова
В попередній статті інтегрували професійну бібліотеку EmWin до свого проекту та спробували щось відобразити на екрані і навіть помалювати за допомоги сенсорної панелі. В цій статті побудуємо, за допомоги програми GUIBuilder, графічний інтерфейс та додамо код взаємодії з графічним інтерфейсом.
Залізяччя
- Плата розробника STM32F407VE_Black, або комплект плати з дисплеєм
- Дисплей сумісний роз'ємом з платою розробника TFT LCD 3.2 240x320 ILI9341
- Программатор ST-Link V2
GUI Builder
Відкрийте програму "GUIBuilder", яка знаходиться в репозиторію CubeMX, або CubeIDE за шляхом "...\Middlewares\ST\STemWin\Software\GUIBuilder.exe".
Window
- Додайте елемент "Window";
- Встановіть властивості вікна: xPos - 0, yPos - 0, xSize - 240, ySize - 320;
- Встановимо колір вікна. ПКМ на елементі "Window", та оберіть "Set background color" -> Сірий (0xC0C0C0).
![]() |
Window |
Text
- Додайте елемент "Text";
- Встановимо позицію та розмір елементу. xPos - 0, yPos - 0, xSize - 240, ySize - 40;
- Встановимо шрифт. ПКМ на елементі "Text" -> "Set font" -> "GUI_FONT_24_1";
- Встановимо текст. ПКМ на елементі "Text" -> "Set text" -> "Example";
- Встановимо рівняння тексту. ПКМ на елементі "Text" -> "Set text alignment" -> "HV";
![]() |
Text |
Radio
- Додайте елемент "Radio";
- Встановимо позицію та розмір елементу: xPos - 20, yPos - 60, xSize - 200, ySize - 60, distance - 30;
- Дамо назву пунктам. ПКМ на елементі "Radio" -> "Set item text" -> "Label text" -> "Option 1" -> "Label index" -> "1", "Radio" -> "Set item text" -> "Label text" -> "Option 2" -> "Label index" -> "2";
- Встановимо шрифт: Font - GUI_FONT_20_1;
![]() |
Radio |
Progbar та 2 x Button
По аналогії з попередніми елементами додайте елементи "Progbar" та "Button". Розташуйте, встановіть розмір, оберіть шрифт, дайте назви кнопкам. Щоб було приблизно як на малюнку.
![]() |
Приклад інтерфейсу |
Генерування проекту
Меню: "File" -> "Save...". Файл "WindowDLG.c" збережеться в директорію програми "GUIBuilder" за шляхом "...\Middlewares\ST\STemWin\Software\WindowDLG.c".
Перевірка роботи
Продовжимо працювати з проектом який створили в попередній статті "Підключення бібліотеки EmWin та перевірка роботи".
- Відкрийте проект створений в процесі роботи з попередньою статтею, який знаходиться на вашому диску, та відкрийте його в Atolic TrueStudio, CubeIDE, або в IDE, яку ви використовуєте;
- Створіть файл "WindowDLG.h" в своєму засобі розробки, або будь яким іншим редактором, з таким змістом:
#ifndef __WINDOWDLG_H #define __WINDOWDLG_H #include "DIALOG.h" WM_HWIN CreateWindow(void); #endif /* __WINDOWDLG_H */
- Внесіть зміни до файлу "WindowDLG.c". Було:
// USER START (Optionally insert additional includes) // USER END #include "DIALOG.h"
- Стало:
// USER START (Optionally insert additional includes) // USER END #include "WindowDLG.h"
- Зкопіюйте ці файли, "WindowDLG.h" та "WindowDLG.с" в свій проект за шляхом "..\Drivers\EmWin\inc" та "..\Drivers\EmWin\src" відповідно;
- Відкрийте файл "main.c" та вставте в код рядок з файлом "WindowDLG.h":
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "ili9341_light.h" #include "GUI.h" #include "XPT2046_touch.h" #include "WindowDLG.h" /* USER CODE END Includes */
- В користувацькій секції 2 і безкінечному циклі видаліть код, який написали з попередньої статті. Тепер ця ділянка має виглядати так:
/* USER CODE BEGIN 2 */ GUI_Init(); lcdBacklightOn(); CreateWindow(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { GUI_Exec(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
- Можна вже компілювати, як немає помилок, заливаємо до чипу і запускаємо. На дисплеї з'явилося зображення, що ми створили за допомогою програми "GUIBuilder.exe". Але поки що наш GUI ніяк не реагує на натискання сенсорної панелі.
- Додамо декілька глобальних змінних до файлу "main.c", це добуті координати від сенсорної панелі і структура для координат і статусу натискання на сенсорну панель для GUI:
/* USER CODE BEGIN PV */ uint16_t x, y; GUI_PID_STATE tsState; /* USER CODE END PV */
- Перейдемо до користувацької секції 4. Там має бути функція зворотного виклику, яка викликається кожного разу коли ви натискаєте на сенсорну панель, та відпускаєте її. За це відповідає сигнал T_IRQ. Докладно налаштування цієї шпильки описано в статті. Перевірте, щоб переривання цієї ніжки відбувалось, як при падінні сигналу, так і при зростанні сигналу на ніжці - GPIO mode -> External Interrupt Mode with Rising/Falling edge trigger detection. Видаляємо весь код який знаходиться в функції зворотного виклику void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) і залишився з попереднього прикладу, та пишемо там такий код:
/* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) { if (GPIO_Pin == T_IRQ_Pin) { if(XPT2046_TouchPressed()) { tsState.Pressed = true; if(XPT2046_TouchGetCoordinates(&x, &y)) { tsState.x = x; tsState.y = GUI_GetScreenSizeY() - y; } } else { tsState.Pressed = false; tsState.x = -1; tsState.y = -1; } GUI_TOUCH_StoreStateEx(&tsState); } } /* USER CODE END 4 */
- Пояснення до коду. Кожного разу коли ви натискаєте чи відпускаєте сенсорну панель, викликається ця функція. Тут перевіряється чи відбулось натискання, або звільнення сенсорної панелі. Як натиснули, то берем координати точки натискання і заповнюємо структуру координатами і встановлюємо прапорець "натиснуто". Як звільнили сенсорну панель, то заповнюємо структуру відповідно, що координат немає і скидаємо прапорець "натиснуто". Заносимо данні з структури до GUI_TOUCH.
- Компілюємо, заливаємо, запускаємо. Тепер наш GUI реагує на натискання кнопок і можемо обрати опцію в елементі "Radio", але при цьому ще нічого не відбувається.
- Щоб додати реакцію на події коли натискати на опції елементу "Radio", відкриваємо файл "WindowDLG.c", знайдіть рядок "case ID_RADIO_0: // Notifications sent by 'Radio'", та додамо в секцію "case WM_NOTIFICATION_RELEASED:" код який буде оброблятись коли ви будете змінювати опцію в елементі "Radio" при відпусканні:
case ID_RADIO_0: // Notifications sent by 'Radio' switch(NCode) { case WM_NOTIFICATION_CLICKED: // USER START (Optionally insert code for reacting on notification message) // USER END break; case WM_NOTIFICATION_RELEASED: // USER START (Optionally insert code for reacting on notification message) { char buf[32]; hItem = WM_GetDialogItem(pMsg->hWin, ID_RADIO_0); RADIO_GetText(hItem, RADIO_GetValue(hItem), buf, 32); hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_0); TEXT_SetText(hItem, buf); } // USER END break; case WM_NOTIFICATION_VALUE_CHANGED: // USER START (Optionally insert code for reacting on notification message) // USER END break; // USER START (Optionally insert additional code for further notification handling) // USER END } break;
- Компілюємо, заливаємо, запускаємо. Тицяємо на опції "Radio" і текст елементу "Text" змінюється відповідно до змін.
- По аналогії додамо реакцію на натискання кнопок. Будемо змінювати значення елементу "Progbar", та міняти напис на елементі "Text". Спочатку додамо змінну "i", що буде зберігати значення для "Progbar", на початку файлу "WindowDLG.c":
/********************************************************************* * * Static data * ********************************************************************** */ // USER START (Optionally insert additional static data) int i; // USER END
- Та напишемо обробник події відпускання кнопок:
case ID_BUTTON_0: // Notifications sent by 'Button' switch(NCode) { case WM_NOTIFICATION_CLICKED: // USER START (Optionally insert code for reacting on notification message) // USER END break; case WM_NOTIFICATION_RELEASED: // USER START (Optionally insert code for reacting on notification message) { char buf[32]; hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_0); BUTTON_GetText(hItem, buf, 32); hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_0); TEXT_SetText(hItem, buf); if(i < 100) ++i; hItem = WM_GetDialogItem(pMsg->hWin, ID_PROGBAR_0); PROGBAR_SetValue(hItem, i); } // USER END break; // USER START (Optionally insert additional code for further notification handling) // USER END } break; case ID_BUTTON_1: // Notifications sent by 'Button' switch(NCode) { case WM_NOTIFICATION_CLICKED: // USER START (Optionally insert code for reacting on notification message) // USER END break; case WM_NOTIFICATION_RELEASED: // USER START (Optionally insert code for reacting on notification message) { char buf[32]; hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_1); BUTTON_GetText(hItem, buf, 32); hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_0); TEXT_SetText(hItem, buf); if(i > 0) --i; hItem = WM_GetDialogItem(pMsg->hWin, ID_PROGBAR_0); PROGBAR_SetValue(hItem, i); } // USER END break; // USER START (Optionally insert additional code for further notification handling) // USER END } break; // USER START (Optionally insert additional code for further Ids) // USER END } break; // USER START (Optionally insert additional message handling) // USER END
- Компілюємо, заливаємо, запускаємо. Тицяємо на елементи, спостерігаємо за реакцією.