Top.Mail.Ru

STM32 и дисплей на базе HD44780 в 4-битном режиме.

Итак, сегодня мы будем работать с дисплеем на базе популярного контроллера HD44780. Уже была статья про это на нашем сайте (вот она), там мы и команды обсудили, и с подключением разобрались, и пример написали и протестировали. Казалось бы что тут еще обсуждать? На самом деле есть что )

В комментариях к той статье попросили разобрать пример с использованием 4-х битной шины данных (как вы помните есть два варианта общения с дисплеем, а именно с использованием 8-ми битной шины, либо 4-х битной), так что сегодняшняя статья посвящена именно этому.

Теорию обсуждать я думаю не будем снова, все есть в уже упомянутой статье, так что сразу перейдем к особенностям работы в 4-х битном режиме. Хотя никаких особенностей-то и нет по большому счету. Если в 8-ми битном режиме мы передаем всю команду целиком, используя выводы DB7-DB0, то в 4-х битном команда делится на две части и передается она соответственно по частям (в этом режиме задействуем только 4 вывода дисплея - DB7-DB4).

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

Работа с дисплеем HD44780.

Как видите, здесь как раз используется 4-х битная шина данных. То что надо!

Давайте теперь попробуем написать программу, которая что-нибудь выведет на дисплей. Я буду использовать микроконтроллер STM32F407, ну и, соответственно, плату STM32F4 Discovery. Итак, создаем как обычно новый проект, добавляем в него файлы библиотек CMSIS и SPL:

Создание нового проекта в Keil.

Дисплей у меня подключен следующим образом:

  • RS – PC2
  • R/W – PB10
  • E – PB14
  • DB7 – PD2
  • DB6 – PC12
  • DB5 – PA8
  • DB4 – PA10

Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также небольшая подборка на смежную тему из нового курса:

Определим все эти выводы следующим образом, чтобы сделать нашу программу более универсальной:

// Set RS port
#define MT_WH1602_RS_PORT                                        (GPIOC)

// Set RS pin
#define MT_WH1602_RS_PIN                                         (GPIO_Pin_2)

// Set RW port
#define MT_WH1602_RW_PORT                                        (GPIOB)

// Set RW pin
#define MT_WH1602_RW_PIN                                         (GPIO_Pin_10)

// Set E port
#define MT_WH1602_E_PORT                                         (GPIOB)

// Set E pin
#define MT_WH1602_E_PIN                                          (GPIO_Pin_14)

// Set DB7 port
#define MT_WH1602_DB7_PORT                                       (GPIOD)

// Set DB7 pin
#define MT_WH1602_DB7_PIN                                        (GPIO_Pin_2)

// Set DB6 port
#define MT_WH1602_DB6_PORT                                       (GPIOC)

// Set DB6 pin
#define MT_WH1602_DB6_PIN                                        (GPIO_Pin_12)

// Set DB5 port
#define MT_WH1602_DB5_PORT                                       (GPIOA)

// Set DB5 pin
#define MT_WH1602_DB5_PIN                                        (GPIO_Pin_8)

// Set DB4 port
#define MT_WH1602_DB4_PORT                                       (GPIOA)

// Set DB4 pin
#define MT_WH1602_DB4_PIN                                        (GPIO_Pin_10)

Также не забываем определить:

// Bit masks for different bits in byte
#define BIT_7_MASK                                               (0x80)
#define BIT_6_MASK                                               (0x40)
#define BIT_5_MASK                                               (0x20)
#define BIT_4_MASK                                               (0x10)
#define BIT_3_MASK                                               (0x08)
#define BIT_2_MASK                                               (0x04)
#define BIT_1_MASK                                               (0x02)
#define BIT_0_MASK                                               (0x01)

Теперь необходимо проинициализировать все ножки микроконтроллера, которые нам понадобятся:

/***************************************************************************************/
GPIO_InitTypeDef MT_GPIOcfg;


