STM Урок 6. Библиотека HAL. LCD 20×4. 4-битный режим



 

Урок 6

Библиотека HAL. LCD 20×4. 4-битный режим

 

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

Мы будем подключать дисплей на контроллере HD44780, хотя в даташите указан S6A0069, который является также аналогом первого. Дисплей отображает символьную информацию размерностью 4 строки по 20 символов. И подключать мы будем данный дисплей 4-битным образом. Так мы можем сэкономить 4 ножки порта. В данном режиме мы передаем данные по половине байта, сначала старшую часть, потом младшую.

Выглядит данный дисплей следующим образом:

 

image02

 

Дисплей к микроконтроллеру STM32F407VG мы подключим вот таким образом (нажмите на картинку для увеличения изображения)

 

image01_0500

 

На схеме изображен индикаотор 20х2, но смысл тот же, просто в программе не нашлось дисплея 20х4.

По подключению дисплея и работе с ним в 4-битном режиме можно подробно посмотреть в уроке по AVR, в котором мы рассматривали дисплей 16х2.

Но всё равно я должен напомнить, что GND и VCC зачастую могут меняться местами в зависимости от типа дисплея, поэтому смотрите документацию именно на свой дисплей, иначе он неминуемо выйдет из строя.

В принципе тем самым мы разобрали уже назначение 1 и 2 ножек модуля дисплея.

Назначение следующих ножек модуля:

3 — V0 — это ножка, с помощью которой регулируется контрастность дисплея. То есть контрастность дисплея будет зависеть от поданного напряжения на данную ножку. Как правило берётся переменный резистор на 10 килоом, подключенный крайними ножками на общий провод и на питание, а с центральной ножки данного резистора провод идёт как раз на ножку V0 и посредством регулировки движка резистора мы и регулируем контрастность дисплея в модуле.

4 — RS — это такая хитрая ножка, с помощью которой контроллер дисплея будет «знать», какие именно данные нахдятся на шине данных. Если мы подадим на данную ножку логический 0, то значит будет команда, если 1 — то это данные.

5 — RW — данная ножка в зависимости от логического состояния на ней говорит контроллеру дисплея, будем мы с него читать или будем мы в него писать данные. Если будет 0 — то мы в контроллер дисплея будем писать, а если 1 — то будем читать данные из контроллера дисплея. Данная функция используется редко. Как правило мы всегда только пишем данные в дисплей. Чтение обычно требуется для того, чтобы определить, что дисплей принял наши данные, либо чтобы определить состояние. Но существуют определённые тайминги, позволяющие нам на слово «верить» котнроллеру дисплея, что он наши данные принял и обработал. Также читать мы можем из памяти дисплея, что, в принципе, незачем. Поэтому мы обычно соединяем данный контакт с общим проводом.

6 — E — это так называемая стробирующая шина, по спадающему фронту (когда 1 меняется в 0) на которой контроллер дисплея понимает, что именно сейчас наступил момент чтения данных на ножках данных D0 — D7, либо передачи данных из модуля в зависимости также от состояния ножки RW.

Ножки D0 — D7 — это параллельная восьмибитная шина данных, через которую и передаются или принимаются данные. Номера 0 — 7 соответствуют одноименным битам в байте данных. Но также есть ещё 4-битный способ передачи данных в контроллер и из контроллера дисплея, когда используются только ножки данных D4 — D7, а ножки D0 — D3 уже не используются. Как правило такой способ используется в целях экономии ножек порта и именно такой способ мы и будем сегодня использовать, так как мы теряем скорость вдвое, но у нас дисплей символьный и спешить нам некуда. В 4-битном режиме мы передаём или принимаем байт в 2 приёма по половинке, сначала старшую часть байта, затем младшую.

Ножки A и K — это анод и катод для подачи напряжения для питания светодиодной подсветки дисплея. Как правило можно питать от 5 вольт, и от 3 вольт, но желательно поставить токоограничивающий резистор на 100 ом и скорее всего тогда подсветка дисплея «проживёт» дольше. Всё это обычно указывается в технической документации на дисплей. Мы поставим на 330.

