STM32F4VE LCD ili9341 16bit CubeMx_Keil
Всем привет!
В этой статье хочу рассказать как начать работать с LCD ili9341 созданным китайскими производителями специально для платы STM32F4VE. Сборная конструкция получается очень удобная для отладки программ в который требуется вывод информации на экран, а также управление программой с применением тачскрина. Также подобная конструкция, когда экран жестко соединен с платой - исключает много ошибок механического характера которые очень трудно отследить когда только начинаешь собирать тестовое устройство. Программу которую мы сейчас создадим, будет являться началом для развития проектов связанных с платой STM32F4VE и LCD ili9341 . В интернете можно найти примеры и библиотеки для работы с LCD ili9341, воспользуемся ими, скорректировав под свои задачи. Основная задача сейчас, состоит в том, чтобы вывести информацию на LCD, отобразить на экране рамки в которых будут цифры, подключить тач и нажимая на поле внутри рамок отобразить информацию в общей строке. Для этого будет необходимо:
1. Настроить конфигурацию портов микроконтроллера для работы с LCD ili9341 контроллера тач XPT2046с помощью CubeMx.
2. Подключить библиотеки для работы с LCD ili9341 и XPT2046.
3. Вывести на LCD ili9341 текст и нарисовать рамки
4. Отработать нажатие в области рамок и перевести это в цифры отобразив их в общей строке.
Приступим ..
По схеме (здесь и дальше я буду вставлять отрывки из схемы на плату STM32F4VE для того чтобы не переключаться и постоянно не сверяться).
Из схемы видно:
Для LCD ili9341 используется FSMC :
FSMC D1 - D15
FSMC A18
FSMC NOE
FSMC NWE
FSMC NE1
Управление подсветкой
LCD_BL
Для XPT2046с используется SPI :
T_SCK
T_MOSI
T_PEN
T_CS
T_MISO
Со схемой определились. Начнем конфигурировать порты микроконтроллера в CubeMx.
Загружаем CubeMx - > выбираем создание нового проекта
Во вкладке поиск вводим STM32F407VE (как на плате)
В появившемся окне
Выбираем микроконтроллер STM32F407VE (как на плате) и переходим в основное окно конфигурации. Начинаем настраивать:
1. Отладка программы микроконтроллера STM32F407VE в меню System core
2. RCC в меню System core
Устанавливаем Crystal/Ceramic Resonator и его настройки
Устанавливаем HSE Calibration Value - 8 .
Вот откуда эта цифра Y2 8M на схеме
3. Переходим в меню Connectivity и выбираем FSMC и настраиваем его следующим образом
Data - 16bits - все на разъеме - можно пересчитать ....
LCD Register Select устанавливает как на схеме.
Остальные настройки оставляем как есть
Настраиваем выход для управления подсветкой LCD ili9341
По схеме (номер 28 на разъеме)
Порт PB1 настраиваем как выход
переименовываем его
Перейдем к настройке портов STM32F4VE для возможности управлять тачскрином который работает на микросхеме XPT2046с.
Смотрим схему
XPT2046с работает по интерфейсу SPI и по схеме он второй т.е. SPI2, T_CS - выбор программный (у микроконтроллера STM32F407VE соответственно выход)
+ выход T_PEN (у микроконтроллера STM32F407VE соответственно вход)
+ необходимо настроить прерывание по приходу сигнала от тач.
Настраиваем - > переходим в меню Connectivity и выбираем SPI2
В открывшемся окне выбираем режим работы
И настраиваем его
Настройки скорости пока оставляем как есть. Они изменяться когда установим основную частоту работы микроконтроллера.
Обратите внимание, что CubeMx по умолчанию назначает SP2 на порт С!!!! Если так произошло необходимо перенастроить на порт PB!!!!
Настраиваем T_PEN (PС5 ) т.к. отклик при нажатии на экран мы будем получать через прерывание порт необходимо настроить следующим образом
переименовываем для удобства
Настроим T_CS
переименовываем для удобства
Идем в настройки
Настраиваем PB1
Настраиваем PB12
Настраиваем PC5. Настройка PC5 как вход с прерыванием!!!
После настройки входа на прерывание - необходимо включить глобальные прерывания!!!
Для этого переходим
И в появившемся окне устанавливаем как на фото ниже
В итоге
С портами микроконтроллера пока все.
Переходим во вкладку
И настраиваем рабочую частоту микроконтроллера следующим образом:
Входная частота 8 000 000 Гц (8 MHz) - > HSE (внешний кварцевый резонатор) -> PLL Source Mux на HSE -> делитель 4 -> умножитель 168
Далее по цепочке - System Clock Mux на PLLCLK
И конечная часть
Отлично. Проверим изменились ли параметры SPI. Переходим во вкладку
Проверяем изменения .
Минимальная конфигурация создана переходим в
Настраиваем что куда ..
Дальше создаем проект.
Ожидаем
И если все нормально получаем запрос
С настройками в CubeMx можно закончить!
Пустой файл архива проекта CubeMX- скачать
Для того чтобы начать работать с LCD ili9341 и тачем на микросхеме XPT2046 нам необходимо добавить библиотеки в свой проект. Скачиваем два архива с библиотеками.
ILI9341 - архив скачать
XPT2046 - архив скачать
и распаковываем их в папку проекта. У меня это выглядит так
Переходим в Keil и пропишем пути к скопированным папкам.
Выбираем
В строке Include Paths нажимаем кнопку с тремя точками.
Добавляем пути для папок
Нажимаем OK два раза
Теперь создадим папки в проекте.
В основном окне Keil. Выбираем основную папку проекта нажимаем правую клавишу мыши и создаем новую Group (папку).
Создавшуюся папку переименовываем для удобства
Также делаем и для тача и получаем
После создания папок в проекте Keil - необходимо в них добавить файлы. Для этого наводим указатель мыши на папку и два раза кликаем на ней. Должно открыться окно выбора файлов. Ищем наши папки и добавляем файлы нажав ADD.
Тоже самое со второй папкой
В результате дерево проекта будет представлять вид
Открываем файл main.c и начинаем его заполнять содержимым строго добавляя в секции пользователя которые создал CubeMx. Иначе если в CubeMx поправить или добавить что-нибудь - области НЕ пользовательские будут затерты и в них придется вносить все заново.
Я буду указывать данные в секциях пользователя. Их необходимо скопировать и поставить в теже области в своем файле main.c
Добавим библиотеки в проект...
/* USER CODE BEGIN Includes */
#include "XPT2046_touch.h"
#include "ili9341.h"
#include <stdio.h>
#include <string.h>
/* USER CODE END Includes */
Добавим переменные
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint16_t x = 0, y = 0;
uint16_t xx = 0, y1 = 0;
char str1[20];
char str2[20];
char str3[20];
char str4[20];
char str[20];
bool flag1;
uint16_t strw;
/* USER CODE END 0 */
Выводим рамки и надписи до основного цикла.
/* USER CODE BEGIN 2 */
lcdBacklightOn();
lcdInit();
lcdSetOrientation(LCD_ORIENTATION_LANDSCAPE);
lcdFillRGB(COLOR_WHITE);
// Пишем текст сверху экрана
lcdSetTextFont(&Font20);
lcdSetTextColor(COLOR_BLACK, COLOR_WHITE);
lcdSetCursor(50, 5); // xy
lcdPrintf("www.stm32res.ru");
// Начинаем рисовать рамки
lcdDrawRect(50,70,230,30,COLOR_BLUE);
lcdDrawRect(30,120,40,30,COLOR_BLUE); //lcdDrawRect(x, y, w, h, color)
lcdDrawRect(75,120,40,30,COLOR_BLUE);
lcdDrawRect(120,120,40,30,COLOR_BLUE);
lcdDrawRect(165,120,40,30,COLOR_BLUE);
lcdDrawRect(210,120,40,30,COLOR_BLUE);
lcdDrawRect(255,120,50,30,COLOR_BLUE);
lcdDrawRect(30,155,40,30,COLOR_BLUE); //lcdDrawRect(x, y, w, h, color)
lcdDrawRect(75,155,40,30,COLOR_BLUE);
lcdDrawRect(120,155,40,30,COLOR_BLUE);
lcdDrawRect(165,155,40,30,COLOR_BLUE);
lcdDrawRect(210,155,40,30,COLOR_BLUE);
lcdDrawRect(255,155,50,30,COLOR_BLUE);
// Начинаем заполнять рамки цифрами
lcdSetTextFont(&Font24);
lcdSetTextColor(COLOR_BLACK, COLOR_WHITE);
lcdSetCursor(45, 125); // x
lcdPrintf("1");
lcdSetCursor(90, 125); // x
lcdPrintf("2");
lcdSetCursor(135, 125); // x
lcdPrintf("3");
lcdSetCursor(180, 125); // x
lcdPrintf("4");
lcdSetCursor(225, 125); // x
lcdPrintf("5");
lcdSetCursor(45, 160); // x
lcdPrintf("6");
lcdSetCursor(90, 160); // x
lcdPrintf("7");
lcdSetCursor(135, 160); // x
lcdPrintf("8");
lcdSetCursor(180, 160); // x
lcdPrintf("9");
lcdSetCursor(225, 160); // x
lcdPrintf("0");
lcdSetCursor(263, 125); // x
lcdPrintf("<-");
lcdSetTextFont(&Font20);
lcdSetCursor(265, 160); // x
lcdPrintf("Ok");
/* USER CODE END 2 */
В основном цикле
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
sprintf(str1,"x = %u",x);
sprintf(str2,"y = %u",y);
if (flag1 ==1) // Флаг по которому мы определяем, что сработало прерывание
{
flag1 =0; // Сбрасываем установившийся в подпрограмме прерывания флаг
// проверяем в какую область нажали на экране. Нас интересует только
// внутренняя площадь рамок
if(x>=31 && x<=65) // Координаты по х
{
if(y>=119 && y<=146) // Координаты по y
{
xx =1; // Если попали то передаем переменной - номер 1
sprintf(str3,"%u",xx);
strcat(str,str3); // Добавляем символ к общей строчке
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=80 && x<=109)
{
if(y>=111 && y<=148)
{
xx =2;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=131 && x<=158)
{
if(y>=109 && y<=151)
{
xx =3;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=166 && x<=203)
{
if(y>=120 && y<=151)
{
xx =4;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=201 && x<=250)
{
if(y>=110 && y<=151)
{
xx =5;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=32 && x<=80)
{
if(y>=156 && y<=181)
{
xx =6;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=78 && x<=110)
{
if(y>=150 && y<=181)
{
xx =7;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=121 && x<=165)
{
if(y>=145 && y<=181)
{
xx =8;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=168 && x<=203)
{
if(y>=156 && y<=181)
{
xx =9;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=212 && x<=247)
{
if(y>=156 && y<=181)
{
xx =0;
sprintf(str3,"%u",xx);
strcat(str,str3);
strw =strlen(str);
sprintf(str4,"%u",strw);
}
}
if(x>=255 && x<=280)
{
if(y>=119 && y<=150)
{
// Эту рамку назначьте самостоятельно
}
//
}
}
// Выводим то что врамках
lcdSetTextFont(&Font20);
lcdSetCursor(60, 78); // x,y
lcdPrintf(str) ;
lcdSetTextFont(&Font20);
lcdSetCursor(60, 200); // x,y
lcdPrintf(str1) ; //"x= "
lcdSetTextFont(&Font20);
lcdSetCursor(180, 200); // x,y
lcdPrintf(str2); //"y= "
lcdSetTextFont(&Font20);
lcdSetCursor(285, 75); // x,y
lcdPrintf(str4);
}
/* USER CODE END 3 */
И наконец - обработчик прерывания - нажатие на тачскрин. Пишется в самом низу файла main.c
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
{
if (GPIO_Pin ==T_PEN_Pin)
{
if(XPT2046_TouchPressed())
{
if(XPT2046_TouchGetCoordinates(&x, &y))
{
flag1=1; // если нажали на экран выставляем флаг срабатывания нажатия
lcdDrawPixel(x, y, COLOR_RED); // будет рисоваться точка при нажании на экран
}
}
}
}
/* USER CODE END 4 */
После того как файл main.c собираем и проверяем проект
Ошибок быть не должно. Предупреждения будут.
Если ошибок нет - необходимо настроить программатор. Идем в настройки проекта во вкладку DEBUG
Т.к. у меня ULINK 2 я настраиваю его
Нажимает Ok два раза и
В результате в микроконтроллер запишется программа и должно получиться как на video ниже.
Ура!!! Все получилось!!!
Для тех у кого не получилось с первого раза берем мой проект - скачать