/***************************************************************************************/
void MT_Init()
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

	// Initialize all pins connected to the WH1602 module
	
	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_RS_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_RS_PORT, &MT_GPIOcfg);

	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_RW_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_RW_PORT, &MT_GPIOcfg);

	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_E_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_E_PORT, &MT_GPIOcfg);

	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB7_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_DB7_PORT, &MT_GPIOcfg);

	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB6_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_DB6_PORT, &MT_GPIOcfg);

	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB5_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_DB5_PORT, &MT_GPIOcfg);

	GPIO_StructInit(&MT_GPIOcfg);
	MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB4_PIN;
	MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
	MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(MT_WH1602_DB4_PORT, &MT_GPIOcfg);
} 


/***************************************************************************************/

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

/***************************************************************************************/
// Функция для реализации простой задержки
void MT_Delay(uint32_t us)
{
	volatile uint32_t i;
	RCC_ClocksTypeDef rcc;

	RCC_GetClocksFreq (&rcc);
	i = (rcc.HCLK_Frequency / 10000000) * us;

	for (; i != 0; i--);
}


/***************************************************************************************/
// Строб импульс
void MT_DataReadWrite()
{
	GPIO_SetBits(MT_WH1602_E_PORT, MT_WH1602_E_PIN);
	MT_Delay(2);
	GPIO_ResetBits(MT_WH1602_E_PORT, MT_WH1602_E_PIN);
}


/***************************************************************************************/
// И наконец функции для инициализации дисплея
void MT_FunctionSet8bit()
{
	GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
	GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);
	GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
}


/***************************************************************************************/
void MT_FunctionSet4bit(bool N, bool F)
{
	GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
	GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);
	GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
	MT_Delay(100);

	if (N == 1)
	{
		GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	}

	if (F == 1)
	{
		GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	}
	
	GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
}


/***************************************************************************************/
void MT_DisplayOnOff()
{
	GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
	GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

	GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
	MT_Delay(100); 

	GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
}


/***************************************************************************************/
void MT_DisplayClear()
{
	GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
	GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

	GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
	MT_Delay(100);

	GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

	MT_DataReadWrite();
}


/***************************************************************************************/

Кроме всего этого нам понадобится функция для записи данных в память дисплея для вывода их на экран:

/***************************************************************************************/
void MT_WriteData(uint8_t data)
{ 
	GPIO_SetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
	GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

	if (data & BIT_7_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	}

	if (data & BIT_6_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	}

	if (data & BIT_5_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	}

	if (data & BIT_4_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
	}

	MT_Delay(100);
	MT_DataReadWrite();

	if (data & BIT_3_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
	}

	if (data & BIT_2_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
	}

	if (data & BIT_1_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
	}

	if (data & BIT_0_MASK)
	{
		GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
	}
	else
	{
		GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
	}

	MT_Delay(100);
	MT_DataReadWrite();
}


/***************************************************************************************/

Итак, все функции которые нам понадобятся готовы! О том, как подаются команды на дисплей мы уже говорили в предыдущей статье про этот дисплей, обязательно посмотрите, если этого еще не сделали, а мы тем временем подошли к главному - к реализации функции main():

/***************************************************************************************/
int main(void)
{
	MT_Init();
	MT_Delay(1000);

	MT_FunctionSet8bit();
	MT_Delay(1000);

	MT_FunctionSet4bit(1, 1);
	MT_Delay(1000);

	MT_FunctionSet4bit(1, 1);
	MT_Delay(1000);

	MT_DisplayOnOff();
	MT_Delay(1000);

	MT_DisplayClear();
	MT_Delay(10000);

	MT_WriteData(0x34);
	MT_Delay(1000);
	MT_WriteData(0x20);
	MT_Delay(1000);
	MT_WriteData(0x62);
	MT_Delay(1000);
	MT_WriteData(0x69);
	MT_Delay(1000);
	MT_WriteData(0x74);
	MT_Delay(1000);
	MT_WriteData(0x20);
	MT_Delay(1000);
	MT_WriteData(0x6D);
	MT_Delay(1000);
	MT_WriteData(0x6F);
	MT_Delay(1000);
	MT_WriteData(0x64);
	MT_Delay(1000);
	MT_WriteData(0x65);
	MT_Delay(1000);	

	while(1)
	{
	}
}


/***************************************************************************************/

Компилируем, прошиваем, запускаем, и вот он результат:

Подключение HD44780 к STM32.

