:::: MENU ::::

hd44780

Хотел описать свою попытку написать универсальный драйвер для символьного дисплея с контроллером HD44780 или его аналогом.

Что-бы он был универсальным, надо что-бы функции задержки и дрыганья ножек на всех микроконтроллерах были одинаковы, естественно этого добиться нельзя.

Поэтому я написал свой код так, что-бы его было очень просто перенести на другие микроконтроллеры — для этого надо реализовать функцию задержки, в которую передаются параметры на сколько микросекунд задержка, и функцию дрыганья одной ножки для каждой ножки подключенной к тому или иному pin дисплея (см. код — timer6wait, setRS, clearRS,setRW, clearRW, setE, clearE, setDB0, clearDB0, setDB1,clearDB1, setDB2, clearDB2, setDB3, clearDB3, setDB4,clearDB4, setDB5, clearDB5, setDB6, clearDB6, setDB7,clearDB7). т.е. в эти функции поместить код, который будет через регистры вашего микроконтроллера, управлять вашим микроконтроллером для того, что-бы он делал то что нужно — задержку на N мкс, сброс напряжения на нужной ножке в 0, установка напряжения в логическую 1 на нужной ножке.

Весь остальной код универсален и его не нужно менять при переходе с одного микроконтроллера на другой(PIC, STM32,STM8, ATMEGA и т.д.). У меня код написан для STM32L1 и для 4 строчного дисплея(по 20 символов в каждой строке).

Разберем код.

В файле hd44780.c реализованы основные функции управления дисплеем в 8-битном режиме.

Функция инициализации дисплея.

void hd44780_init(void)
{
    send_DB_0_7_lines(0); 
    clear_RW();
    clear_RS();
    clear_E();
    timer_6_wait(40000);

    send_DB_0_7_lines(0x30);
    timer_6_wait(5000);
    blink_E();
    timer_6_wait(160);
    blink_E();
    timer_6_wait(160);
    blink_E();
    timer_6_wait(160);

    send_DB_0_7_lines(0x38);
    blink_E();
    timer_6_wait(160);


    hd44780_command(0x10);
    hd44780_command(0x0C);
    hd44780_command(0x06);
}

 

Основные задержки и команды взяты из документации на дисплеи МЭЛТ (см. картинку ниже) и в принципе стандартные на HD44780.

hd44780_init

 

hd44780_cmd

Функция выдачи команды на дисплей.

void hd44780_command(uint8_t lcdcmnd)
{
    timer_6_wait(40);
    send_DB_0_7_lines(lcdcmnd);
    clear_RS();
    clear_RW();
    blink_E();
    if(lcdcmnd < 2)
    {
        timer_6_wait(1700);
    }
}

Функция установки нужных значений на ножках дисплея для выдачи команд — реализована для универсальности кода.

void send_DB_0_7_lines(uint8_t command)
{
    if((command & 1) == 1)
    {
        set_DB0();
    }
    else
    {
        clear_DB0();
    }

    if(((command >> 1) & 1) == 1)
    {
        set_DB1();
    }
    else
    {
        clear_DB1();
    }

    if(((command >> 2) & 1) == 1)
    {
        set_DB2();
    }
    else
    {
        clear_DB2();
    }

    if(((command >> 3) & 1) == 1)
    {
        set_DB3();
    }
    else
    {
        clear_DB3();
    }

    if(((command >> 4) & 1) == 1)
    {
        set_DB4();
    }
    else
    {
        clear_DB4();
    }

    if(((command >> 5) & 1) == 1)
    {
        set_DB5();
    }
    else
    {
        clear_DB5();
    }

    if(((command >> 6) & 1) == 1)
    {
        set_DB6();
    }
    else
    {
        clear_DB6();
    }

    if(((command >> 7) & 1) == 1)
    {
        set_DB7();
    }
    else
    {
        clear_DB7();
    }
}

Функция моргания сигналом Eстроб импульс, необходима для установки команды.

void blink_E(void)
{
    set_E();
    timer_6_wait(1);
    clear_E();
}

Перенос курсора в нужную позицию — для более удобного вывода на дисплей. Перенос в нужную позицию курсора осуществляется командой 0b10000000 (см. таблицу выше). Эта команда выбирает область в DDRAM для последующих операций. Область памяти для каждого символа указана на рисунке ниже.

