Převzaté z http://mcu.cz/comment.php?comment.news.2181 a upravené.

#include "stm32f10x.h"
 
// LCD_RW je pripojen na GND = zapis
#define LCD_PORT GPIOC
#define LCD_RS   GPIO_Pin_10
#define LCD_E    GPIO_Pin_11
#define LCD_D4   GPIO_Pin_0
#define LCD_D5   GPIO_Pin_1
#define LCD_D6   GPIO_Pin_2
#define LCD_D7   GPIO_Pin_3
 
/**
 * LCD (HD44780) ovládané 4-bity.
 *
 * Jakub Trmota (trmotjak)
 */
 
/**
 * Inicializace LCD.
 */
void LcdInitialize()
{
	// Inicalizace PINu
	GPIO_InitTypeDef GPIO_InitStructure;
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
 
	GPIO_InitStructure.GPIO_Pin = LCD_RS | LCD_E | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(LCD_PORT, &GPIO_InitStructure);
 
	// Inicializace LCD (dle specifikace nastaveni na 4-bitovou komunikaci)
	GPIO_ResetBits(LCD_PORT, LCD_RS | LCD_E);
	LcdDelayUs(20000); // wait more than 15 ms
	LcdSend4Bits(48); // 0011(0000)
	LcdDelayUs(6000);	// wait more than 4.1 ms
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdSend4Bits(48); // 0011(0000)
	LcdDelayUs(200); // wait more than 100 us 
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdSend4Bits(48); // 0011(0000)
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdDelayUs(20);
 
	// Nyni by mel byt LCD v 8-bitovem modu a definitivne ho prepneme do 4-bitoveho modu
	LcdSend4Bits(32); // 0010(0000)
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdDelayUs(100);
 
	// Prikaz 0 0 1 DL N F * * (DL = bitu komunikace 1 = 8bitu, 0 = 4bity; N = pocet radek 1 = 2 radky, 0 = 1 radka; F = Font 1=5x10bodu, 0=5x8 bodu)
	LcdSendCommand(40); // 00101000
	LcdDelayUs(100);
 
	// Display off
	LcdSendCommand(8); // 00001000
	LcdDelayUs(100);
 
	// Display clear
	LcdSendCommand(1); // 00000001
	LcdDelayUs(2000); // wait 1,64 ms
 
	// Zvedej sam adresu a posunuj kurzor, ktery neukazuj
	LcdSendCommand(12); // 00001100
	LcdDelayUs(100);
}
 
/**
 * Odesla prikaz do LCD.
 * @param cmd prikaz
 */
void LcdSendCommand(uint8_t cmd)
{
	LcdSend4Bits(cmd);
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdDelayUs(50);
 
	LcdSend4Bits(cmd << 4);
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdDelayUs(50);
}
 
/**
 * Odesle 4-bitovy prikaz do LCD.
 * @param bits prikaz
 */
void LcdSend4Bits(uint8_t bits)
{
	uint16_t portData;
	bits = bits >> 4;
	portData = GPIO_ReadOutputData(LCD_PORT);
	portData = portData & 0xFFF0;
	portData = portData | (uint16_t) bits;
	GPIO_Write(LCD_PORT, portData);
	GPIO_SetBits(LCD_PORT, LCD_E);
	LcdDelayUs(200);
}
 
/**
 * Odesle znak do LCD.
 * @param cmd znak
 */
void LcdSendChar(char cmd)
{
	GPIO_SetBits(LCD_PORT, LCD_RS);
 
	LcdSend4Bits(cmd);
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdDelayUs(50);
 
	LcdSend4Bits(cmd << 4);
	GPIO_ResetBits(LCD_PORT, LCD_E);
	LcdDelayUs(50);
 
	GPIO_ResetBits(LCD_PORT, LCD_RS);
	LcdDelayUs(50);
}
 
/**
 * Vymaze LCD.
 */
void LcdClear(void)
{
    LcdSendCommand(1); // 00000001
	LcdDelayUs(2000); // wait 1,64 ms
}
 
/**
 * Nastavi kurzor na pocatecni pozici.
 */
void LcdCursorHome(void)
{
    LcdSendCommand(2); // 00000010
	LcdDelayUs(2000); // wait 1,64 ms
}
 
/**
 * Nastavi kurzor na pozici.
 * @param col sloupec (1 - 20)
 * @param row radek (1 nebo 2)
 */
void LcdSetCursor(int col, int row)
{
	LcdSendCommand(0x80 + ((((row - 1) * 40) + (col - 1)) & 0x7F));
	LcdDelayUs(2000);
}
 
/**
 * Napise retezec na LCD.
 * @param str retezec
 */
void LcdPrint(char *str)
{
	uint8_t i = 0;
 
	if (!str) {
		return;
	}
 
	while(str[i] != '\0')
	{
		LcdSendChar(str[i++]);
	}
}
 
/**
 * Napise string z flash pameti na LCD.
 * @param str retezec
 */
void LcdPrintFlash(const char *str)
{
	uint8_t i = 0;
 
	if (!str) {
		return;
	}
 
	while(str[i] != '\0')
	{
		LcdSendChar(str[i++]);
	}
}
 
/**
 * Funkce cekani v us (priblizne).
 * @param us us na cekani
 */
void LcdDelayUs(__IO uint32_t us)
{
	us = us * ((SystemCoreClock / 3) / 1000000);
 
	for (; us != 0; us--);
}