STM Урок 7. HAL. LCD 20×4. 4-битный режим. Выводим информацию

 

 

 

 

Урок 7

HAL. LCD 20×4. 4-битный режим. Выводим информацию

 

 

Сегодня мы продолжим работать с дисплеем 20×4, с которым мы начали работать на прошлом занятии. Мы написали инициализацию и проверили работу кода на практике.

Теперь пытаемся что-то вывести на дисплей.

Для этого сначала пишем функцию для записи данных в дисплей, она немного будет отличаться от команд (только лишь лапкой rs)

 

void LCD_Data(uint8_t dt)

{

        rs1;

        LCD_WriteData(dt>>4);

        e1;

        delay();

        e0;

        LCD_WriteData(dt);

        e1;

        delay();

        e0;

}

 

Еще напишем функцию очистки дисплея

 

void LCD_Clear(void)

{

        LCD_SendCommand4(0x01);

        HAL_Delay(2);

}

 

Также, собственно, напишем функцию вывода символа на дисплей

 

void LCD_SendChar(char ch)

{

        LCD_Data((uint8_t) ch);

        delay();

}

 

Сделаем ее видимой, написав прототип в lcd.h.

И попытаемся наконец вывести какой то символ в главной функции программы

 

        LCD_ini();

        LCD_SendChar('s');

 

Прошьем и посмотрим

 

image10

 

Попробуем еще что то вывести на экран

 

        LCD_SendChar('s');

        LCD_SendChar('t');

        LCD_SendChar('m');

 

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

 

image11

 

Все работает, но, согласитесь, не совсем удобно писать программу, используя для каждого символа отдельную команду. Давайте поэтому напишем функцию для вывода целой строки

 

void LCD_String(char* st)

{

        uint8_t i=0;

        while(st[i]!=0)

        {

                LCD_Data(st[i]);

                delay();

                i++;

        }

}

 

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

Сначала объявим массив и проинициализируем

 

int main(void)

