суботу, 29 жовтня 2016 р.

STM32: Бібліотека для роботи з LCD WH1602(4) або іншим сумісним дисплеєм з контролером HD44780


upd 09.03.2019: Версія цієї бібліотеки для 4-х бітної шини і шини I2C знаходиться тут

Передмова

Ця бібліотека є вільним програмним забезпеченням і може вільно розповсюджується та змінюватись. Я не автор бібліотеки, а вніс зміни щодо автоматизації налаштувань, вніс зміни щодо більшої абстракції, а також усунув недолік, який псував все задоволення від роботи з цією бібліотекою, це випадкове "сміття" на екрані при увімкненні живлення. Щоб прибрати "сміття" потрібно було перезавантажувати пристрій кнопкою "reset". Бібліотека доволі вдала, як на мене, і має великий спектр функцій, щоб задовольнити будь які потреби, у відтворені інформації на дисплей типу WH1602 (WH1604) з контролером HD44780. Ця бібліотека створювалась початково, як кросплатформена для AVR, PIC, ARM. Чи збереглась кросплатформеність перевірити не маю змоги. Але на мікроконтролерах STM32F1xx і STM32F4xx перевірено - працює. В мережі можна зустріти різні варіації цієї бібліотеки, але набір функцій один і той самий. Зроблені мною зміни спрощують налаштування бібліотеки. В принципі налаштовувати взагалі нічого не потрібно. Ну може зовсім трішечки :-)

Схема підключення

Схема підключення

Схема підключення на малюнку. Підключати будемо по 4-х провідниковій схемі з заземленим сигналом W/R. Це означає що нам потрібно під'єднати до мікроконтролера шість дротів від дисплея. Такі як D4, D5, D6, D7, E, RS. До яких саме виводів мікроконтролеру під'єднувати дисплей, це вже вирішувати вам самим. Бібліотека допускає підключення кожного виводу дисплея на різні порти і будь які піни обраного/обраних порту/портів. Під'єднайте до дисплею живлення, це ніжка 2 - "+5 Вольт". Загальний мінус на ніжки дисплею 1 та 5. Та до ніжки дисплею під номером 3 резистивний дільник з підстроєчним резистором 10к для регулювання контрасту інформації, яка висвічується на екрані. Якщо ваш дисплей має підсвічування екрану, то можна ще подати живлення на підсвічування, це 15 і 16 ніжки дисплею. Живлення подати напряму, або через транзисторний ключ, який керується з ніжки мікроконтролеру. Тоді підсвічування можна вмикати та вимикати програмно, або навіть регулювати яскравість підсвічування налаштувавши ніжку, яка керує ключем підсвічування, як PWM (ШИМ).

STM32CubeIDE

Щоб бібліотека працювала правильно потрібно всім шпилькам, з якими буде з'єднано мікроконтролер та дисплей WH1602, дати назви (псевдоніми) за принципом:

  • Enable (E) - LCD_E
  • RS - LCD_RS
  • D4 - LCD_D4
  • D5 - LCD_D5
  • D6 - LCD_D6
  • D7 - LCD_D7

Обираєте зручні для вас, або вільні виводи мікроконтролеру. Виставляєте їх в режим "GPIO_Output" та називаєте за принципом, як зазначено вище. Приклад на малюнку. Червоними зонами позначив потрібне для підключення LCD:

Оголошення назв і режиму виводів для підключення LCD в STM32CubeIDE

Щодо налаштування LCD в то це все. Генеруєте код та перейдемо до додавання файлів, підключення бібліотеки та написання демо-коду.

Підключаємо бібліотеку до проекту

  1. Завантажте архів бібліотеки "hd44780.zip" собі на диск. В архіві знаходиться тека "hd44780" з підтеками "inc" та "src".
  2. Копіюємо файли бібліотеки до проекту. Можна скопіювати самі файли бібліотеки до проекту. Заголовні файли "h" у теку "inc" проекту, а сирцеві файли "c" до теки "src" проекту.

Передпроцесорні директиви #include 

Тепер, коли на рівні файлів все під'єднано як слід, треба в коді додати лиш один рядок в головний файл "main.c":

1
2
3
/* USER CODE BEGIN Includes */
#include "hd44780.h"
/* USER CODE END Includes */

Оце і все. Можна компілювати проект для перевірки. Як зроблено все правильно то компілятор скомпілює проект без помилок.

Список функцій бібліотеки