Для данных мы будем использовать порт D, а для урпавления — 8 и 9 ножки порта B.

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

 

image03

 

Здесь мы видим, по какому адресу нам нужно будет отправлять байт с кодом символа.

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

 

image04

 

Также условием выполнения команды именно с таким временным интервалом является тактирование контроллера дисплея частотой 270 кГц.

 

 

Также чтобы запустить наш дисплей в работу, так как там существует контроллер, нужна будет первоначальная инициализация. В докуентации, правда в другой — на дисплей 1602 есть порядок инициализации. Он ничем не отличается от инициализации дисплея 2004. Для 4-битного способа подключения он такой

 

image05

 

Проект MYLCD80 я сделал из TEST002 таким же образом, как и на прошлом занятии.

Открываем MYLCD80 в кубе. Отключаем таймер TIM6

 

image00

 

Также за ненадобностью отключим лапки PA1,PD12,PD13,PD14,PD15

 

image06    image07

 

Включим на выход лапки PB8, PB9,PD0,PD4,PD5,PD6,PD7

 

image08

 

В настройках вообще ничего не трогаем. Генерируем проект, собираем.

Видим ошибки на наш ручной код по таймеру, убираем строку

 

        tim6_counter=0;

 

а также всё написанное нами из бесконечного цикла.

Из main.h переменную

 

uint8_t tim6_counter;

 

Подключаем новые файлы lcd.h и lcd.c с содержимым:

 

lcd.h:

#ifndef LCD_H_

#define LCD_H_

 

#include «stm32f4xx_hal.h»

 

#endif /* LCD_H_ */

 

lcd.c:

#include «lcd.h»

 

 

Затем подключаем lcd.h к main.h

 

main.h:

#include «lcd.h»

 

Напишем дефайны в файл lcd.h, для удобного управления уровнями на ножках данных

 

//—————————————-

#define d4_set() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_SET)

#define d5_set() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET)

#define d6_set() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET)

#define d7_set() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET)

#define d4_reset() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_RESET)

#define d5_reset() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET)

#define d6_reset() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET)

#define d7_reset() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_RESET)

 

#define e1                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET) // установка линии E в 1

#define e0    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET) // установка линии E в 0

#define rs1   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET) // установка линии RS в 1 (данные)

#define rs0   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET) // установка линии RS в 0 (команда)

//—————————————-

 

Смотрим выше таблицу, как инициализировать 4-битный режим и собственно пишем инициализацию.

Начинаем с задержки

 

void LCD_ini(void)

{

        HAL_Delay(40);

}

 

Пишем на нее прототип в заголовочный файл.

Затем нам нужно написать функцию записи данных в память дисплея

 

void LCD_WriteData(uint8_t dt)

{

        if(((dt >> 3)&0x01)==1) {d7_set();} else {d7_reset();}

        if(((dt >> 2)&0x01)==1) {d6_set();} else {d6_reset();}

        if(((dt >> 1)&0x01)==1) {d5_set();} else {d5_reset();}

        if((dt&0x01)==1) {d4_set();} else {d4_reset();}

}

 

Напишем функцию для небольшой задержки

 

void delay(void)

{

        uint16_t i;

        for(i=0;i<1000;i++)

 {

         

 }

}

 

Теперь напишем функцию для команд

void LCD_Command(uint8_t dt)

{

        rs0;

        LCD_WriteData(dt>>4);

        e1;

        delay();

        e0;

        LCD_WriteData(dt);

        e1;

        delay();

        e0;

}

 

Затем продолжим писать функцию инициализации дисплея, поглядыая время от времени в техническую документацию и в урок по AVR, где было рассказано уже про каждую команду

 

void LCD_ini(void)