{

 

  /* USER CODE BEGIN 1 */

        char str[] = "Stm32F407VG";

  /* USER CODE END 1 */

 

Затем вызовем функцию, а посимвольный вывод пока закомментируем

        LCD_ini();

        LCD_String(str);

//        LCD_SendChar('s');

//        LCD_SendChar('t');

//        LCD_SendChar('m');

 

Соберём код, прошьём контроллер и посмотрим результат

 

image12

 

Вся наша строка на дисплее видна.

 

 

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

Для этого заглянем в даташит (открыв специализированный для LCD2004)

Мы видим там (на стр. 8), что строки имеют свои адреса в памяти DDRAM и все символы также:

1 строка – 0x00

2 строка – 0x40

3 строка – 0x14

4 строка – 0x54

А каждый символ будет смещением относительно начала строки.

Поняв это, пишем функцию позиционирования по столбцу и строке

 

void LCD_SetPos(uint8_t x, uint8_t y)

{

        switch(y)

        {

                case 0:

                        LCD_Command(x|0x80);

                        HAL_Delay(1);

                        break;

                case 1:

                        LCD_Command((0x40+x)|0x80);

                        HAL_Delay(1);

                        break;

                case 2:

                        LCD_Command((0x14+x)|0x80);

                        HAL_Delay(1);

                        break;

                case 3:

                        LCD_Command((0x54+x)|0x80);

                        HAL_Delay(1);

                        break;

        }

}

 

Не забываем про прототип.

Попробуем что-нибудь написать в другую позицию.

Изменим код в main.c следующим образом. Сначала объявим по другому (без инициализации) строковый массив

 

  /* USER CODE BEGIN 1 */

        char str[100];

  /* USER CODE END 1 */

 

Затем изменим код вывода

LCD_ini();

sprintf(str, "Stm32F407VG");

LCD_String(str);

LCD_SetPos(10, 2);

sprintf(str, "ARM mc");

LCD_String(str);

 

Также наш дисплей должен уметь полностью очищаться. Для этого пишем функцию очистки.

 

void LCD_Clear(void)

{

        LCD_Command(0x01);

        HAL_Delay(2);

}

 

Для нее также нужен будет прототип.

Попробуем после некоторой задержки очистить наш экран

 

sprintf(str, "ARM mc");

LCD_String(str);

HAL_Delay(2000);

LCD_Clear();

 

Прошьем и посмотрим. В видеоверсии, прикреплённой внизу урока, это будет нагляднее, поэтому здесь не показываю.

Добавим переменную в main() и напоследок немного поприкалываемся

 

  /* USER CODE BEGIN 1 */

        uint32_t i=0;

        char str[100];

  /* USER CODE END 1 */

 

Добавим код

 

  sprintf(str, "ARM mc");

        LCD_String(str);

        HAL_Delay(2000);

        LCD_Clear();

        LCD_SetPos(4,0);

        LCD_SendChar('s');

        LCD_SetPos(8,1);

        LCD_SendChar('t');

        LCD_SetPos(12,2);

        LCD_SendChar('m');

        LCD_SetPos(16,3);

        LCD_SendChar('3');

        LCD_SendChar('2');

        HAL_Delay(2000);

  /* USER CODE END 2 */

 

Также добавим код в бесконечный цикл

 

  /* USER CODE BEGIN WHILE */

  while (1)

  {

                LCD_SetPos(0,0);

                LCD_SendChar((char) ((i/100)%10) + 0x30);

                LCD_SendChar((char) ((i/10)%10) + 0x30);

                LCD_SendChar((char) (i%10) + 0x30);

                LCD_SetPos(16,1);

                LCD_SendChar((char) (((i+250)/100)%10) + 0x30);

                LCD_SendChar((char) (((i+250)/10)%10) + 0x30);

                LCD_SendChar((char) ((i+250)%10) + 0x30);

                LCD_SetPos(6,2);

                LCD_SendChar((char) (((i+500)/100)%10) + 0x30);

                LCD_SendChar((char) (((i+500)/10)%10) + 0x30);

                LCD_SendChar((char) ((i+500)%10) + 0x30);

                LCD_SetPos(9,3);

                LCD_SendChar((char) (((i+750)/100)%10) + 0x30);

                LCD_SendChar((char) (((i+750)/10)%10) + 0x30);

                LCD_SendChar((char) ((i+750)%10) + 0x30);

                HAL_Delay(100);

                i++;

  /* USER CODE END WHILE */

 

Ну и уж совсем на посошок уберем надоедливую черную мигалку (или курсор). Для этого меняем только одну букву в инициализации

 

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

        HAL_Delay(1);

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

        HAL_Delay(1);

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

        HAL_Delay(1);

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

        HAL_Delay(2);

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

        HAL_Delay(1);

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

 

Вот что у нас получилось (соответственно, в видеоверсии смотреть лучше)

 

image13

 

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

 

Исходный код

 

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

Дисплей LCD2004

Дисплей LCD1602

 

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

STM32F4-DISCOVERY

Дисплей LCD 20×4

 

 

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

 

STM32 HAL. LCD 20x4. 4-битный режим. Выводим информацию

20 комментариев на “STM Урок 7. HAL. LCD 20×4. 4-битный режим. Выводим информацию
  1. Lexa:

    Большое спасибо за урок! Мне, как начинающему, все понятно. Пошел "зашивать".

    • admin:

      Значит не зря стараюсь.

      • Lexa:

        Конечно не зря! Даже у меня получилось, хотя я и не программист, а электронщик и Ваш LCD — вторая программа после мигания светодиодами и очень нужна для серьезной работы, а времени и опыта что-то самому писать нет. Дальше буду осваивать ADC по вашим урокам. Заранее огромное спасибо!

  2. Lexa:

    С выводом 15 промахнулись, когда рисовали схему, и подключили к RS вместо VDD.  И 330 ом многовато. Лучше 10 ом.

  3. Роман:

    Уважаемый — Ваши уроки это супер! Спасибо большое за труд и старания!

    Хотелось бы спросить: 

    Строка: LCD_WriteData(dt>>4);

    В прошлом уроке ее небыло. Или я что-то не правильно понял?

     

    Спасибо заранее.

    • Спасибо за оценку!
      Да вроде должна быть, иначе как мы старшую тетраду передадим.

      • Роман:

        Добрый день. Спасибо за ответ. Я пока к практике не перешел (Сижу проводочки паяю ))))

        На сколько я понял мы вызываем эту процедуру:

        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();}

        }

         

        поидее строка: LCD_WriteData(dt>>4);  будет равно вот этому условию:         if((dt&0x01)==1) {d4_set();} else {d4_reset();}?   Если так — то почему не в таком виде:   if(((dt >> 4)&0x01)==1) {d4_set();} else {d4_reset();}? Я еще не силен в СИ, в основном BASIC и ASSEMBLER(совсем чуть чуть). Спасибо заранее.

         

        И еще хотелось бы спросить — а будет урок посвященный работе со встроенными RTC? Спасибо еще раз за громадную проделанную работу!!!!!!!!

        • Роман:

          Добрый день!!! РАЗОБРАЛСЯ )))))))))) Почитал еще основные математические действия ) и все понял ). Я изначально не так понял эти строки: 

          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();}

           

          Теперь стало все понятно )))) Еще раз спасибо за подробные уроки!

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

    Здравствуйте! Для начала хочю сказать спасибо за Вашы уроки! Очень подробно все описываете, такого больше нигде не встречал!

    Нужна Ваша помощь по одному вопросу.

    Заказал я как-то из Китая дисплей 1602. Он пришел, я подпаял разъем для подключения контактов, подал питание и засветилась первая строка, все вроде как должно быть. Только вот после инициализации вместо того, чтобы символы показывать светится две строки заполненные прямоугольниками. Единственное что их немного хуже видно чем одну строку до инициализации. Пробовал подключать и от 5В, и от 3,3В, брал и Mega16 и STM32F030C8T6, результат тот же — две строки с прямоугольниками. Пробовал и инициализировать по разному, смотрел код инициализации на разных сайтах, в разных даташитах, ничего не получается. Похоже что бракованный пришел.

    После этого заказал у другого продавца дисплей с подпаянным модулем I2C, подключил, все работает, инициализация проходит успешно.

    Так вопрос вот в чем: как считаете, это реально брак, или можно с ним еще что-то сделать?

    • Здравствуйте!

      Спасибо за оценку ресурса!

      Скорее всего, всё-таки брак. Глюки программной части проявляются немного не так.

      У меня был подобный дисплей, на котором я нечаянно перепутал полюса питания и он после этого вёл себя приблизительно так же. Только правда он половину своего экрана заполнял символами, а половину — закрашенными прямоугольниками. А вообще, чтобы точно вынести вердикт, что это не глюк прошивки, нужно подключить такой же, только заведомо годный, в смысле не по другому интерфейсу, а именно по параллельному.

  5. Алексей:

    Спасибо вам огромное за проделанный труд!Еще никто так подробно не разжевывал библиотеку НАL…хочется ещё каких нибудь уроков например по энкодеру,разным режимам ШИМ.Еще раз спасибо!

  6. Osekovs:

    Добрый день!

    Вопрос по коду

     

    void LCD_SendChar(char ch)

    {

            LCD_Data((uint8_t) ch);

            delay();

    }

    Неужели все так просто? Как будто экран синхронизирован с контроллером. Я смотрел спецификацию на этот экран и там написано что нужно отправить число типо LLHHLHHH чтобы вывести s. Мы же отправляем s напрямую как? Никаких lcd библиотек мы не подключали..

  7. dejin:

    Приветствую!

    Подключил lcd , написал на нем надписи . Всё по уроку. Дошел до указания позиции курсора и тут затык . Keil выдаёт такую ошибку при компиляции :

    ../Inc/lcd.h(26): error:  #20: identifier "uint8_t" is undefined
      void LCD_SetPos(uint8_t x, uint8_t y);

    Подскажите пожалуйста почему ему не нравится тип uint8_t 

  8. heaven:

    Здравствуйте!

    Спасибо большое за материалы.

    Хотел бы оставить свой ИМХО.

    void LCD_String(const char* st) — такая сигнатура должна позволить писать вызов как LCD_String("stm32").

  9. Андрей:

    А что это за "LCD_SendCommand4(0x01);" в void LCD_Clear(void) ?

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

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

*