Бібліотека для своєї роботи і зручності користувача - має ряд функцій. Внутрішні функції розглядати не будемо, а розглянемо ті функції, що потрібні нам для виводу на дисплеї різноманітної інформації.

  • lcdInit - функція початкової ініціалізації дисплею;
  • lcdClrScr - функція очищення дисплею, курсор в початкове положення;
  • lcdReturn - функція повернення курсору в початкове положення;
  • lcdSetMode - функція встановлення режимів: дисплей увімк/вимк, курсор блимає увімк/вимк, курсор увімк/вимк;
  • lcdGoto - функція встановлює курсор в певне місце: рядок, стовпець;
  • lcdPuts - функція виводу текстового рядка;
  • lcdPutc - функція виводу окремого символу типу char;
  • lcdLoadChar - функція завантаження до пам'яті дисплею користувацького символу;
  • lcdDrawChar - функція малювання на дисплеї користувацького символу;
  • lcdBackSpace - функція зміщення курсору на один символ ліворуч і його знищення;
  • lcdScroll - функція зміщення всього тексту на один стовпець в потрібному напрямку (ліворуч або праворуч);
  • cursorShift - функція зміщення курсору на позицію праворуч чи ліворуч без знищення символу, що вже зображений. Призначена для редагування/виправлення тексту;
  • lcdItos - функція виводу на екран числа типу integer;
  • lcdFtos - функція виводу на екран числа типу float;
  • lcdNtos - функція виводу на екран числа типу integer з певним числом розрядів. Зайві розряди відсікаються. Розряди, яких не вистачає заповнюються нулями. Для фіксованого розташування на екрані;
  • lcdDrawBar - функція малювання індикатору виконання;
  • lcdClrBar - функція очищення індикатору виконання.

Список деяких параметрів бібліотеки

В файлі "lcd_cfg.h"

//-------------------------------
// DEFAULT CONFIGURATIONS
//-------------------------------
#define DEFAULT_DISPLAY_CONFIG  DISPLAY_CONFIG_4bit_2L_5x8
#define DEFAULT_ENTRY_MODE   ENTRY_MODE_INC_NO_SHIFT
#define DEFAULT_VIEW_MODE   VIEW_MODE_DispOn_BlkOff_CrsOff
#define USE_BUSY_FLAG    0u /* 1 (true) or 0 (false) */
  • дисплей під'єднано по 4-х бітному режиму, на 2 або 4 рядки, з шрифтом 5х8 пікселів;
  • зліва направо, без зсуву видимої частини DDR RAM пам'яті;
  • дисплей увімкнено, блимання вимкнуто, курсор вимкнуто;
  • чи використовується сигнал дисплею R/W, в нашому випадку - ні, тому 0.
#define MCU_FREQ_VALUE    SystemCoreClock/1000000 /* MHz. Minimal value = 1 MHz */

В змінній SystemCoreClock зберігається частота MCU в Герцах, ділимо на мільйон, отримуємо в мегаГерцах. Для правильних таймінгів дисплею.

//-------------------------------
// SET FORMATTED OUTPUT OPTIONS
//-------------------------------
#define USE_FORMATTED_OUTPUT   1u /* 1 (true) or 0 (false) */
#define TAB_SPACE     4u /* 1 .. 255 */
  • використовувати символи форматування /t, /n, /r в рядках з текстом - 1, не використовувати - 0;
  • довжина табуляції - 4.
//-------------------------------
// PROGRESS BAR OPTIONS
//-------------------------------
#define USE_PROGRESS_BAR   0u    /* 1 (true) or 0 (false) */
#define USE_REGRESS_BAR    1u    /* 1 (true) or 0 (false) */
#define PROGRESS_BAR_LINE   LCD_2nd_LINE /* Select lcd line: 1, 2, 3, 4, ... */
#define PROGRESS_BAR_HEIGHT   5u     /* in pixel: 1(min), 2, 3, 4, 5, 6, 7, 8(max) */
#define PROGRESS_BAR_WIDTH   10u    /* Number of chars in lcd line:  1, 2, .. , 8, 16, 20 */
  • використовувати індикатор виконання, що прогресує - 1, ні - 0;
  • використовувати індикатор виконання, що регресує - 1, ні -0;
  • індикатор виконання буде в другому рядку індикатора;
  • висота індикатора виконання в пікселях;
  • ширина індикатора в знакомісцях.

Демонстраційна програма

Замість того, щоб пояснювати в подробицях кожну функцію бібліотеки, це ви можете і самі знайти в коментарях самої бібліотеки, або в просторах інтернету. Наприклад тут. Краще приведу програму, яка наочно демонструє можливості бібліотеки.

