Главная » Микроконтроллеры
Призовой фонд
на ноябрь 2017 г.
1. Термометр Relsib WT51
Рэлсиб
2. 1000 руб
PCBWay
3. Тестер компонентов LCR-T4
Паяльник
4. 200 руб.
От пользователей

Похожие статьи:


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); //Курсор мигает

Прикрепленные файлы:

Теги:

Опубликована: 0 0
Я собрал 0 2
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 5 Проголосовало: 2 чел.

Комментарии (45) | Я собрал (0) | Подписаться

0
Иван #
Как вывести на дисплей значение переменной?
Ответить
+1

[Автор]
Rough #
Если переменная строка, например:
char *t="Какой-то текст";
то пршете просто:
PrintStr(t);
Если же хотите вывести числовую переменную, то подключаете библиотеку stdio.h и конвертируете число в строку:
int i=123;
char *t;
snprintf(t, 255, "%d", i);
PrintStr(t);
Отредактирован 13.02.2014 11:51
Ответить
0
Дмитрий #
Зависает на этой snprintf()
Ответить
0
Дмитрий #
Зависает, потому, что никто не делает запись в неинициализированный указатель.
char io_buff[255];
int i = 123;
sprintf(io_buff, "%d", i);
PrintStr(io_buff);
Ответить
0
Jeka #
Какая продолжительность delay(1)?
Ответить
0

[Автор]
Rough #
Примерно микросекунда
Ответить
0
Antares #
Для экономии ног можно прикрутить 74HC595 и рулить дисплеем через аппаратный SPI. Это так, идея для развития статьи
Ответить
0

[Автор]
Rough #
Да, можно и так, но сейчас вы используете 6 ног, а с HC - 4 ноги. Имхо, не слишком большая экономия. А так вообще есть дисплеи, управляемые по SPI изначально.
Ответить
+2
Александр #
Удобная библиотечка, буду теперь ее использовать, а то моя сделанная для пробы гораздо хуже выглядит. Только на мой взгляд неудобно, что вид курсора меняем отправкой байта конфигурации, у меня было сделано это библиотечной функцией.
Ответить
+1

[Автор]
Rough #
Строки про курсор скорее были как пример использования SendByte. Никто не мешает вам добавить в библиотеку функцию типа:
void CursorBlink(int blinkType)
{
if(blinkType==0) SendByte(0b00001111, 0); //Курсор мигает
else if(blinkType==1) SendByte(0b00001110, 0); //Курсор не мигает
else if(blinkType==2)SendByte(0b00001100, 0); //Курсор выключен
}

и менять вид курсора командой типа CursorBlink(1);
Ответить
0
Artos5 #
И то верно! Автор, респект вам!
Ответить
0
ШСА #
Ваши статьи помогают кое что понять в STM32. Однако, когда начинаешь разбираться в библиотеке CooCox, натыкаешься на совершенно непонятные конструкции типа Pragma и т.п.
Вопрос: Подскажите, где можно ознакомиться с подробным описанием версии языка CooCox?
Буду очень признателен за любую помощь.
Ответить
0
Dm3Ch #
У меня STM32F4-DISCOVERY и экран на чипе клоне HD44780. Подключил, как у вас на схеме, код запускаю ваш. Количество символов то, а текст не тот. Подскажите, пожалуйста, что делать?
Ответить
0

[Автор]
Rough #
Что вы имеете ввиду под не тем текстом? Кракозябры? Или просто буквы другие?
Ответить
0
Роман #
Сделал по схеме, дисплей wh1602b, прозвонил и проверил всё несколько раз, прошиваю контроллер, но на дисплее крякозярбры, а текста нет, не подскажете в чем проблема?
Ответить
0

