Работаем с Lcd дисплеем WH1602 в STM32 f4 discovery

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


 

Хотя может ещё быть вариант с пинами в два ряда сбоку...
Управляется такой дисплей очень просто. Есть два режима: по 8 проводной шине данны и по 4ёх проводной. Будем пользоваться первой системой т.к. она проще.
Другая не намного сложнее (данные нужно слать тетрадами), но отвлечёт от всей "магии"))

 Распиновка дисплея такая:


Обратите внимание, что дисплей питается от 5В в то время как контроллеры stm32 от 3,3В.
Упростим себе задачу и не будем считывать флаг занятости с устройства. Заменим эту функцию задержкой в коде. Следовательно пин 5 (RW) суем на землю.

ГРАБЛИ 1!! Пин 3 - регулировка контрастности дисплея.
Ложим её на землю видим закрашенные квадраты (таким образом можно проверить целостность дисплея). Для нормального вывода туда нужно напряжения 0,7-0,9В.
Делается это либо переменным резистором либо делителем напряжения.

Теперь разберёмся с тем как управлять. Каждая буква имеет свой код. Для латинского алфавита этот код совпадает с кодом символа (char), для русского можно создать массив с нужными кодами. Смотрите даташит.
Присоединили 8 пинов данных к ногам контроллера. Рекомендую это делать к соответствующим ногам чтобы сразу писать в регистр без сдвигов данных.
т.е.

DB7 -- PC7
DB6 -- PC6

и так далее...
Это всё существенно упрощает и даёт нам разбираться.

При старте дисплей нужно инициализировать послав несколько наборов данных, перед этим настроив ноги контроллера как выводы.

void lcd_init_gpio() {
    RCC_AHB1PeriphClockCmd(LCD_RCC_GPIO,ENABLE);
    GPIO_InitTypeDef init;
    init.GPIO_Mode = GPIO_Mode_OUT;
    init.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_12;
    init.GPIO_OType = GPIO_OType_PP;

    GPIO_Init(LCD_PORT,&init);
}

Теперь посылаем данные.

void lcd_init() {
    lcd_init_gpio();
    int del = 99999;
    GPIO_ResetBits(LCD_PORT, LCD_RS_Pin);  // rs = 0

    delay(del);
    lcd_write_data(0b00110000); //init1

    delay(del);
    lcd_write_data(0b00110000); //init2

    delay(del);
    lcd_write_data(0b00110000); //init3

    delay(del);
    lcd_write_data(0b00111000); // function set  8bit 2line 5x8 dots

    delay(del);
    lcd_write_data(0b00001111); // display on + cursor underline + blinking

    delay(del);
    lcd_write_data(0b00000001); //clear

    delay(del);
    lcd_write_data(0b00000110); //entry mode set

    delay(del);
    lcd_write_data(0b00000010); // return to home

    delay(del);
    GPIO_SetBits(LCD_PORT,LCD_RS_Pin);  //rs = 1
}

Обратите внимание, что пин RS нужно установить в ноль, чтобы контроллер дисплея воспринял управляющие команды. Иначе он решит что это данные.
Теперь о функции записи данных. она посылает данные на указанные в ноги.
Я соблюдал номера ног и номера разрядов данных, поэтому меня интересует только порт на который подключен дисплей.

void lcd_write_data(u16 data) {
    GPIO_SetBits(LCD_PORT,data | LCD_E_Pin);
    delay(0xFFFF);
    GPIO_ResetBits(LCD_PORT,LCD_E_Pin | data);
}

Мы "выставляем" данные на ноги порта соединённого с lcd и устанавливаем пин E в 1.
Ждём пока данные "зарегистрируются" и устанавливаем E в ноль. Остальные пины тоже сбрасываем.

Вот и всё. Уже сейчас можно выводить порции данных на дисплей.
Но мы ещё опишем функцию для перемещения курсора:

void lcd_set_cursor(int line,int pos) {
    pos |= 0b10000000;
    if (line == 1) {
        pos += 0x40;
    }
    lcd_write_cmd(pos);
}

line - номер строки (0 или 1)
pos - позиция. тоже от 0 до 16.

Так как коды символов совпадают, можно также написать функцию для вывода строк:

void lcd_write_str(char*str) {
    do {
        lcd_write_data(*str);
    }while(*++str);
}

Задержку я сделал просто циклом:

void delay(unsigned int s){
    while(--s > 0) {
        __NOP();
    }
}

Для работы также нужно определить константы порта и пинов RS,E
У меня вот так:

#define LCD_PORT GPIOC
#define LCD_RCC_GPIO RCC_AHB1Periph_GPIOC
#define LCD_E_Pin GPIO_Pin_12
#define LCD_RS_Pin GPIO_Pin_10

Вот собственно архив с либой.

зы не претендую на самый крутой код и прочее. Даю гарантию работоспособности в Eclipse + st-util + stm32f4discovery + wh1602b

Доказательства:

Просмотров:   25081

Комментарии

чт, 02/14/2013 - 19:26
Максим

А как сделать вывод числовых переменных?

пт, 02/15/2013 - 19:33

Не идеальное решение но всё же:

const uint8_t lcd_2x16_decode[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

void lcd_write_dec_xxxx(uint16_t data){
	lcd_write_data(lcd_2x16_decode[(data / 1000) & 0x0F]);
	lcd_write_data(lcd_2x16_decode[((data % 1000) / 100) & 0x0F]);
	lcd_write_data(lcd_2x16_decode[((data % 1000) % 100) / 10 & 0x0F]);
	lcd_write_data(lcd_2x16_decode[((data % 1000) % 100) % 10 & 0x0F]);
}

void lcd_write_dec_xxx(uint16_t data){
	lcd_write_data(lcd_2x16_decode[(data / 100) & 0x0F]);
	lcd_write_data(lcd_2x16_decode[((data % 100) / 10) & 0x0F]);
	lcd_write_data(lcd_2x16_decode[((data % 100) % 10) & 0x0F]);
}

void lcd_write_dec_xx(uint8_t data){
	lcd_write_data(lcd_2x16_decode[((data % 100) / 10) & 0x0F]);
	lcd_write_data(lcd_2x16_decode[((data % 100) % 10) & 0x0F]);
}

void lcd_write_dec_x(uint8_t data) {
	lcd_write_data(lcd_2x16_decode[data]);
}

 

ср, 01/08/2014 - 21:09
Олег

Спасибо за статью, надо будет прикрутить дисплейчик

Добавить комментарий

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.
CAPTCHA
Введи эти символы. Ато роботы одолели!