{

        HAL_Delay(40);

        rs0;

        LCD_WriteData(3);

        e1;

        delay();

        e0;

        HAL_Delay(1);

        LCD_WriteData(3);

        e1;

        delay();

        e0;

        HAL_Delay(1);

        LCD_WriteData(3);

        e1;

        delay();

        e0;

        HAL_Delay(1);

        LCD_Command(0x28);//режим 4 бит, 2 линии (для нашего большого дисплея это 4 линии), шрифт 5х8

        HAL_Delay(1);

        LCD_Command(0x28);//еще раз для верности

        HAL_Delay(1);

        LCD_Command(0x0F);//дисплей включаем (D=1), также включаем пока все курсоры

        HAL_Delay(1);

        LCD_Command(0x01);//уберем мусор

        HAL_Delay(2);

        LCD_Command(0x06);//пишем влево.

        HAL_Delay(1);

        LCD_Command(0x02);//возврат курсора в нулевое положение

        HAL_Delay(2);

}

 

Вызываем инициализацию из главного модуля

 

  /* USER CODE BEGIN 2 */

        LCD_ini();

  /* USER CODE END 2 */

 

Прошиваем, смотрим.

 

image09

 

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

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

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Техническая документация:

Дисплей LCD2004

Дисплей LCD1602

 

Отладочную плату и дисплей LCD 20×4 можно приобрести здесь:

STM32F4-DISCOVERY

Дисплей LCD 20×4

 

 

Смотреть ВИДЕОУРОК

 

STM32 Библиотека HAL. LCD 20x4. 4-битный режим

