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
11 лет назад

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

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

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

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

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

Germa
Germa
11 лет назад

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

German
German
11 лет назад

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

bootor
bootor
11 лет назад

Добрый день!
Не могли бы Вы рассказать, как использовать вот такую штуку 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
11 лет назад

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
10 лет назад

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

Vasya
Vasya
10 лет назад

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

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

Alex
Alex
10 лет назад

Добрый день
По вашей программе у меня на 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);
все стало ОК

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

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

Sergey
Sergey
10 лет назад

Добрый день! Помогите разобраться пробую подключить дисплей 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
10 лет назад

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

Sergey
Sergey
10 лет назад

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

Sergey
Sergey
10 лет назад

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

Ilja
Ilja
10 лет назад

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

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

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

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

Подключал через потенциометр вращаю ручку контрастность меняется.Но информации нет.ВОт код программы.
#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();
}
}

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

Подключал через потенциометр вращаю ручку контрастность меняется.Но информации нет.ВОт код программы.
#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();
}
}

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

Да, дисплей WH1602A

Vladislav
6 лет назад

Вот моя современная библиотека для этих древних 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
6 лет назад

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

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