Skip to main content
Visitor
September 9, 2026
Question

Connection to alphanumeric LCD model 1602

  • September 9, 2026
  • 6 replies
  • 36 views

Hello. I am a beginner, I am trying to connect an STM32 nucleo f446re to an LCD, model 1602A V 2.0.

I tried making a test code with no functions to see if the display works

I only see a grid of rectangles light up and when running the code no characters display. What could be the issue?

 

This is the code: 

int main(void){



/* USER CODE BEGIN 1 */



HAL_Init();

SystemClock_Config();







// LCD Board label STM32 pin

//---------------------------------------

// RS D10 PB6

// E D9 PC7

// D4 D8 PA9

// D5 D7 PA8

// D6 D6 PB10

// D7 D5 PB4





// =====================================================

// ENABLE GPIO CLOCKS

// =====================================================



RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;





// =====================================================

// CONFIGURE GPIO PINS AS OUTPUTS

// =====================================================



// PB6 = RS

GPIOB->MODER &= ~(3U << (6 * 2));

GPIOB->MODER |= (1U << (6 * 2));



// PC7 = E

GPIOC->MODER &= ~(3U << (7 * 2));

GPIOC->MODER |= (1U << (7 * 2));



// PA9 = D4

GPIOA->MODER &= ~(3U << (9 * 2));

GPIOA->MODER |= (1U << (9 * 2));



// PA8 = D5

GPIOA->MODER &= ~(3U << (8 * 2));

GPIOA->MODER |= (1U << (8 * 2));



// PB10 = D6

GPIOB->MODER &= ~(3U << (10 * 2));

GPIOB->MODER |= (1U << (10 * 2));



// PB4 = D7

GPIOB->MODER &= ~(3U << (4 * 2));

GPIOB->MODER |= (1U << (4 * 2));





// =====================================================

// LCD POWER-UP WAIT

// =====================================================



HAL_Delay(20);





// =====================================================

// 4-BIT INITIALIZATION

// =====================================================



// RS = 0

// Command mode

GPIOB->BSRR = (1U << (6 + 16));





// =====================================================

// SEND 0011

// =====================================================



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 1

GPIOA->BSRR = (1U << 9);



// Pulse E

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));



HAL_Delay(5);





// =====================================================

// SEND 0011 AGAIN

// =====================================================



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 1

GPIOA->BSRR = (1U << 9);



// Pulse E

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));



HAL_Delay(1);





// =====================================================

// SEND 0011 A THIRD TIME

// =====================================================



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 1

GPIOA->BSRR = (1U << 9);



// Pulse E

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));



HAL_Delay(1);





// =====================================================

// SEND 0010

// Switch LCD to 4-bit mode

// =====================================================



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// Pulse E

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));



HAL_Delay(1);





// =====================================================

// LCD IS NOW IN 4-BIT MODE

// =====================================================





// =====================================================

// COMMAND: 0x28

// 0010 1000

//

// 4-bit mode

// 2 lines

// 5x8 character font

// =====================================================



// RS = 0

GPIOB->BSRR = (1U << (6 + 16));





// First nibble = 0010



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Second nibble = 1000



// D7 = 1

GPIOB->BSRR = (1U << 4);



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// COMMAND: 0x0C

// 0000 1100

//

// Display ON

// Cursor OFF

// Blink OFF

// =====================================================



// RS = 0

GPIOB->BSRR = (1U << (6 + 16));





// First nibble = 0000



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Second nibble = 1100



// D7 = 1

GPIOB->BSRR = (1U << 4);



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// COMMAND: 0x01

// 0000 0001

//

// Clear display

// =====================================================



// RS = 0

GPIOB->BSRR = (1U << (6 + 16));





// First nibble = 0000



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Second nibble = 0001



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 1

GPIOA->BSRR = (1U << 9);



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Clear display takes longer than normal commands

HAL_Delay(5);





// =====================================================

// COMMAND: 0x06

// 0000 0110

//

// Increment cursor after each character

// =====================================================



// RS = 0

GPIOB->BSRR = (1U << (6 + 16));





// First nibble = 0000



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Second nibble = 0110



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// SEND "hello"

// =====================================================



// RS = 1 → data mode

GPIOB->BSRR = (1U << 6);





// =====================================================

