Итак, сегодня мы будем работать с дисплеем на базе популярного контроллера HD44780. Уже была статья про это на нашем сайте (вот она), там мы и команды обсудили, и с подключением разобрались, и пример написали и протестировали. Казалось бы что тут еще обсуждать? На самом деле есть что )
В комментариях к той статье попросили разобрать пример с использованием 4-х битной шины данных (как вы помните есть два варианта общения с дисплеем, а именно с использованием 8-ми битной шины, либо 4-х битной), так что сегодняшняя статья посвящена именно этому.
Теорию обсуждать я думаю не будем снова, все есть в уже упомянутой статье, так что сразу перейдем к особенностям работы в 4-х битном режиме. Хотя никаких особенностей-то и нет по большому счету. Если в 8-ми битном режиме мы передаем всю команду целиком, используя выводы DB7-DB0, то в 4-х битном команда делится на две части и передается она соответственно по частям (в этом режиме задействуем только 4 вывода дисплея - DB7-DB4).
Довольно часто при работе с дисплеями проблема возникает в первую очередь с инициализацией, поэтому скачиваем документацию на используемый дисплей и ищем что-нибудь похожее на набор команд, которыми необходимо проинициализировать дисплей. Я, например, использую дисплей WH1602. Вот интересующая нас часть даташита на него:
Как видите, здесь как раз используется 4-х битная шина данных. То что надо!
Давайте теперь попробуем написать программу, которая что-нибудь выведет на дисплей. Я буду использовать микроконтроллер STM32F407, ну и, соответственно, плату STM32F4 Discovery. Итак, создаем как обычно новый проект, добавляем в него файлы библиотек CMSIS и SPL:
Дисплей у меня подключен следующим образом:
- RS – PC2
- R/W – PB10
- E – PB14
- DB7 – PD2
- DB6 – PC12
- DB5 – PA8
- DB4 – PA10
Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также небольшая подборка на смежную тему из нового курса:
- Подключение дисплея на базе ST7735 к микроконтроллеру STM32.
- Дисплей на базе ST7735 и STM32. Вывод изображения.
- Дисплей на базе контроллера SSD1306. Библиотека для STM32.
- 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) { } } /***************************************************************************************/
Компилируем, прошиваем, запускаем, и вот он результат:
Как видим, все работает 👍 Поэтому на этом заканчиваем обсуждение 4-х битного режима передачи данных, до скорых встреч и новых статей!
огромное спасибо за пример,очень кстати.
Спасибо большое за статью. А не могли бы вы написать статью про динамическую индикацию с таким же примером? Кажется всё просто, а как в железо зашил так и началось по мимо нужного разряда ещё соседний подсвечивается. Думал проблема в частоте или малой задержке, но поигравшись с ними я ничего странного не обнаружил и положительного эффекта не получил.
А какая конкретно задача стоит?
АЦП измеряет напряжение, эту информацию необходимо выводить на 3-х разрядный семисегментный светодиодный индикатор. Динамическая индикация на AVR у меня работала без проблем, а вот когда решил перейти на STM начались чудеса. Сейчас просто пытаюсь вывести любое фиксированное число не прибегая пока к АЦП, но и это не получается. В перспективе АЦП будет измерять 4-5 параметров, какие-то выводить на индикатор, а по каким-то формировать определённый код на своих ножках. Вот на этом форуме (http://forum.cxem.net/index.php?showtopic=126568) я задавал вопрос, но полезного ответа так и не получил.
Что-то не нашел у себя никакого сегментного индикатора..( Если получится куплю на недельке, попробую
Есть вопрос по схеме, выводы дисплея подключаются напрямую к контроллеру,дисплей запитывать от 3.3 или от 5 В от платы?
Напрямую от контроллера, 3.3 В
Можете назвать модель используемого дисплея?
Конечно) WH1602A
Добрый день!
Не могли бы Вы рассказать, как использовать вот такую штуку 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 для работы с экраном?
Хорошо, посмотрю вечерком, что это за девайс такой )
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 не компилируется. Подскажите пожалуйста куда копать?
Файл не подключен, в котором определяется BIT_4_MASK
Можно добавить прям в main.c:
При переключении на следующий разряд, нужно его принудительно гасить, выставляя 0.
Автор, спасибо большое за статью.
но мой индикатор работал не стабильно. После долгих ковыряний выснилось, что дело в неправильном формировании задержки.
Эту строку пришлось сделать так.
i = (rcc.HCLK_Frequency / 8000000) * us;
Добрый день
По вашей программе у меня на 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);
все стало ОК
Здравствуйте, подскажите что поправить в библиотеке чтобы пример заработал с F3Discovery?
Надо инициализацию поменять всех портов под F3
Добрый день! Помогите разобраться пробую подключить дисплей 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?
Ошибка скорее всего из-за типа данных bool.
А по поводу порта - у stm32f100rb просто немного другие значения возможные в SPL. В данном случае надо Push-Pull использовать.
забыл написать что оболочка CoIDE компилятор arm-none-eabi-gcc
на что нужно изменить bool ?
Можно попробовать дописать в MT_WH1602.h:
typedef enum {FALSE = 0, TRUE = !FALSE} bool;
Спасибо за помощь))
Кто подскажет: планирую этот пример использовать как библиотеку для работы с HD44780? И как лучше реализовать: вставкой перед main или как отдельный файл, прикрепив в проекте и просто вызывая функцию вывода на экран?
Лучше как отдельные файлы.
Здравствуйте, такой вопрос , сделал все как написано в статье,но после компиляции загораются все сегменты в дисплее но нужной информации нету, что это может быть??
А вывод контрастности подключен?
Подключал через потенциометр вращаю ручку контрастность меняется.Но информации нет.ВОт код программы.
#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();
}
}
Подключал через потенциометр вращаю ручку контрастность меняется.Но информации нет.ВОт код программы.
#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();
}
}
Дисплей точно такой же как в статье?
Да, дисплей WH1602A
Линии данных все прозваниваются? Точно верные порты заданы в программе?
Вот моя современная библиотека для этих древних 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.
Владислав
Сегодня протестировал на 40х04 - все работает.