Демо-код

На початку програми в файлі "main.c", оголошуємо прототип функції для імітації друкування тексту з клавіатури. Сама функцію розташуємо вже після головної функції "main":

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void imitationPrinting(char *ptr);
/* USER CODE END PFP */

Далі в тілі функції "main" до початку безкінечного циклу в блоці 1 - оголошуємо всі змінні які знадобляться для демонстрації:

/* USER CODE BEGIN 1 */
 uint32_t SystemFreq = HAL_RCC_GetHCLKFreq();
 char str[17] = {};
 float pi = 3.14;
 int t = 123;
 unsigned char men1[FONT_HEIGHT] = {0x0e,0x0e,0x04,0x1f,0x04,0x1a,0x01,0x00};
 unsigned char men2[FONT_HEIGHT] = {0x07,0x07,0x0a,0x07,0x02,0x05,0x09,0x00};
  /* USER CODE END 1 */

Ініціалізуємо наш дисплей в ділянці позначену як "USER CODE BEGIN 2":

/* USER CODE BEGIN 2 */
lcdInit(); // ініціалізація дисплею
/* USER CODE END 2 */

В безкінечному циклі пишемо нашу демонстраційну програму де я постарався використати всі функції бібліотеки, та написав коментар до кожного рядка:

  /* USER CODE BEGIN WHILE */
  while (1)
  {
   // очищення дисплею
   lcdClrScr();
   // встановлення позиції курсору
   lcdGoto(LCD_1st_LINE,1);
   //друкуємо текстовий рядок з переносом на інший рядок
   lcdPuts("CooCox CoIDE\nFreq MCU ");
   // друкуємо частоту мікроконтролеру в Mhz
   lcdItos(SystemFreq/1000000);
   lcdPuts(" Mhz");
   // чекаємо 3 секунди
   HAL_Delay(3000);
   /*
    * В циклі зміщуємо все що на екрані на 16 позицій праворуч
    */
   for (int i = 0; i < 16; ++i)
   {
    lcdScroll(RIGHT);
    HAL_Delay(250);
   }
   // очищаємо дисплей
   lcdClrScr();
   // до буферу str відправляємо текст
   sprintf(str,"STM32F103RB and");
   // функція імітації друкування тексту
   imitationPrinting(str);
   // до буферу str відправляємо текст
   sprintf(str,"LCD WH1602A Demo");
   // встановлення позиції курсору
   lcdGoto(LCD_2nd_LINE,0);
   // функція імітації друкування тексту
   imitationPrinting(str);
   // чекаємо 3 секунди
   HAL_Delay(3000);
   /*
    * В циклі зміщуємо все що на екрані на 16 позицій ліворуч
    */
   for (int i = 0; i < 16; ++i)
   {
    lcdScroll(LEFT);
    HAL_Delay(250);
   }
   // чекаємо секунду
   HAL_Delay(1000);
   /*
    * В циклі зміщуємо все що на екрані на 16 позицій праворуч
    */
   for (int i = 0; i < 16; ++i)
   {
    lcdScroll(RIGHT);
    HAL_Delay(250);
   }
   // чекаємо 2 секунди
   HAL_Delay(2000);
   // очищаємо дисплей
   lcdClrScr();
   // виводимо на екран текст
   lcdPuts("Float = ");
   // виводимо на екран число типу float з двома знаками після коми
   lcdFtos(pi,2);
   // встановлення позиції курсору
   lcdGoto(LCD_2nd_LINE,0);
   // виводимо на екран текст
   lcdPuts("Integer = ");
   // виводимо на екран число типу integer
   lcdItos(t);
   // чекаємо 3 секунди
   HAL_Delay(3000);
   // вмикаємо режим: дисплей увімкнутий, миготіння курсору вимкнуте, курсор увімкнутий
   lcdSetMode(VIEW_MODE_DispOn_BlkOff_CrsOn);
   // встановлення позиції курсору
   lcdGoto(LCD_2nd_LINE,16);
   // в циклі видаляємо весь рядок backspace'ом
   for (int i = 0; i < 16; ++i)
   {
    lcdBackSpace();
    HAL_Delay(100);
   }
   // встановлюємо позицію курсору
   lcdGoto(LCD_1st_LINE,16);
   // в циклі видаляємо весь рядок backspace'ом
   for (int i = 0; i < 16; ++i)
   {
    lcdBackSpace();
    HAL_Delay(100);
   }
   // встановлюємо режим: дисплей увімкнутий, миготіння вимкнуте, курсор вимкнутий
   lcdSetMode(VIEW_MODE_DispOn_BlkOff_CrsOff);
   // повертаємо курсор до дому
   lcdReturn();
   // друкуємо текст з табуляцією
   lcdPuts("\tLoading...");
   // встановлюємо позицію курсору
   lcdGoto(PROGRESS_BAR_LINE, PROGRESS_BAR_WIDTH);
   // друкуємо текст
   lcdPuts("[   %]");
   // в циклі показуємо індикатор виконання
   for(uint8_t i = 0; i <= PROGRESS_BAR_MAX_LOAD; ++i)
   {
    // встановлення позиції курсора
    lcdGoto(PROGRESS_BAR_LINE, PROGRESS_BAR_WIDTH + 1);
    // друкування відсотків виконання в чітко заданій позиції на три розряди
    lcdNtos((i*100)/PROGRESS_BAR_MAX_LOAD, 3 );
    // показуємо поточний стан індикатора виконання
    lcdDrawBar(i);
    // чекаємо 1/10 секунди
    HAL_Delay(100);
   }
   // чекаємо 3 секунди
   HAL_Delay(3000);
   // очищаємо дисплей
   lcdClrScr();
   /*
    * завантажуємо символ користувача до комірки пам'яті 6 і 7 в дисплей
    * комірки пам'яті від 0 по 5 зайняті індикатором виконання
    * якщо ви не використовуєте індикатор виконання, то можна завантажувати
    * з 0 комірки пам'яті дисплею
    */
   lcdLoadChar(men1,6);
   lcdLoadChar(men2,7);
   // друкуємо текст з табуляцією і переходом на новий рядок
   lcdPuts("\tRunning men\n");
   // в циклі показуємо людину що біжить :)))
   for(uint8_t i = 0; i < 8; i++)
   {
    lcdPutc(6);
    HAL_Delay(250);
    cursorShift(LEFT);
    lcdPutc(' ');
    lcdPutc(7);
    HAL_Delay(250);
    cursorShift(LEFT);
    lcdPutc(' ');
   }
   /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

Та не забуваємо про функцію, яку написали для демонстраційної програми і оголосили її прототип на початку програми. Функцію пишемо після головної функції "main" в головному файлі "main.c" в користувацькому блоці 4:

/* USER CODE BEGIN 4 */
// функція імітації друкування тексту з клавіатури
void imitationPrinting(char *ptr)
{
 // встановлюємо режим з увімкнутим курсором
 lcdSetMode(VIEW_MODE_DispOn_BlkOff_CrsOn);
 // поки не кінець рядку
 while(*ptr != 0)
 {
  // друкуємо поточний символ
  lcdPutc(*ptr++);
  // чекаємо 1/10 секунди
  HAL_Delay(100);
 }
 // встановлюємо режим з вимкнутим курсором
 lcdSetMode(VIEW_MODE_DispOn_BlkOff_CrsOff);
}
/* USER CODE END 4 */

Та не забуваємо, що в демонстраційній програмі використовуємо індикатор виконання "progress bar", а для цього  в файлі lcd_cfg.h константу USE_PROGRESS_BAR встановлюємо в 1u. "#define USE_PROGRESS_BAR    1u".

Без CubeMX

Підключення бібліотеки до проекту абсолютно таке саме як я описав вище. Створюєте проект для свого мікроконтролера в своєму засобі розробки. До файлу main.c додаєте рядок - #include "hd44780.h" в файлі бібліотеки lcd_cfg.h перевірте чи файл драйверу SPL чи HAL вказано правильно для вашого контролеру MCU, наприклад - #include "stm32f1xx.h".
А також потрібно потурбуватись самим про ініціалізацію виводів мікроконтролеру підключених до LCD. В кінці файлу "hd44780.c" є функція  "lcdGpioInit" в середині якої треба написати ініціалізацію виводів і портів, які під'єднано до дисплею.
Ось приклад, як це може виглядати, якщо виводи дисплею під'єднано до виводів мікроконтролеру PIN_0 - RS, PIN_1 - E, PIN_4...PIN_7 - D4...D7 порту "C":

void lcdGpioInit(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __HAL_RCC_GPIOC_CLK_ENABLE();

  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
}

А на початку файлу "main.c" треба додати декілька #define, щоб бібліотека працювала правильно. Зверніть увагу! Програма CubeMX додає до назви виводів, які ми називаємо для підключення LCD, ще PIN і GPIO_Port. Наприклад, сигнал RS під'єднано до виводу мікроконтролера PC0, тоді потрібно директивами #define позначити pin - LCD_RS_Pin як GPIO_PIN_0, та port - LCD_RS_GPIO_Port як GPIOC. І так для всіх виводів до яких під'єднано LCD:

#define LCD_RS_Pin GPIO_PIN_0
#define LCD_RS_GPIO_Port GPIOC
#define LCD_E_Pin GPIO_PIN_1
#define LCD_E_GPIO_Port GPIOC
#define LCD_D4_Pin GPIO_PIN_4
#define LCD_D4_GPIO_Port GPIOC
#define LCD_D5_Pin GPIO_PIN_5
#define LCD_D5_GPIO_Port GPIOC
#define LCD_D6_Pin GPIO_PIN_6
#define LCD_D6_GPIO_Port GPIOC
#define LCD_D7_Pin GPIO_PIN_7
#define LCD_D7_GPIO_Port GPIOC

Ну а все інше так само як і з CubeMX. Додайте до головного файлу "main.c" демонстраційну програму яка вже наведена вище. Компілюєте, прошиваєте, спостерігаєте.

Що саме додав до бібліотеки

До файлу "lcd_cfg.h" додав макроси щоб автоматично налаштовувалась бібліотека під визначені користувачем порти і виводи мікроконтролеру, що під'єднані до дисплею. Дяка за ідею користувачу "voland" з українського форуму програмістів.

#define MASK2PIN(mask) ((mask&GPIO_PIN_0)?0:(mask&GPIO_PIN_1)?1:(mask&GPIO_PIN_2)?2:(mask&GPIO_PIN_3)?3: \
   (mask&GPIO_PIN_4)?4:(mask&GPIO_PIN_5)?5:(mask&GPIO_PIN_6)?6:(mask&GPIO_PIN_7)?7: \
   (mask&GPIO_PIN_8)?8:(mask&GPIO_PIN_9)?9:(mask&GPIO_PIN_10)?10:(mask&GPIO_PIN_11)?11: \
   (mask&GPIO_PIN_12)?12:(mask&GPIO_PIN_13)?13:(mask&GPIO_PIN_14)?14:(mask&GPIO_PIN_15)?15:0)