[Автор]
Rough #
Текст на русском писали или английском?
Ответить
0
Artos5 #
Помогите пожалуйста разобраться... не стартует дисплей. Нету инициализации. Подключение все тщательно проверил.
Инициализирую так:
void InitializeLCD(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIOB->CRH |= 0x33333333; // конфигурируем на выход частота 50мгЦ
GPIOB->CRL |= 0x33333333; // конфигурируем на выход частота 50мгЦ

//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);
}
Вроде правильно. Проц: STM32F100R8T6. Подозреваю что в задержках бок...
Ответить
0
Artos5 #
Вот такие пины:
//---Переопределяем порты для подключения дисплея, для удобства---//
#define LCM_OUT GPIOB->ODR
#define LCM_PIN_RS GPIO_Pin_3
#define LCM_PIN_EN GPIO_Pin_4
#define LCM_PIN_D7 GPIO_Pin_5
#define LCM_PIN_D6 GPIO_Pin_6
#define LCM_PIN_D5 GPIO_Pin_7
#define LCM_PIN_D4 GPIO_Pin_9
#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;
Ответить
0
Artos5 #
Понял что библиотека жестко привязана к номерам пинов.
Переделал так:
//---Переопределяем порты для подключения дисплея, для удобства---//
#define LCM_OUT GPIOA->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 InitializeLCD(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIOA->CRH |= 0x33333333; // конфигурируем на выход частота 50мгЦ
GPIOA->CRL |= 0x33333333; // конфигурируем на выход частота 50мгЦ

//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);
}
Результат аналогичный...
Ответить
0
denblack #
Попробуйте поменять значенте 60 в библиотеке //---Функция задержки---// на 600.
Ответить
0
Artos5 #
Посмотрел все три примера с разных сайтов включая этот, ни один из них НЕ ИМЕЕТ ПРАВИЛЬНОЙ инициализации ЖКИ! Долбался целый день пока удалось корректно заставить работать! Теперь у меня появилась (в основу заложил примеры из двух статей) отличная библиотека , при помощи которой я могу настроить любую ножку и ЛЮБОЙ ПОРТ мк на работу дисплея! Хоть даже так:

GPIOB->pin_1 = RS
GPIOC->pin_3 = bit4
GPIOA->pin_4 = E
............
............
и т.д. :)

Во всех этих примерах есть ограничения с настройкой порта. А в этом примере даже нельзя к другой ножке одного и того же порта подключить .
Ответить
0
Sherpa #
Пришлите пожалуйста свою библиотеку, если можно. Тоже проблемы с изменением ног! Исходник работает, меняю ноги - нет!
Ответить
0
Дмитрий #
У меня на камушке STM32F100RB с задержкой 5000 только заработало.
Ответить
0
ZERRO_ #
У меня дисплей wh1202a, подключил на другие ножки, в библиотеке поменял, но ничего не работает на дисплее "светятся" все ячейки.
Отредактирован 09.07.2014 21:11
Ответить
0
count_raven #
У меня кракозябры отображаются
Ответить
0