hd44780_mem

Так для первой строки смещение 0x00 и команда 0b100000000x80, для второй смещение 0x40 и команда 0b100000000xC0, для третьей смещение 0x14 и команда 0b100000000x94, для четвертой смещение 0x54 и команда 0b100000000xD4. Для перехода на на нужный столбец (по x) — необходимо прибавить нужное смещение — что и реализовано в коде ниже.

void hd44780_goto(uint8_t x, uint8_t y)
{
  uint8_t addr;

  switch (y)
  {
  case 0:
    addr = 0x80;
    break;
  case 1:
    addr = 0xC0;
    break;
  case 2:
    addr = 0x94;
    break;
  default:
    addr = 0xD4;
    break;
  }
  addr = addr + x;
  hd44780_command(addr);
}

Вывод символа на дисплей.

void hd44780_char(uint8_t ldata)
{
    set_RS();
    clear_RW();

    timer_6_wait(40);
    send_DB_0_7_lines(ldata);
    blink_E();
}

Вывод строки на дисплей.

void hd44780_write(char ldata[])
{
  char k=0;

    set_RS();
    clear_RW();

  while(ldata[k] != 0)
  {
        timer_6_wait(40);
    send_DB_0_7_lines(ldata[k]);
    blink_E();
    k++;
  }
}

В файле hd44780_4bit.c реализованы все те же функции только для 4-битного режима.

В файле hd44780_driver.c реализованы зависимые, от типа микроконтроллера и от схемы подключения дисплея, функции.

Так например для STM32L1

void set_E(void)
{
    //PB10
    GPIO_SetBits(GPIOB, GPIO_Pin_10);
}

void clear_E(void)
{
    GPIO_ResetBits(GPIOB, GPIO_Pin_10);
}

void set_DB0(void)
{
    //PC6
    GPIO_SetBits(GPIOC, GPIO_Pin_6);
}

void clear_DB0(void)
{
    GPIO_ResetBits(GPIOC, GPIO_Pin_6);
}

************************
и т.д.

Немного неправильно сделано — то что функция для задержки на N мкс лежит в timeworks.c и называется привязано к моему микроконтроллеру. Правильно конечно было ее вынести в hd44780driver.c и переименовать просто в wait_hd44780() — для того, чтобы красиво сформировать библиотечные файлы.

Задержка для STM32L1:

void timer_6_1us_int(void)
{
    TIM_TimeBaseInitTypeDef TIMER_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
    TIM_TimeBaseStructInit(&TIMER_InitStructure);

    TIMER_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIMER_InitStructure.TIM_Period = 16;
    TIMER_InitStructure.TIM_Prescaler = 1;
    TIM_TimeBaseInit(TIM6, &TIMER_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_SelectOnePulseMode(TIM6, TIM_OPMode_Single);
    TIM_ITConfig(TIM6, TIM_IT_Update,ENABLE);
}

void timer_6_wait(uint32_t n_usec)
{   
    extern uint8_t f_timer_6_end;

    if(n_usec <= 4000)
    {
        TIM6->PSC = 0;
        TIM6->ARR = (uint16_t)(16 * n_usec);
        TIM_Cmd(TIM6, ENABLE);
    }
    else
    {
        TIM6->PSC = 1000 - 1;
        TIM6->ARR = (uint16_t)(16 * (n_usec / 1000));
        TIM_Cmd(TIM6, ENABLE);
    }

    while(f_timer_6_end == 0){}
    f_timer_6_end = 0;
}

Код для работы с дисплеем в 8 битном режиме:

send_DB_0_7_lines(0);

hd44780_init_8_bit();
hd44780_command_8_bit(0x01); // clear screen
timer_6_wait(1700);
hd44780_command_8_bit(0x01); // clear screen
hd44780_write_8_bit("It's Work");

Код для работы с дисплеем в 4 битном режиме:

send_DB_4_7_lines(0);

hd44780_init_4_bit();
hd44780_command_4_bit(0x01); // clear screen
timer_6_wait(1700);
hd44780_command_4_bit(0x01); // clear screen
hd44780_write_4_bit("It's Work");

Проект реализованный в keil mdk arm v5 приложен далее заархивированый 7zip.

hd44780_driver