STM32F4VE LCD ili9341 16bit CubeMx_Keil

Опубликовано stm32 - чт, 02/27/2020 - 14:09

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 для того чтобы не переключаться и постоянно не сверяться).

u1

Из схемы видно:

Для 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 - > выбираем создание нового проекта 

u2

Во вкладке поиск вводим  STM32F407VE (как на плате)

u3

В появившемся окне 

u4

Выбираем микроконтроллер STM32F407VE (как на плате) и переходим в основное окно конфигурации. Начинаем настраивать:

1. Отладка программы микроконтроллера STM32F407VE в меню System core

u5

 

u16

2. RCC в меню System core

u6

Устанавливаем Crystal/Ceramic Resonator и его настройки

u7

Устанавливаем HSE Calibration Value - 8 .

Вот откуда эта цифра Y2 8M на схеме

u8

 

u12

3. Переходим в меню Connectivity и выбираем FSMC и настраиваем его следующим образом

 

u9

 

Data - 16bits - все на разъеме - можно пересчитать ....

u13  u14u15

LCD Register Select устанавливает как на схеме.

u11

Остальные настройки оставляем как есть 

u10

Настраиваем выход для управления подсветкой LCD ili9341

По схеме (номер 28 на разъеме) 

u18

Порт PB1 настраиваем как выход

u19

 

u20   переименовываем  его  p14 

 

 

 

Перейдем к настройке портов STM32F4VE для возможности управлять тачскрином который работает на микросхеме  XPT2046с.  

 

Смотрим схему

 

u26

 XPT2046с  работает по интерфейсу SPI и по схеме он второй т.е. SPI2,  T_CS - выбор программный  (у микроконтроллера STM32F407VE  соответственно выход)

 

u27

+ выход T_PEN (у микроконтроллера STM32F407VE  соответственно вход

u28

+ необходимо настроить прерывание по приходу сигнала от тач.

Настраиваем - > переходим в меню Connectivity и выбираем SPI2

u29

В открывшемся окне выбираем режим работы

u31

И настраиваем его 

u32

Настройки скорости пока оставляем как есть. Они изменяться когда установим основную частоту работы микроконтроллера.

 

u33       g62

Обратите внимание,  что CubeMx по умолчанию назначает SP2 на порт С!!!!  Если так произошло необходимо перенастроить на порт PB!!!!

     Настраиваем T_PEN (PС5 ) т.к. отклик при нажатии на экран мы будем получать через прерывание порт необходимо настроить следующим образом

u43         переименовываем для удобства        u37

Настроим T_CS

 

u38переименовываем для удобства u62

 

Идем в настройки 

p15

Настраиваем PB1

p16

Настраиваем PB12

p17

 

Настраиваем  PC5. Настройка PC5 как вход с прерыванием!!!

p18

 

 

После настройки входа на прерывание - необходимо включить глобальные прерывания!!!

Для этого переходим

 u47

И в появившемся окне устанавливаем как на фото ниже

u57

В итоге

u58

С портами микроконтроллера пока все.

Переходим во вкладку 

u64

И настраиваем рабочую частоту микроконтроллера следующим образом:

Входная частота 8 000 000 Гц (8 MHz) - > HSE (внешний кварцевый резонатор) -> PLL Source Mux на HSE -> делитель 4 -> умножитель 168 

u48

 

Далее по цепочке - System Clock Mux на PLLCLK 

u49

 

И конечная часть 

u50

Отлично. Проверим изменились ли параметры SPI. Переходим во вкладку 

u52

Проверяем изменения .

u53

Минимальная конфигурация создана переходим в 

 

u54

Настраиваем что куда ..

u55

Дальше создаем проект.

u59

Ожидаем 

u60

И если все нормально получаем запрос

u61

С настройками в CubeMx можно закончить!

Пустой файл архива проекта CubeMX- скачать

Для того чтобы начать работать с LCD ili9341 и тачем на микросхеме XPT2046 нам необходимо добавить библиотеки в свой проект. Скачиваем два архива с библиотеками.

ILI9341  - архив скачать

XPT2046  - архив скачать

 и распаковываем их в папку проекта. У меня это выглядит так 

p1

Переходим в  Keil и пропишем пути к скопированным папкам.

p4

Выбираем 

p3

 В строке Include Paths нажимаем кнопку с тремя точками.

p5

Добавляем пути для папок 

p6

Нажимаем OK два раза

Теперь создадим папки в проекте.

В основном окне Keil. Выбираем основную папку проекта нажимаем правую клавишу мыши и создаем новую Group (папку). 

 

p7_0

Создавшуюся папку переименовываем для удобства

p9

Также делаем и для тача и получаем 

p10

 

После создания папок в проекте Keil - необходимо в них добавить файлы. Для этого наводим указатель мыши на папку и два раза кликаем на ней. Должно открыться окно выбора файлов. Ищем наши папки и добавляем файлы нажав ADD.

p11

Тоже самое со второй папкой 

p12

В результате дерево проекта будет представлять вид

o1

Открываем файл 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 собираем и проверяем проект

o2

Ошибок быть не должно. Предупреждения будут.

Если ошибок нет - необходимо настроить программатор. Идем в настройки проекта во вкладку DEBUG

p4_0

p21

Т.к. у меня ULINK 2 я настраиваю его

p22

p23

Нажимает Ok два раза и 

o3

В результате в микроконтроллер запишется программа и должно получиться как на video ниже.

Ура!!! Все получилось!!!

Для тех у кого не получилось с первого раза берем мой проект - скачать 

 

 

Video
Видео файл
Яндекс.Метрика