[Автор]
Rough #
1) Если пишете русские буквы, то попробуйте английские;
2) Проверьте правильность подключения, отсутствие КЗ и разрывов;
3) Сравните инициализацию Вашего дисплея по даташиту с используемым в статье.
Ответить
0
Pioneer271 #
Спасибо автору. Очень понравилась статья. Но при загрузке прошивки буквы и цифры не совпадают и не отражается вторая строчка. Дисплей SCM1602A
Ответить
0
Алексей Николаевич #
Возможно дополнение к вышесказанному, у кого шрифт отображается криво. У меня индикатор 1202. Инициализируется (то есть подключение правильное), а адресация букв - свап (те. вместо 0x63 выходит буква с адресом 0х36 и тд.)
Ответить
0
Serega #
У меня WH2004L, кокс Version: 1.7.7 и если я наберу на русском даже букву "А" - то отобразится бредятина, хотя для этого индикатора для любой раскладки буква "А" под одним и тем же кодом. Если через сендбайт посылать номер символа - то выводятся все и русские и дополнительные. Компилятор gcc-arm-none-eabi-4_6-2012q4-20121016. Вобщем в чем проблема - я не понял. Может кто решил?
Ответить
0
Serega #
Есть несколько вопросов:
1) Прога для дисплея WH2004 подойдет или только для 1602?
2) Есть ли возможность загружать свои символы?
Ответить
0
Serega #
Спасибо автору за статью, запустился с первого раза. Немного пришлось покрутить, потому как у меня дисплей 2004. Ниже приведу код выбора строки, может кому поможет, по идее должен работать и для двухстрочных индикаторов:
//---Установка позиции курсора---//
void Cursor(char Row, char Col)
{
char address;

switch ( Row )
{
case 0: address = 0x00; break;
case 1: address = 0x40; break;
case 2: address = 0x14; break;
case 3: address = 0x54; break;
}

address += Col;
SendByte(0x80 | address, 0);
}
Ответить
0
Macrobot #
Кто собирал проект в keil пожалуйста выложите проект
Ответить
0
STiX #
Присоеденяюсь к просьбе!
Не могу собрать, - startup\startup_stm32f4xx.c(289): error: #29: expected an expression
Keil V4.74.0.22
Ответить
0
GOR23 #
Хочу задать вопрос по согласованию уровней. У меня дисплей WH2004A питание по даташиту минимум 4,5В (стандартное 5). У контроллера 3,3 В.
Следовательно логические уровни совпадать не будут. Дисплей может сжечь порты МК (не защищённые от 5 В), а контроллер в свою очередь не сможет отправлять данные, так как лог единица от 0.7Vdd (согласно даташиту). Как быть, городить полевики на каждый выход МК?
Ответить
0
GOR23 #
Нашёл выход сам. Самый простой способ согласовать уровни, подтянуть пины к +5В, а выходы настроить на открытый сток. ДЕЛАТЬ ТАКОЕ МОЖНО ТОЛЬКО С 5V Tolerant ПИНАМИ.
Ответить
0
AlphaLaiman #
Стоит добавить, что на некоторых STM-ках (STM32F103 в частности) пин РВ4 по дефолту подключен к JTAG интерфейсу, и представленный код работать не будет.
Вот такие вот грабли
Ответить
0
Андрей #
Говорят, StdPeriph уже не поддерживается-вышел Cube, но генерирует много кода. Есть ли библиотека дисплея под CMSIS?
Ответить
0
Major #
При сбросе микропроцессора дисплей 1602 работает через раз, те при первом сбросе ничего не отображает, а при втором сбросе все работает нормально. При включении питания всегда работает нормально. Не могу разобраться в чем может быть проблема.
Ответить
0
Major #
Вопрос с сбросом через один решен для 1602. Все OK!
Ответить
0
WhoAmI #
Та же проблема. Как решили?
Ответить
0
Егор #
Не могу понять, что изменить в коде, чтобы он работал на однострочном дисплее с 16-ю символами? Контроллер тот же. Слово на дисплее, если оно длиннее 8 символов, отображается обрезанным. Благодарю.
Ответить
0
Sherpa #
Подскажите почему со сменой порта B на порт A у меня ничего не работает? Исходный вариант заработал сразу. Использую пины с 8 по 13 порта А!
Ответить
0
MegaEvil #
Для тех у кого кракозябры, смотрите строчку 93
LCM_OUT = 0x20;
и сверяйтесь со своими портами.
Ответить
0
Kamatsy #
Возникла проблема, сделал все как написано в уроке, текст на экран вывелся, но вот в первой строке текст обрезанный, в чем может быть проблема, использую дисплей WH1602a
Ответить
0
al-kor #
Уже несколько дней мучаюсь. Дисплей ACM1602s-FL. Не могу его никак завести чтобы работал. Делал по разным примерам, загораются две строки, а выводить ничего не хочет
и с задержкой игрался, а толку ноль
Прикрепленный файл: KAKA.c
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическое сопротивление?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

AVR-программатор USB ASP
AVR-программатор USB ASP
Pickit 2 - USB-программатор PIC-микроконтроллеров Конструктор - Гитарная педаль Remote Delay 2.5
вверх