STM Урок 22. HAL. I2C. I2C to LCD2004

 

 

 

Урок 22

HAL. I2C. Переходник для LCD 20×4

 

 

Сегодня мы попробуем подключить символьный дисплей LCD 20×4 подключить через переходник по шине I2C. Это позволит нам сэкономить ножки портов, а также обойтись меньшим количеством проводов.

Данный переходник выглядит вот так и его разъём полностью совместим по ножкам с разъёмом дисплея

 

image01

 

Это ничто иное, как преобразователь последовательного кода в параллельный на базе микросхемы PCF8574. Вот схема переходника (нажмите на картинку для увеличения изображения)

 

image02_500

 

По схеме мы видим на какие именно ножки разъёма дисплея у нас идут ножки микросхемы.

Проект создаём из MYLCD80, называем его I2CLCD80.

Запускаем Cube. Так как проект был создан в более ранней версии Cube, то в ответ на диалог с тремя кнопками жмём «Migrate», чтобы проект наш адаптировался к новой версии.

Включим I2C1. Ничего нигде больше не трогаем, запоминаем лапки SDA и SCL, генерируем проект, добавляем в него файл lcd.c, настраиваем программатор, собираем код.

Откроем файл lcd.h и исправим там всё в соответствии с требованиями шины I2C.

Убираем включение ножек портов совсем, т.к. они у нас не используются и этим займётся микросхема

 

#include "stm32f4xx_hal.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)

 

Прежде чем раньше менять, нам потребуется функция, которая будет посылать определённые данные в переходник. Для того, чтобы нам её добавить, откроем файл lcd.h и напишем туда функцию

 

//————————————————

void WriteByteI2CLCD(uint8_t bt)

{

        buf[0]=bt;

        HAL_I2C_Master_Transmit(&hi2c1,(uint16_t) 0x4E, buf,1,1000);

}

//————————————————

 

Вернёмся в lcd.h

Всё остальное переделываем вот так на основании вышеупомянутой схемы

 

#define e_set()   WriteByteI2CLCD(portlcd|=0x04) // установка линии E в 1

#define e_reset()   WriteByteI2CLCD(portlcd&=~0x04)  // установка линии E в 0

#define rs_set()    WriteByteI2CLCD(portlcd|=0x01) // установка линии RS в 1

#define rs_reset()   WriteByteI2CLCD(portlcd&=~0x01)  // установка линии RS в 0

#define setled()    WriteByteI2CLCD(portlcd|=0x08) // включение подсветки

#define setwrite()   WriteByteI2CLCD(portlcd&=~0x02)  // установка записи в память дисплея

 

Теперь подправим файл lcd.c

Напишем туда кое-какие дефайны

 

#include "lcd.h"

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

extern I2C_HandleTypeDef hi2c1;

uint8_t buf[1]={0};

char str1[100];

uint8_t portlcd = 0; //ячейка для хранения данных порта микросхемы расширения

 

Затем изменим функцию задержки, сделаем её в микросекундах

 

//————————————————

__STATIC_INLINE void DelayMicro(__IO uint32_t micros)

{

           micros *= (SystemCoreClock / 1000000) / 5;

   /* Wait till done */

   while (micros—);

}

//————————————————

 

 

Идём дальше по порядку.

Убираем функцию LCD_WriteData.

Убираем функции LCD_Command и LCD_Data, вместо них добавим другие функции

 

//————————————————

void sendhalfbyte(uint8_t c)

{

        c<<=4;

        e_set(); //включаем линию Е

        DelayMicro(50);

        WriteByteI2CLCD(portlcd|c);

        e_reset(); //выключаем линию Е

        DelayMicro(50);

}

//————————————————

void sendbyte(uint8_t c, uint8_t mode)

{

        if (mode==0) rs_reset();

        else         rs_set();

        uint8_t hc=0;

        hc=c>>4;

        sendhalfbyte(hc); sendhalfbyte(c);

}

//————————————————

 

Далее подправим эту функцию

 

void LCD_Clear(void)

{

        sendbyte(0x01, 0);

        DelayMicro(1500);

}

Эту тоже подправим

void LCD_SendChar(char ch)

{

        sendbyte(ch,1);

}

Данная функция подправится незначительно

void LCD_SetPos(uint8_t x, uint8_t y)

{

        switch(y)

        {

                case 0:

                        sendbyte(x|0x80,0);

                        HAL_Delay(1);

                        break;

                case 1:

                        sendbyte((0x40+x)|0x80,0);

                        HAL_Delay(1);

                        break;

                case 2:

                        sendbyte((0x14+x)|0x80,0);

                        HAL_Delay(1);

                        break;

                case 3:

                        sendbyte((0x54+x)|0x80,0);

                        HAL_Delay(1);

                        break;

        }

}

 

Теперь вот эту

 

void LCD_ini(void)