Как видим, все работает 👍 Поэтому на этом заканчиваем обсуждение 4-х битного режима передачи данных, до скорых встреч и новых статей!

Подписаться
Уведомить о
guest

36 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
German
German
10 лет назад

огромное спасибо за пример,очень кстати.

Виталий
Виталий
10 лет назад

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

Виталий
Виталий
Ответ на комментарий  Aveal
10 лет назад

АЦП измеряет напряжение, эту информацию необходимо выводить на 3-х разрядный семисегментный светодиодный индикатор. Динамическая индикация на AVR у меня работала без проблем, а вот когда решил перейти на STM начались чудеса. Сейчас просто пытаюсь вывести любое фиксированное число не прибегая пока к АЦП, но и это не получается. В перспективе АЦП будет измерять 4-5 параметров, какие-то выводить на индикатор, а по каким-то формировать определённый код на своих ножках. Вот на этом форуме (http://forum.cxem.net/index.php?showtopic=126568) я задавал вопрос, но полезного ответа так и не получил.

Germa
Germa
10 лет назад

Есть вопрос по схеме, выводы дисплея подключаются напрямую к контроллеру,дисплей запитывать от 3.3 или от 5 В от платы?

German
German
10 лет назад

Можете назвать модель используемого дисплея?

bootor
bootor
9 лет назад

Добрый день!
Не могли бы Вы рассказать, как использовать вот такую штуку http://www.ebay.com/itm/New-IIC-I2C-TWI-SPI-Serial-Interface-Board-Module-Port-For-2004-1602-LCD-Display-/261176654807?pt=LH_DefaultDomain_0&hash=item3ccf577bd7 для работы с экраном?

Vasily
9 лет назад

Error[Pe020]: identifier "BIT_4_MASK" is undefined C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.5\arm\examples\ST\STM32F2xx\IAR-STM32F207ZG-SK\LCD\Firmware\src\main.c 243
В IAR не компилируется. Подскажите пожалуйста куда копать?

Vasya
Vasya
9 лет назад

При переключении на следующий разряд, нужно его принудительно гасить, выставляя 0.

Vasya
Vasya
9 лет назад

Автор, спасибо большое за статью.
но мой индикатор работал не стабильно. После долгих ковыряний выснилось, что дело в неправильном формировании задержки.
Эту строку пришлось сделать так.

i = (rcc.HCLK_Frequency / 8000000) * us;

Alex
Alex
9 лет назад

Добрый день
По вашей программе у меня на STM32F205 индикатор 1602А запускался каждый 2-й раз но после удаления строк :
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
в конце функции void MT_FunctionSet4bit(bool N, bool F)
и изменении
MT_FunctionSet4bit(1, 1);
MT_Delay(1000);

MT_FunctionSet4bit(1, 1);
MT_Delay(1000);
на
MT_FunctionSet4bit(0, 0);
MT_Delay(1000);

MT_FunctionSet4bit(0, 0);
MT_Delay(1000);
все стало ОК

Антон Бауер
Антон Бауер
9 лет назад

Здравствуйте, подскажите что поправить в библиотеке чтобы пример заработал с F3Discovery?

Sergey
Sergey
9 лет назад

Добрый день! Помогите разобраться пробую подключить дисплей WH1602 к stm32f100RB порты перенастроил, но компилятор ругается на строку void MT_FunctionSet4bit(bool N, bool F)
точнее main.c:133:31: error: expected ')' before 'N' подскажите что нужно подправить? В си только начинаю разбираться.

и еще заменил строку
MT_GPIOCfg.GPIO_Mode = GPIO_Mode_Out;
на
MT_GPIOCfg.GPIO_Mode = GPIO_Mode_Out_PP;
потому что компилятор ругался на неправильный параметр GPIO_Mode_Out, порт надо настраивать в Push-Pull или Open Drain?

Sergey
Sergey
9 лет назад

забыл написать что оболочка CoIDE компилятор arm-none-eabi-gcc

Sergey
Sergey
9 лет назад

на что нужно изменить bool ?

Sergey
Sergey
9 лет назад

Спасибо за помощь))

Ilja
Ilja
9 лет назад

