STM32. Урок 5. Подключение LCD дисплея WH1602

В сегодняшнем уроке будет рассмотрена работа с символьным LCD дисплеем фирмы Winstar на контроллере HD44780. Следует сразу отметить, что аналогов данного дисплея великое множество и прошивка будет работать со всеми ними. Также была проверена работа данного кода с графическими и символьными OLED дисплеями.

Начнем, как и обычно, с постановки задачи. Необходимо подключить дисплей по 4х-битной шине к отладочной плате STM32F4 и вывести на него любой текст.

Итак, начнем с подключения. Существует два типа подключения подобных дисплеев: по 4х- и 8ми-битным шинам, при этом существенной разницы между ними нет, поэтому остановимся на первой, поскольку она требует меньшего количества проводников.

Схема подключения показана на рисунке ниже.

Схема подключения LCD к STM32

Следует отметить один очень важный момент: 1 вывод — «+5В» и 2 — «GND», на многих дисплеях поменяны местами, поэтому прежде чем подключить дисплей, прочитайте даташит. Неправильное подключение может привести к выходу дисплея из строя.

Собрать отладочную плату и дисплей в одно устройство можно разными способами. Можно просто распаять проводками, можно развести печатную плату-переходник, а можно собрать переходник на макетной плате, как показано на фото.

Теперь перейдем к прошивке. Выполним ее в виде отдельной библиотеки, чтобы в дальнейшем упростить подключение дисплея в других проектах — добавляете файл в проект и используете. Библиотеку назовем lcd.h. В библиотеке содержится следующий код:

 //---Переопределяем порты для подключения дисплея, для удобства---// #define     LCM_OUT               GPIOB->ODR #define     LCM_PIN_RS            GPIO_Pin_0          // PB0 #define     LCM_PIN_EN            GPIO_Pin_1          // PB1 #define     LCM_PIN_D7            GPIO_Pin_7          // PB7 #define     LCM_PIN_D6            GPIO_Pin_6          // PB6 #define     LCM_PIN_D5            GPIO_Pin_5          // PB5 #define     LCM_PIN_D4            GPIO_Pin_4          // PB4 #define     LCM_PIN_MASK  ((LCM_PIN_RS | LCM_PIN_EN | LCM_PIN_D7 | LCM_PIN_D6 | LCM_PIN_D5 | LCM_PIN_D4)) GPIO_InitTypeDef  GPIO_InitStructure;  //---Функция задержки---// void delay(int a) {     int i = 0;     int f = 0;     while(f < a)     {         while(i<60)         	{i++;}         f++;     } }  //---Нужная функция для работы с дисплеем, по сути "дергаем ножкой" EN---// void PulseLCD() {     LCM_OUT &= ~LCM_PIN_EN;     delay(220);     LCM_OUT |= LCM_PIN_EN;     delay(220);     LCM_OUT &= (~LCM_PIN_EN);     delay(220); }  //---Отсылка байта в дисплей---// void SendByte(char ByteToSend, int IsData) {     LCM_OUT &= (~LCM_PIN_MASK);     LCM_OUT |= (ByteToSend & 0xF0);      if (IsData == 1)         LCM_OUT |= LCM_PIN_RS;     else         LCM_OUT &= ~LCM_PIN_RS;     PulseLCD();     LCM_OUT &= (~LCM_PIN_MASK);     LCM_OUT |= ((ByteToSend & 0x0F) << 4);      if (IsData == 1)         LCM_OUT |= LCM_PIN_RS;     else         LCM_OUT &= ~LCM_PIN_RS;      PulseLCD(); }  //---Установка позиции курсора---// void Cursor(char Row, char Col) {    char address;    if (Row == 0)    address = 0;    else    address = 0x40;    address |= Col;    SendByte(0x80 | address, 0); }  //---Очистка дисплея---// void ClearLCDScreen() {     SendByte(0x01, 0);     SendByte(0x02, 0); }  //---Инициализация дисплея---// void InitializeLCD(void) {     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);     GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_4 | GPIO_Pin_5| GPIO_Pin_6| GPIO_Pin_7;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;     GPIO_Init(GPIOB, &GPIO_InitStructure);     LCM_OUT &= ~(LCM_PIN_MASK);     delay(32000);     delay(32000);     delay(32000);     LCM_OUT &= ~LCM_PIN_RS;     LCM_OUT &= ~LCM_PIN_EN;     LCM_OUT = 0x20;     PulseLCD();     SendByte(0x28, 0);     SendByte(0x0E, 0);     SendByte(0x06, 0); }  //---Печать строки---// void PrintStr(char *Text) {     char *c;     c = Text;     while ((c != 0) && (*c != 0))     {         SendByte(*c, 1);         c++;     } } 

Пройдемся по основным функциям библиотеки:

InitializeLCD( ) — инициализация дисплея, необходимо выполнять при старте программы.

 InitializeLCD(); //Инициализация дисплея

ClearLCDScreen( ) — очистка памяти дисплея.

 ClearLCDScreen(); //Очистка памяти дисплея

Cursor(№ строки, № столбца) — установка позиции курсора, отсчет начинается с нулевой строки и нулевого столбца.

 Cursor(0,2); //Установка курсора, 0-ая строка, 2-ой столбец

PrintStr(текст) — написание строки на дисплее.

 PrintStr("CXEM.NET");

SendByte(байт, режим) — если коротко, то эта функция отправляет байт в дисплей. Если параметр «режим» равен «1», то на дисплее появится символ, а если «0» — то байт будет принят дисплеем в режиме настройки. Например очистка дисплея, установка курсора или выбор типа курсора.

 SendByte(0b00001100, 0); //Курсор выключен

С библиотекой закончили. Теперь пора запускать дисплей. Для этого в основном файле main.c надо написать следующий код:

 #include "stm32f4xx.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" #include "lcd.h"  int main(void) {     InitializeLCD(); //Инициализация дисплея     ClearLCDScreen(); //Очистка дисплея от мусора     Cursor(0,2); //Установка курсора     PrintStr("Specially for"); //Написание текста     Cursor(1,4);     PrintStr("CXEM.NET");      while(1)     {      } }

Думаю по комментариям все понятно. Теперь остается скомпилировать код и прошить плату. Делаем рестарт и наслаждаемся написанным.

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

Для выключения курсора выполняем:

 SendByte(0b00001100, 0); //Курсор выключен

Для нижнего подчеркивания:

 SendByte(0b00001110, 0); //Курсор не мигает

Для мигающего:

 SendByte(0b00001111, 0); //Курсор мигает