STM32F103C8T6 can not communicate with HD44780

3

I'm trying to control a HD44780 16X2 LCD(4 bit communication) using a STM32F103C8T6. I connected the LCD this way:

RS => PA0

EN => PA2

RW Ground

D7 => PB7

D6 => PB6

D5 => PB5

D4 => PB4

The LCD doesn't display anything. Where might the problem be? Does anyone know something about this issue?

Here is my code:

#include "delay.h"
#include "stm32f10x.h" // Device header

void lcd_command(unsigned char command);
void lcd_init(void);
void lcdPosition(unsigned int row, unsigned int column);
void lcd_data(unsigned char data);

int main() {
  delay_init();
  RCC->APB2ENR |= 1 << 2; // Port A Enabled.
  RCC->APB2ENR |= 1 << 3; // Port B Enabled.

  GPIOA->CRL = 0x22222222; // A0 and A2 Output.
  GPIOB->CRL = 0x22222222; // B7,B6,B5,B4 Output.
  GPIOB->ODR = 0x00;       // Port B clear.

  delay_ms(20);
  lcd_command(0x30); // Datasheet says.
  delay_ms(5);
  lcd_command(0x30); // Datasheet says.
  delay_ms(1);
  lcd_command(0x30); // Datasheet says.
  delay_ms(1);
  lcd_init();
  lcdPosition(1, 1); // first row first column
  delay_ms(1);
  lcd_data('A'); // Letter A
  while (1)
    ;
}

void lcd_command(unsigned char command) {

  GPIOA->BRR |= 1 << 0; // RS reset.

  GPIOA->BSRR |= 1 << 2;   // E set.
  GPIOB->ODR = command;    // upper nibble
  delay_ms(2);             // delay
  GPIOA->BRR |= 1 << 2;    // E reset.
  GPIOB->BRR = 0x000000F0; // clear data bits
  delay_ms(2);             // delay

  command = command << 4; // lower nibble

  GPIOA->BSRR |= 1 << 2;   // E set.
  GPIOB->ODR = command;    // lower nibble
  delay_ms(2);             // delay
  GPIOA->BRR |= 1 << 2;    // E reset.
  GPIOB->BRR = 0x000000FF; // clear data bits
}
void lcd_init() {
  lcd_command(0x02); // Return
  delay_ms(2);       // delay
  lcd_command(0x28);
  set 4 - bit data, 2 - line, 5x7 font delay_ms(2); // delay
  lcd_command(0x0C);
  turn on display, cursor off.delay_ms(2); // delay
  lcd_command(0x01);                       // Clear.
  delay_ms(2);                             // delay
  lcd_command(0x06);
  move cursor right delay_ms(4); // delay
}
void lcdPosition(unsigned int row, unsigned int column) {
  if (row == 1) {
    column--;
    lcd_command(0x80 + column); // Define row

  } else if (row == 2) {
    column--;
    lcd_command(0xC0 + column); // Define column
  }
}

void lcd_data(unsigned char data) {
  GPIOA->BSRR |= 1 << 0; // RS reset.
  GPIOA->BSRR |= 1 << 2; // E set.
  GPIOB->ODR = data;
  upper nibble first delay_ms(4); // delay
  GPIOA->BRR |= 1 << 2;           // E reset.
  GPIOB->BRR = 0x000000F0;        // clear data bits
  delay_ms(4);                    // delay

  data = data << 4; // lower nibble

  GPIOA->BSRR |= 1 << 2;   // E set.
  GPIOB->ODR = data;       // lower nibble
  delay_ms(4);             // delay
  GPIOA->BRR |= 1 << 2;    // E reset.
  GPIOB->BRR = 0x000000FF; // clear data bits
}
stm32
keil
lcd
communicate
hd44780
asked on Stack Overflow Sep 30, 2019 by Ilker Aykut • edited Oct 1, 2019 by Tarick Welling

2 Answers

1

Also PA0 and PA2 are not 5V tolerant pins, usually HD44780 is 5V device, if it runs on +5V refer to the datasheet in Table 5. "Medium-density STM32F103xx pin definitions", if the pin is 5V tolerant in column I/O level it should be denoted with FT!

0

Please read carefully how to initialize 4-bit interface in the datasheet at page 46, figure 24.

In short: your lcd_command sends two nibbles one after another, but you are required to send only one nibble for first several commands (since the display controller still is in the 8-bit mode). You'll need to have a separate function to send only one nibble.

answered on Stack Overflow Oct 1, 2019 by AterLux

User contributions licensed under CC BY-SA 3.0