Кто подскажет: планирую этот пример использовать как библиотеку для работы с HD44780? И как лучше реализовать: вставкой перед main или как отдельный файл, прикрепив в проекте и просто вызывая функцию вывода на экран?

Дмитрий
Дмитрий
6 лет назад

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

Дмитрий
Дмитрий
Ответ на комментарий  Aveal
6 лет назад

Подключал через потенциометр вращаю ручку контрастность меняется.Но информации нет.ВОт код программы.
#include
#include

#include

GPIO_InitTypeDef MT_GPIOcfg;

void MT_Init()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

// Initialize all pins connected to the WH1602 module

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_RS_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_RS_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_RW_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_RW_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_E_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_E_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB7_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB7_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB6_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB6_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB5_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB5_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB4_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB4_PORT, &MT_GPIOcfg);
}
void MT_Delay(uint32_t us)
{
volatile uint32_t i;
RCC_ClocksTypeDef rcc;

RCC_GetClocksFreq (&rcc);
i = (rcc.HCLK_Frequency/10000000)*us;

for (; i != 0; i--);
}

// ????? ???????
void MT_DataReadWrite()
{
GPIO_SetBits(MT_WH1602_E_PORT, MT_WH1602_E_PIN);
MT_Delay(2);
GPIO_ResetBits(MT_WH1602_E_PORT, MT_WH1602_E_PIN);
}

// ? ??????? ??????? ??? ????????????? ???????
void MT_FunctionSet8bit()
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}

void MT_FunctionSet4bit(bool N, bool F)
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
MT_Delay(100);

if (N == 1)
{
GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}

if (F == 1)
{
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}

void MT_DisplayOnOff()
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
MT_Delay(100);

GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}

void MT_DisplayClear()
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
MT_Delay(100);

GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}
void MT_WriteData(uint8_t data)
{
GPIO_SetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

if (data & BIT_7_MASK)
{
GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}

if (data & BIT_6_MASK)
{
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}

if (data & BIT_5_MASK)
{
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}

if (data & BIT_4_MASK)
{
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}

MT_Delay(100);
MT_DataReadWrite();

if (data & BIT_3_MASK)
{
GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}

if (data & BIT_2_MASK)
{
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}

if (data & BIT_1_MASK)
{
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}

if (data & BIT_0_MASK)
{
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}

MT_Delay(100);
MT_DataReadWrite();
}
int main(void)
{

MT_Init();
MT_Delay(1000);

MT_FunctionSet8bit();
MT_Delay(1000);

MT_FunctionSet4bit(1, 1);
MT_Delay(1000);

MT_FunctionSet4bit(1, 1);
MT_Delay(1000);

MT_DisplayOnOff();
MT_Delay(1000);

MT_DisplayClear();
MT_Delay(10000);

MT_WriteData(0x34);
MT_Delay(1000);
MT_WriteData(0x20);
MT_Delay(1000);
MT_WriteData(0x62);
MT_Delay(1000);
MT_WriteData(0x69);
MT_Delay(1000);
MT_WriteData(0x74);
MT_Delay(1000);
MT_WriteData(0x20);
MT_Delay(1000);
MT_WriteData(0x6D);
MT_Delay(1000);
MT_WriteData(0x6F);
MT_Delay(1000);
MT_WriteData(0x64);
MT_Delay(1000);
MT_WriteData(0x65);
MT_Delay(1000);

while(1)
{
__NOP();
}
}

Дмитрий
Дмитрий
6 лет назад

Подключал через потенциометр вращаю ручку контрастность меняется.Но информации нет.ВОт код программы.
#include
#include

#include

GPIO_InitTypeDef MT_GPIOcfg;

void MT_Init()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

// Initialize all pins connected to the WH1602 module

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_RS_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_RS_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_RW_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_RW_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_E_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_E_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB7_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB7_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB6_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB6_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB5_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB5_PORT, &MT_GPIOcfg);

GPIO_StructInit(&MT_GPIOcfg);
MT_GPIOcfg.GPIO_Pin = MT_WH1602_DB4_PIN;
MT_GPIOcfg.GPIO_Mode = GPIO_Mode_OUT;
MT_GPIOcfg.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MT_WH1602_DB4_PORT, &MT_GPIOcfg);
}
void MT_Delay(uint32_t us)
{
volatile uint32_t i;
RCC_ClocksTypeDef rcc;

RCC_GetClocksFreq (&rcc);
i = (rcc.HCLK_Frequency/10000000)*us;

for (; i != 0; i—);
}