#define RS_PIN_NUMBER (MASK2PIN(LCD_RS_Pin))
#define E_PIN_NUMBER (MASK2PIN(LCD_E_Pin))
#define RW_PIN_NUMBER (MASK2PIN(LCD_RW_Pin))
#define D7_PIN_NUMBER (MASK2PIN(LCD_D7_Pin))
#define D6_PIN_NUMBER (MASK2PIN(LCD_D6_Pin))
#define D5_PIN_NUMBER (MASK2PIN(LCD_D5_Pin))
#define D4_PIN_NUMBER (MASK2PIN(LCD_D4_Pin))

Можливо якийсь компілятор неадекватно сприйме таку конструкцію з опціями оптимізації, але в мене з трьома різними компіляторами оброблялось все коректно. Майте на увазі.

Автоматично визначається робоча частота MCU:

#define MCU_FREQ_VALUE    SystemCoreClock/1000000 /* MHz. Minimal value = 1 MHz */

Змінив функцію початкової ініціалізації дисплею, додаванням послідовності команд 0x30, 0x30, 0x28, щоб перемикання в 4-х бітний режим було надійним. Початково, послідовності 0x30, 0x30 не було. З-за цього на екрані після подачі живлення з'являлось випадкове "сміття". Лікувалось перезавантаженням пристрою кнопкою "ресет". А це дещо не зручно.