// 'h' = 0x68 = 0110 1000

// =====================================================



// Upper nibble = 0110



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Lower nibble = 1000



// D7 = 1

GPIOB->BSRR = (1U << 4);



// D6 = 0

GPIOB->BSRR = (1U << (10 + 16));



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// 'e' = 0x65 = 0110 0101

// =====================================================



// Upper nibble = 0110



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Lower nibble = 0101



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 1

GPIOA->BSRR = (1U << 9);



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// 'l' = 0x6C = 0110 1100

// =====================================================



// Upper nibble = 0110



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Lower nibble = 1100



// D7 = 1

GPIOB->BSRR = (1U << 4);



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// Second 'l' = 0x6C = 0110 1100

// =====================================================



// Upper nibble = 0110



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Lower nibble = 1100



// D7 = 1

GPIOB->BSRR = (1U << 4);



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 0

GPIOA->BSRR = (1U << (8 + 16));



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// 'o' = 0x6F = 0110 1111

// =====================================================



// Upper nibble = 0110



// D7 = 0

GPIOB->BSRR = (1U << (4 + 16));



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 0

GPIOA->BSRR = (1U << (9 + 16));



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// Lower nibble = 1111



// D7 = 1

GPIOB->BSRR = (1U << 4);



// D6 = 1

GPIOB->BSRR = (1U << 10);



// D5 = 1

GPIOA->BSRR = (1U << 8);



// D4 = 1

GPIOA->BSRR = (1U << 9);



// E pulse

GPIOC->BSRR = (1U << 7);

HAL_Delay(1);

GPIOC->BSRR = (1U << (7 + 16));





// =====================================================

// MAIN LOOP

// =====================================================



while (1)

{

}





/* USER CODE END 1 */







}
LCD wiring
STM32 wiring

 

6 replies

mƎALLEm
ST Technical Moderator
September 9, 2026

Hello ​@Rick_ and welcome to the ST community,

I only see a grid of rectangles light up

That means the LCD is not yet/not correctly initialized.

At this stage avoid the direct access to the registers as it introduces more complexity in the analysis. Use HAL and follow the LCD initialization steps mentioned in the LCD datasheet.

PS: in next time please use “Code” button when you insert a code snippet:

I’ve edited your post to follow this recommendation.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
Associate II
September 9, 2026

(sorry, I was wrong)

 

Andrew Neil
Super User
September 9, 2026

 I am a beginner

Welcome to the forum, and the world of STM32 !

Do you have experience with any other microcontroller(s)? With programming in general?

 

Getting an LCD to work requires you to have already mastered quite a few things - please take a look at:

 

I tried making a test code with no functions

I don’t think that’s a good approach.

You end up with a huge amount of duplicated code - which gives loads of opportunities for errors to creep in.

A much better approach is to write functions.

Start with simple things, like pulsing the E line - these are easy to test and, once tested, you know they work.

Then build on these to do more advanced stuff - like initialising the display.

 

As ​@mƎALLEm said, using HAL functions lets you concentrate on getting the display working without having to get bogged down in the arcane minutiae of the STM32 internals.

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Pavel A.
September 9, 2026

There are a lot of “1602” compatible LCDs from different vendors. We don’t know what exactly you have. Does it require 5V inputs? The STM32 output pins provide 3.3V. If not sure, consider other LCD module which has I2C interface (some of these on Ali express consist of a “1602” + I2C interface board) . Costs slightly more, but much easier to use.

Ozone
Principal
September 10, 2026

> There are a lot of “1602” compatible LCDs from different vendors. We don’t know what exactly you have. Does it require 5V inputs?

I would definitely second that.
These modules are quite widespread in the Arduino world, and many of the common Arduinos run with 5V.
I would recommend to download and read the datasheet and user manual for the LCD board.

Andrew Neil
Super User
September 10, 2026

 

These modules are quite widespread in the Arduino world, 

Indeed.

 

In the OP, ​@Rick_ wrote:

I tried making a test code ... to see if the display works

@Rick_ - so what is your actual goal here ?

  • Learning STM32 ?
  • Testing this unknown LCD ?

If the latter, it might be easier to use an Arduino with a known-good sketch …

Lots to be found on the Arduino forums…

https://forum.arduino.cc/

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.