// ????? ???????
void MT_DataReadWrite()
{
GPIO_SetBits(MT_WH1602_E_PORT, MT_WH1602_E_PIN);
MT_Delay(2);
GPIO_ResetBits(MT_WH1602_E_PORT, MT_WH1602_E_PIN);
}

// ? ??????? ??????? ??? ????????????? ???????
void MT_FunctionSet8bit()
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}

void MT_FunctionSet4bit(bool N, bool F)
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
MT_Delay(100);

if (N == 1)
{
GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}

if (F == 1)
{
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}

void MT_DisplayOnOff()
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
MT_Delay(100);

GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}

void MT_DisplayClear()
{
GPIO_ResetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
MT_Delay(100);

GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);

MT_DataReadWrite();
}
void MT_WriteData(uint8_t data)
{
GPIO_SetBits(MT_WH1602_RS_PORT, MT_WH1602_RS_PIN);
GPIO_ResetBits(MT_WH1602_RW_PORT, MT_WH1602_RW_PIN);

if (data & BIT_7_MASK)
{
GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}

if (data & BIT_6_MASK)
{
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}

if (data & BIT_5_MASK)
{
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}

if (data & BIT_4_MASK)
{
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}

MT_Delay(100);
MT_DataReadWrite();

if (data & BIT_3_MASK)
{
GPIO_SetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB7_PORT, MT_WH1602_DB7_PIN);
}

if (data & BIT_2_MASK)
{
GPIO_SetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB6_PORT, MT_WH1602_DB6_PIN);
}

if (data & BIT_1_MASK)
{
GPIO_SetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB5_PORT, MT_WH1602_DB5_PIN);
}

if (data & BIT_0_MASK)
{
GPIO_SetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}
else
{
GPIO_ResetBits(MT_WH1602_DB4_PORT, MT_WH1602_DB4_PIN);
}

MT_Delay(100);
MT_DataReadWrite();
}
int main(void)
{

MT_Init();
MT_Delay(1000);

MT_FunctionSet8bit();
MT_Delay(1000);

MT_FunctionSet4bit(1, 1);
MT_Delay(1000);

MT_FunctionSet4bit(1, 1);
MT_Delay(1000);

MT_DisplayOnOff();
MT_Delay(1000);

MT_DisplayClear();
MT_Delay(10000);

MT_WriteData(0x34);
MT_Delay(1000);
MT_WriteData(0x20);
MT_Delay(1000);
MT_WriteData(0x62);
MT_Delay(1000);
MT_WriteData(0x69);
MT_Delay(1000);
MT_WriteData(0x74);
MT_Delay(1000);
MT_WriteData(0x20);
MT_Delay(1000);
MT_WriteData(0x6D);
MT_Delay(1000);
MT_WriteData(0x6F);
MT_Delay(1000);
MT_WriteData(0x64);
MT_Delay(1000);
MT_WriteData(0x65);
MT_Delay(1000);

while(1)
{
__NOP();
}
}

Дмитрий
Дмитрий
6 лет назад

Да, дисплей WH1602A

Vladislav
5 лет назад

Вот моя современная библиотека для этих древних LCD.
Адаптированная для использования с STM32 CubeMX.
https://www.dropbox.com/s/uhcbwx8dvdgemx2/LCD_CubeMX.rar?dl=0
Поддерживаются ВСЕ известные алфавитно-цифровые LCD-дисплеи на базе контроллеров HD44780 (SPLC780 и др.):
- 8x1
- 8x2
- 12x2
- 16x1 (обе разновидности)
- 16x2
- 16x4
- 20x2
- 20x4
- 24x2
- 40x2
- 40x4

Если линк недоступен здесь, то просто направьте запрос на 67vladk@gmail.com.

Владислав

vladk
vladk
Ответ на комментарий  Vladislav
5 лет назад

Сегодня протестировал на 40х04 - все работает.

36
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x