/*! \brief Initialize the LCD.
 *  \note This library use the 4-bit interface. */
void lcdInit(void)
{
 /* GPIO initialization. */
 setAllPinsAsOutputs();
 /* LCD initialization. */
 lcdWrite(0x30);
 lcd10usDelay(BUSY_CYCLE_TIME);
 lcdWrite(0x30);
 lcd10usDelay(BUSY_CYCLE_TIME);
 lcdConfig(DEFAULT_DISPLAY_CONFIG);
 lcdSetMode(DEFAULT_VIEW_MODE);
 lcdSetMode(DEFAULT_ENTRY_MODE);
 lcdClrScr();
 lcdReturn();
 #if (USE_PROGRESS_BAR)
  lcdInitBar();
 #endif
}

Невеличкі поради

Як не будете в своєму проекті використовувати "progress bar", то в файлі "lcd_cfg.h" назначте константі USE_PROGRESS_BAR значення 0. Це заощадить вам чимало байтів пам'яті мікроконтролеру. Та вивільнить аж 6 комірок пам'яті під користувацькі символи в дисплеї. 

Відео приклад підключення і використання бібліотеки HD44780

Плата розробника STM32F103RB Nucleo. Засіб розробки True Studio.


Плата розробника STM32F407VG Discovery. Засіб розробки System Workbench for STM32.