{

        HAL_Delay(15);

        sendhalfbyte(0x03);

        HAL_Delay(4);

        sendhalfbyte(0x03);

        DelayMicro(100);

        sendhalfbyte(0x03);

        HAL_Delay(1);

        sendhalfbyte(0x02);

        HAL_Delay(1);

        sendbyte(0x28, 0); //4бит-режим (DL=0) и 2 линии (N=1)

        HAL_Delay(1);

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

        HAL_Delay(1);

        sendbyte(0x6, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево

        HAL_Delay(1);

        setled();//подсветка

        setwrite();//запись

}

 

Вот эту незначительно

 

void LCD_String(char* st)

{

        uint8_t  i=0;

        while(st[i]!=0)

        {

                sendbyte(st[i],1);

                i++;

        }

}

 

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

 

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

 

Исходный код

 

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

 

Отладочную плату, переходник I2C to LCD и дисплей можно приобрести здесь:

STM32F4-DISCOVERY

Переходник I2C to LCD1602 2004

Дисплей LCD 20×4

 

 

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

 

STM32 HAL. I2C. I2C to LCD2004

 

14 комментариев на “STM Урок 22. HAL. I2C. I2C to LCD2004
  1. Михаил:

    Добрый день.

    Отличный урок, но надо было особо заострить внимание на то, что для библиотеки HAL адрес внешнего устройства на шине I2C должен быть сдвинут влево на 1 бит. Не у всех переходничек имеет адрес 2F.

    Специально просмотрел внимательно этот урок и первый урок по шине I2C: ни в одном об этом напрямую не говорится. Т.е., пока адрес совпадает с Вашим, все нормально. А мне пришлось покурить интернет, т.к. адрес у меня оказался 3F.

  2. Евгений:

    Чтобы линия E не отключалась одновременно с данными.
    void sendhalfbyte(uint8_t c)
    {
    c<<=4;
    e_set(); //включаем линию Е
    DelayMicro(50);
    WriteByteI2CLCD(portlcd|=c);
    e_reset(); //выключаем линию Е
    DelayMicro(50);
    WriteByteI2CLCD(portlcd&=15);
    }

  3. Виктор:

    Здравствуйте!
    Фирма Bolymin выпускает мультиинтерфейсные индикаторы BC1602AI и
    BC2004AI. Интерфейсы I2C, SPI, UART. Я привык работать с I2C.
    Индикаторы пятивольтовые, но выводы STM32 по I2C толерантны к
    напряжению 5 вольт. Сигналы завожу через резисторы 500 ом. Работает
    уверенно. Эти индикаторы я считаю более выгодным и простым решением
    чем обычные с переходником на I2C.

  4. streloc:

    А как сделать чтобы показывалась кириллица. Хочется написать по-русски.

  5. streloc:

    А, WinStar это дисплеи, а я думал это библиотека какая.

  6. Чурбанов Вадим Евгеньевич:

    Добрый вечер. Спасибо за уроки. Проблемка в следующем у меня корректно отрабатывают функции LCD_SetChar и LCDString если явно указываю аргумент функции. Но стоит только начать передавать данные в виде массива . sprintf(str, «Name»);
    LCDString(str);
    Выводит на экран крякозабры (как будто выводит не символ массива а символ с адресом в системе ascii)

  7. Andriy:

    Для вывода строки задействована функция sprintf()
    В связи с этим два вопроса:
    1. Не нашел подключения стандартных библиотек. Но код компилируется, и работает…
    2. Везде пишут, что sprintf отнимает много места во флеше.
    Опишите, пожалуйста, по-подробнее использование функции вывода

    • Куча отличных книг по нормальному ANSI C без плюсов пригодится.

      «Везде пишут, что sprintf отнимает много места во флеше» — шиза чья-то
      Все доп ф-ции Си и 4кб не дают. Для STM32 подобная экономия абсурдна.
      Передо мной проект с подключенной FreeRtos, Си либами мath,string,stdio,stdlib и почти полным HAL. И всего то =14кб на 2ой оптимизации.

      Возьми себе stm32H750 480МГЦ за 300р, 1МБ оперативки.128флэш, опреционники, инструментальники, 16 битные таймера, JPEG кодеки итп
      Подключи внешнюю flash, мб на 4 и не думай про «огрооомную» sprintf :))

      (отредактировано, убрана внешняя ссылка)

  8. unrealalex:

    Уважаемый Narod Stream, здравствуйте!
    Ваш урок очень полезен, для начального понимания, но хочу отметить следующие минусы:
    1. Передается максимум 1 байт на одну i2c сессию.
    чтобы передать 1 байт на дисплей, нужно стартануть новую сессию i2c, передать start, потом передать адрес дисплея, потом передать байт, потом stop.
    Таким образом, чтобы передать на дисплей 80 байт, нужно передать в действительности 2 байта в лучшем случае.
    2. программе приходится ждать обмена с дисплеем, а это очень не хорошо. когда же программе заниматься своими полезными функциями ?
    3. В библиотеке есть задержки в 50 микросекунд, оставшиеся видимо со времен библиотеки с подключением без переходника i2c. там они были нужны, здесь — однозначно нет. потому что посчитайте, сколько нужно микросекунд для передачи 8 бит в накопительный регистр, который в переходнике. Вы получите гораздо больше, чем 50 микросекунд.
    4. Чтобы программа не ждала вывода на дисплей, нужно просто сделать, чтобы DMA выводил на дисплей из области памяти. В эту область памяти программа просто пишет, как в память дисплея. да, там один символ будет занимать 4 байта, но зато ускорение составило 5 раз. если Вам интересно, могу прислать Вам тестовую прогу с моей либой.
    Спасибо за Ваши уроки, но выражу пожелание — докапывайтесь до самой сути, пожалуйста, оптимизируйте Ваши программы, прицчайте к оптимизации Ваших зрителей.
    Спасибо.

  9. Денис:

    Спасибо за урок. Подскажите что может быть. Наблюдаю проблему что экранчик что по 4битному подключению, что по I2C выводит инфу, но не всегда, причем часто выводит после касаний пальцами пинов. Похоже на наводки. Хотя везде уже навешал конденсаторов по питанию керамических, осцилограф показывает что все ОК. Не знаете в чем может быть проблемма?

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

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

*