/* p3_3.c: Initialize and display "HELLO" on the LCD using 4-bit data mode. * * Because of 4-bit data mode, every byte of command or data is * transmitted twice, one for the upper nibble and one for lower nibble. * This program does not poll the status of the LCD. * It uses delay to wait out while LCD controller is busy. * For simplicity, all delay below 1 ms uses 1 ms. You may * want to adjust the amount of delay for your LCD controller * to enhance the performance. * * The LCD controller arduino shield is connected to the Nucleo-F030R8 * board as follows: * * LCD --> Arduino pin --> STM32F030R8 pin * DB4 --> Digital 4 --> PB5 * DB5 --> Digital 5 --> PB4 * DB6 --> Digital 6 --> PB10 * DB7 --> Digital 7 --> PA8 * RS --> Digital 8 --> PA9 * EN --> Digital 9 --> PC7 * BL --> Digital 10 --> PB6 * * This program was tested with Keil uVision v5.23 with DFP v2.0.0 */ #include "stm32f0xx.h" #define DB4 (1<<5) /* PB5 mask for reg select */ #define DB5 (1<<4) /* PB4 mask for enable */ #define DB6 (1<<10) /* PB10 mask for reg select */ #define DB7 (1<<8) /* PA8 mask for enable */ #define RS (1<<9) /* PA9 mask for reg select */ #define EN (1<<7) /* PC7 mask for enable */ #define BL (1<<6) /* PB6 mask for reg select */ #define SET_RS() GPIOA->BSRR = RS #define CLR_RS() GPIOA->BSRR = RS<<16 #define SET_EN() GPIOC->BSRR = EN #define CLR_EN() GPIOC->BSRR = EN<<16 void delayMs(int n); void LCD_nibble_write(char data, unsigned char control); void LCD_command(unsigned char command); void LCD_data(char data); void LCD_init(void); void PORTS_init(void); int main(void) { /* initialize LCD controller */ LCD_init(); while (1) { /* Write "HELLO" on LCD */ LCD_data('H'); LCD_data('E'); LCD_data('L'); LCD_data('L'); LCD_data('O'); delayMs(1000); /* clear LCD display */ LCD_command(1); delayMs(1000); } } /* initialize GPIOB/C then initialize LCD controller */ void LCD_init(void) { PORTS_init(); delayMs(20); /* LCD controller reset sequence */ LCD_nibble_write(0x30, 0); delayMs(5); LCD_nibble_write(0x30, 0); delayMs(1); LCD_nibble_write(0x30, 0); delayMs(1); LCD_nibble_write(0x20, 0); /* use 4-bit data mode */ delayMs(1); LCD_command(0x28); /* set 4-bit data, 2-line, 5x7 font */ LCD_command(0x06); /* move cursor right */ LCD_command(0x01); /* clear screen, move cursor to home */ LCD_command(0x0F); /* turn on display, cursor blinking */ } void PORTS_init(void) { /* enable GPIOA/B/C clock */ RCC->AHBENR |= 0x00020000; RCC->AHBENR |= 0x00040000; RCC->AHBENR |= 0x00080000; /* * DB7 --> Digital 7 --> PA8 * RS --> Digital 8 --> PA9 */ GPIOA->MODER &= ~0x000F0000; /* clear pin mode */ GPIOA->MODER |= 0x00050000; /* set pin output mode */ /* * DB4 --> Digital 4 --> PB5 * DB5 --> Digital 5 --> PB4 * DB6 --> Digital 6 --> PB10 * BL --> Digital 10 --> PB6 */ GPIOB->MODER &= ~0x00303F00; /* clear pin mode */ GPIOB->MODER |= 0x00101500; /* set pin output mode */ GPIOB->BSRR = BL; /* turn on Backlight */ /* * EN --> Digital 9 --> PC7 */ GPIOC->MODER &= ~0x0000C000; /* clear pin mode */ GPIOC->MODER |= 0x00004000; /* set pin output mode */ GPIOC->BSRR = EN << 16; /* turn off EN */ } void LCD_nibble_write(char data, unsigned char control) { uint16_t datamask = 0; /* populate data bits */ /* * LCD --> Arduino pin --> STM32F030R8 pin * DB4 --> Digital 4 --> PB5 * DB5 --> Digital 5 --> PB4 * DB6 --> Digital 6 --> PB10 * DB7 --> Digital 7 --> PA8 */ if(data & (1<<4)){ datamask |= DB4; } if(data & (1<<5)){ datamask |= DB5; } if(data & (1<<6)){ datamask |= DB6; } // GPIOB->BSRR = (DB4|DB5|DB7)<<16 | datamask; GPIOB->BSRR = (DB4|DB5|DB6)<<16; GPIOB->BSRR = datamask; GPIOA->BSRR = DB7<<16 | ((data&(1<<7))?DB7:0); /* set R/S bit */ if (control) SET_RS(); else CLR_RS(); /* pulse E */ SET_EN(); delayMs(0); CLR_EN(); } void LCD_command(unsigned char command) { LCD_nibble_write(command & 0xF0, 0); /* upper nibble first */ LCD_nibble_write(command << 4, 0); /* then lower nibble */ if (command < 4) delayMs(2); /* command 1 and 2 needs up to 1.64ms */ else delayMs(1); /* all others 40 us */ } void LCD_data(char data) { LCD_nibble_write(data & 0xF0, 1); /* upper nibble first */ LCD_nibble_write(data << 4, 1); /* then lower nibble */ delayMs(1); } /* delay n milliseconds (8 MHz CPU clock) */ void delayMs(int n) { int i; for (; n > 0; n--) for (i = 0; i < 1142; i++); }