Файли з бібліотекою і проектами

15 коментарів:

  1. Доброго дня.
    У коді помилка. В режимі 4біт LCD_RS в 1 не виставляється!
    "SET(LCD_RS_OUT, LCD_RS);" нема взагалі. Від чого дисплей нічого не показує.
    А так дякую за код.

    ВідповістиВидалити
    Відповіді
    1. ""SET(LCD_RS_OUT, LCD_RS);" нема взагалі." - де немає взагалі? І чого саме? Дефайну SET? Дефайнів LCD_RS? Де саме їх немає? В бібліотеці? В прикладах? У вас?

      Видалити
    2. У коді який лежить на гітхабі.
      https://github.com/taburyak/LCD1602_I2C_OR_4BIT_STM32/blob/master/Src/hd44780.c
      Якщо використовувати для 4біт то дисплей нічого не покаже бо "LCD_RS" ніколи не віставляється в 1.

      Видалити
    3. Ще раз щиро дякую. Виправив помилку на github

      Видалити
  2. Среда IAR не обнаруживает установочного файла "main.h", инклюд которого прописан в файле конфигурации lcd_cfg.h. Вопрос, откуда берется файл "main.h"

    ВідповістиВидалити
    Відповіді
    1. он же генерируется кубом и лежит в core/inc
      и он так же инклюдится в main.c...
      настройте IAR что бы он видел заголовочные файлы из core/inc, по ходу он настроен криво...

      Видалити
  3. Багато разів використовував ці бібліотеки v2.01 в своїх проектах. На індикаторах 1602 ніяких проблем не було і все дуже зручно і функціонально. Застосував 2004-й в режимі 4 рядки 20 символів, 4BIT. 1-й і 2-й рядки - все нормально, 3-й і 4-й - виводяться, але з якимось однаковим для обох зміщенням знакомісць. Якщо можна, підкажіть, де підправити. Заздалегідь вдячний.

    ВідповістиВидалити
    Відповіді
    1. Вітаю, Микола.
      А чому б не скористатись свіжішою статтєю? https://stm32withoutfear.blogspot.com/2019/03/stm32-lcd-wh1602-hd44780-i2c.html
      Або спробуйте виправити ці рядки в файлі lcd_cfg.h на такі
      #define START_ADDRESS_3rd_LINE 0x14u
      #define START_ADDRESS_4th_LINE 0x54u
      Будь ласка повідомте чи це допомогло вам. Дякую.

      Видалити
  4. Дякую за підтримку і відповідь. На жаль знов спіткала мене невдача.. Код, завантажений з відсіля не спрацював зовсім (на дісплей не виводиться нічого, не розбирався, чьому). З гитхаба версія 3.0 працюе самісінько також. Спробую пояснити, що воно маю. При однаковому значенні номера місця символу у рядку від 0 до 19, для першого і другого рядків все відповідає заданому значенню. Для третього і четвертого при цьому виконується така послідовність знакомісць: 0 1 2 3 0 1 2 3 8 9 10 11 8 9 10 11 0 1 2 3. Якщо виводити текст довжиною, наприклад 18 символів з нульової позиції - все працює вірно.Таким чином вірно виводяться тільки позициї 0 - 3 та 8 - 11. Адреси міняв ще спочатку, як ви написали, не допомогало.

    ВідповістиВидалити
    Відповіді
    1. Так все ж ви якось виправили це, бо я не можу?

      Видалити
    2. Я перевірив. На 1602 і на 2004. Все працює.

      Видалити
    3. А в мене працює лише, коли адрес записувати напряму, наприклад, не lcdGoto(LCD_3rd_LINE,4), а lcdGoto(LCD_3rd_LINE,0x17u). Не знаю, в чому причина, але дякую за бібліотеку.

      Видалити
  5. Доброго дня.
    Куб виставляє в static void MX_GPIO_Init(void);
    static void MX_ADC1_Init(void);
    static void MX_TIM4_Init(void);
    а компілятор видає помилку. Видаляю Static-проблема зникає.
    Підкажіть, будь-ласка, новачку в чому тут проблема.
    Дякую

    ВідповістиВидалити