28 комментариев на “STM Урок 6. Библиотека HAL. LCD 20×4. 4-битный режим
  1. Олег:

    Здравствуйте. А почему функция записи данных в память дисплея именно так делается, почему нельзя отправлять число сразу в ODR?

    • Здравствуйте! Мы изучаем применение библиотеки HAL, а не запись в регистры напрямую. Можно конечно и напрямую бесконтрольно, но тогда это не будет соответствовать теме.

  2. Сергей:

    У Вас на схеме подключения индикатора ошибка —  к сигналу R/S подлючен анод подсветки индикатора. Нужно соеденительную точку чуть ниже опустить — на линию Vdd

  3. Андрей:

    Непонятно вот это:

    LCD_Command(0x28);//режим 4 бит, 2 линии (для нашего большого дисплея это 4 линии), шрифт 5х8

    Каким образом можно передать число 0x28 по четырехбитной линии?​ В двоичной форме это 101000 и  единица на четвертой справа позиции должна уйти от контроллера к дисплею по линии d3, которая у нас не подключена.

     

  4. Александр:

    Здравствуйте!
    Попытался «переделать» проект под STM32F103C8T6 (отладочная платка с Китая). Настроил порты а Cube, добавил .c и .h файлы из вашего проекта, переправил в .h файле «дефайны» под свои порты. Тактирование от внешнего кварца (8 МГц). Проект собирается нормально, но на дисплее белиберда какая-то. Скажите что я мог сделать не так?

  5. Александр:

    Спустя некоторое время всё-таки вывел текст на экран. Немного поменял алгоритм инициализации и временные задержки.
    Спасибо за ваше внимание и труд! Очень интересные и полезные уроки, даже не смотря на «мои танцы с бубном», так сказать. Где-то на видео вы сказали примерно следующее:»Не научившись находить ошибки не научишься программировать» — совершенно с вами согласен! 🙂

  6. onur:

    Привет nArod, может ли этот код использоваться для stm32f103c8t?

  7. RootShell:

    По схеме: нога 15(NC_1) дисплея через токоограничивающий резистор подключена к 95(PB8) mc и 4(RS) дисплея. Нужно на 19(Vdd) mc и на 2(Vcc) дисплея. (На 5 вольт). Видимо на схеме ошибка.

  8. Борис:

    Здравствуйте Narod Stream.

    Подскажите пожалуйста.Вы подключили дисплей на 5 вольт,а stm32 на 3 вольта?И проблем не возникает?
    Например:для управления дисплея как мы понимаем нужен 5 вольт, но stm32 выдает с ног всего лишь по 3 вольта.И другие подобные примеры в связи разницей напряжения.

    Спасибо.

  9. Aleksandr:

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

  10. Дмитрий:

    Добрый день! Не инициализируется дисплей, черные квадраты в верхнем ряду. Задержки менял, не помогает. Под авр работает, здесь нет…Подозреваю что конкретно мой дисплей не работает с 3 вольтами.

  11. Сергей:

    Добрый день!
    При «линейном программировании» все работает, при попытке использовать библиотеку LCD в Free RTOS не работает.
    В чем причина?

    • Скорей всего потеря значений, так как функции занимают очень продолжительное время (в один квант не влезают) и поэтому вызов идёт из нескольких задач одновременно. Вместо глобальных переменных здесь уже надо использовать параметры или очереди, а также задержки стандартные обязательно заменить на RTOS-овские. А, ещё глобальные переменные полностью исключить.

  12. Денис:

    Добрый вечер! У меня LCD на контроллере KS0066U, для перехода на 4 битный режим надо на DB5 отправить два раза 1, как учесть это в программе не понимаю, это мой первый проект, помогите пожалуйста.

  13. Илья:

    Библиотеку так и не смог запустить, то работает то не работает, хотя просидел весь вечер)) Но все равно спасибо, я как начинающий кое что узнал. В итоге запустил другую с гитхаба. В этой все же не понравился момент с таймером привязанным к тактовой частоте.
    И еще один очень важный момент !!! -величина напряжений на информ. выводах дисплея, должна быть равна питанию дисплея. т.е. если у вас дисплей может работать от 3.3 вольт, то все ок, а если работает только от 5 вольт, то надо сделать преобразователь уровня на транзисторах к примеру. Если это правило не соблюсти, то некоторые экземпляры отказываются работать и это сбивает с толку.

  14. Евгений Олегович:

    Для дисплеев Winstar на контроллере ks0066u

    void LCD_Command(uint8_t dt)
    {
    rs0;
    LCD_WriteData(dt);
    e1;
    delay();
    e0;
    }
    //—————
    void LCD_ini(void)
    {
    HAL_Delay(40);
    LCD_Command(2);
    LCD_Command(2);
    LCD_Command(3);
    HAL_Delay(40);
    LCD_Command(0);
    LCD_Command(15);
    HAL_Delay(40);
    LCD_Command(0);
    LCD_Command(1);
    HAL_Delay(40);
    LCD_Command(0);
    LCD_Command(7);
    }

  15. Антон:

    Друзья! Такой вопрос. В даташите указаны задержки, например, для очистки дисплея 1.52 мс. при тактовой частоте 270 кГц. Не могу уловить, где именно мы задаем тактовую частоту. Получается, что при инициализации мы в ручную дергаем стробирующую ногу МК (е1 и е0). И что самое интересное, мы записываем команду «очистки дисплея» опускаем в нуль стробирующую ногу и ждем положенное время. При этом тактового сигнала нигде нет.
    Такой дотошный вопрос, поскольку после процедуры инициализации индикатор никак не хочет оживать.

    • Валентин:

      Команды взяты из документации от МЭЛТ MT16S2D. Инициализировался только так.

      HAL_Delay(40);
      rs0;
      LCD_WriteData(30);
      e1;
      delay();
      e0;
      HAL_Delay(40);
      LCD_WriteData(30);
      e1;
      delay();
      e0;
      HAL_Delay(40);
      LCD_WriteData(30);
      e1;
      delay();
      e0;
      HAL_Delay(40);
      LCD_WriteData(0x02); // команда режим 4 бит
      e1;
      delay();
      e0;
      HAL_Delay(40);
      LCD_command(0x28); // команда режим 4 бит,
      HAL_Delay(1);
      LCD_command(0x08); // команда выключить дисплей
      HAL_Delay(1);
      LCD_command(0x01); // команда очистить дисплей
      HAL_Delay(2);
      LCD_command(0x0F); // команда включить дисплей, включить курсор
      HAL_Delay(1);

  16. Руслан:

    Здравствуйте. Если дисплей изначально в 8-битном режиме, то вместо трижды LCD_WriteData(3);
    надо слать трижды
    LCD_WriteData(0x30);
    же?
    Спасибо за уроки!

  17. KIRILL:

    Доброго дня. Исправьте схему в текстовом уроке. У вас резистор подсветки подключен одним концом не к питанию, а к шине RS он же PB8….

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*