Для начала - по аппаратной части, то бишь по соединению МК и дисплея. Весь порт Е, с 0 по 15 выводы, занят шиной данных. Линии управления занимают часть порта B:
CS - 11 вывод;
RESET - 12 вывод;
WR - 13 вывод;
RS - 14 вывод;
RD - 15 вывод.
Это дело с помощью директивы #define для простоты прописываем в хидере исходника для lcd:
Спойлер
Код: Выделить всё
#define LCD_CTRLPORT GPIOB
#define LCD_RESET GPIO_Pin_12 //PORTB_12
#define LCD_CS GPIO_Pin_11 //PORTB_11
#define LCD_RS GPIO_Pin_14 //PORTB_14
#define LCD_WR GPIO_Pin_13 //PORTB_13
#define LCD_RD GPIO_Pin_15 //PORTB_15
Производим настройку портов (для 100й линейки придется чуток переписать - есть отличия в структурах) с помощью функции
LCD_CtrlLinesConfig():
Спойлер
Код: Выделить всё
void LCD_CtrlLinesConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOD, GPIOE, and GPIOB clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/*-- GPIO Configuration ------------------------------------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 |
GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |
GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* CTRL Pins Config */
GPIO_InitStructure.GPIO_Pin = LCD_RESET | LCD_CS | LCD_RS | LCD_WR | LCD_RD;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
return;
}
Помним, что при записи в регистр вначале мы пишем номер регистра, а затем - его содержимое.
Поэтому функция записи в регистр (
LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)) у нас состоит из двух функций.
Спойлер
Код: Выделить всё
void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
LCD_WriteRegIndex (LCD_Reg);
LCD_WriteRegValue (LCD_RegValue);
return;
}
А вот обе эти функции, по порядку: запись индекса регистра, запись числа в регистр.
Спойлер
Код: Выделить всё
/******************************************************************************/
void LCD_WriteRegIndex (uint16_t RegIndex){
GPIO_ResetBits(LCD_CTRLPORT, LCD_CS);
GPIO_ResetBits(LCD_CTRLPORT, LCD_RS);
GPIOE->ODR = RegIndex;
GPIO_ResetBits(LCD_CTRLPORT, LCD_WR);
GPIO_SetBits(LCD_CTRLPORT, LCD_WR);
return;
}
/******************************************************************************/
void LCD_WriteRegValue (uint16_t RegValue){
GPIO_ResetBits(LCD_CTRLPORT, LCD_CS);
GPIO_SetBits(LCD_CTRLPORT, LCD_RS);
GPIOE->ODR = RegValue;
GPIO_ResetBits(LCD_CTRLPORT, LCD_WR);
GPIO_SetBits(LCD_CTRLPORT, LCD_WR);
return;
}
/******************************************************************************/
Напомню, что имена выводов у нас - именованные константы, которые мы определяли в хидере.
И, собственно, инициализация.
Спойлер
Код: Выделить всё
void init_1289(void)
{
GPIO_SetBits(LCD_CTRLPORT, LCD_RESET);
Delay_ms(10);
GPIO_ResetBits(LCD_CTRLPORT, LCD_RESET);
Delay_ms(30);
GPIO_SetBits(LCD_CTRLPORT, LCD_RESET);
Delay_ms(50);
GPIO_SetBits(LCD_CTRLPORT, LCD_RD);
GPIO_SetBits(LCD_CTRLPORT, LCD_WR);
GPIO_SetBits(LCD_CTRLPORT, LCD_RS);
GPIO_ResetBits(LCD_CTRLPORT, LCD_CS);
// power supply setting
// set R07h at 0021h (GON=1,DTE=0,D[1:0]=01)
LCD_WriteReg(0x0007,0x0021);
// set R00h at 0001h (OSCEN=1)
LCD_WriteReg(0x0000,0x0001);
// set R07h at 0023h (GON=1,DTE=0,D[1:0]=11)
LCD_WriteReg(0x0007,0x0023);
// set R10h at 0000h (Exit sleep mode)
LCD_WriteReg(0x0010,0x0000);
// Wait 30ms
Delay_ms(30);
// set R07h at 0033h (GON=1,DTE=1,D[1:0]=11)
LCD_WriteReg(0x0007,0x0033);
// Entry mode setting (R11h)
// R11H Entry mode
// vsmode DFM1 DFM0 TRANS OEDef WMode DMode1 DMode0 TY1 TY0 ID1 ID0 AM LG2 LG2 LG0
// 0 1 1 0 0 0 0 0 0 1 1 1 * 0 0 0
LCD_WriteReg(0x0011,0x6078);
// LCD driver AC setting (R02h)
LCD_WriteReg(0x0002,0x0600);
// power control 1
// DCT3 DCT2 DCT1 DCT0 BT2 BT1 BT0 0 DC3 DC2 DC1 DC0 AP2 AP1 AP0 0
// 1 0 1 0 1 0 0 0 1 0 1 0 0 1 0 0
// DCT[3:0] fosc/4 BT[2:0] DC{3:0] fosc/4
LCD_WriteReg(0x0003,0x0804);//0xA8A4
LCD_WriteReg(0x000C,0x0000);//
LCD_WriteReg(0x000D,0x0808);// 0x080C --> 0x0808
// power control 4
// 0 0 VCOMG VDV4 VDV3 VDV2 VDV1 VDV0 0 0 0 0 0 0 0 0
// 0 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0
LCD_WriteReg(0x000E,0x2900);
LCD_WriteReg(0x001E,0x00B8);
LCD_WriteReg(0x0001,0x293F);//vertical inversion; start->left bottom corner
LCD_WriteReg(0x0010,0x0000);
LCD_WriteReg(0x0005,0x0000);
LCD_WriteReg(0x0006,0x0000);
LCD_WriteReg(0x0016,0xEF1C);
LCD_WriteReg(0x0017,0x0003);
LCD_WriteReg(0x0007,0x0233);
LCD_WriteReg(0x000B,0x0000|(3<<6));
LCD_WriteReg(0x000F,0x0000);
LCD_WriteReg(0x0041,0x0000);
LCD_WriteReg(0x0042,0x0000);
LCD_WriteReg(0x0048,0x0000);
LCD_WriteReg(0x0049,0x013F);
LCD_WriteReg(0x004A,0x0000);
LCD_WriteReg(0x004B,0x0000);
LCD_WriteReg(0x0030,0x0707);
LCD_WriteReg(0x0031,0x0204);
LCD_WriteReg(0x0032,0x0204);
LCD_WriteReg(0x0033,0x0502);
LCD_WriteReg(0x0034,0x0507);
LCD_WriteReg(0x0035,0x0204);
LCD_WriteReg(0x0036,0x0204);
LCD_WriteReg(0x0037,0x0502);
LCD_WriteReg(0x003A,0x0302);
LCD_WriteReg(0x003B,0x0302);
LCD_WriteReg(0x0023,0x0000);
LCD_WriteReg(0x0024,0x0000);
LCD_WriteReg(0x0025,0x8000);
LCD_WriteReg(0x004f,0);
LCD_WriteReg(0x004e,0);
Delay_ms(50);
LCD_Clear(LCD_COLOR_GREEN);
return;
}
В силу собственных нужд дисплей я настраивал так, чтобы отсчет строк начинался из нижнего левого угла.
Сейчас попробую найти фото, как это примерно выглядит..вот оно:
Спойлер

"Configuring" - велика и могуча моя китайская английская йезыка. Сам смеялся.
Функция задержки
Delay_ms() выглядит следующим образом.
Спойлер
Код: Выделить всё
/******************************************************************************/
void Delay_ms(uint32_t ms)
{
volatile uint32_t nCount;
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq (&RCC_Clocks);
nCount=(RCC_Clocks.HCLK_Frequency/10000)*ms;
for (; nCount!=0; nCount--);
}
Я ее честно стырил из каких-то исходников STM.
Функция заливки: 1. Устанавливаем позицию курсора (ф-ция
LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)). 2. Даем команду подготовки к записи (ф-ция LCD_WriteRAM_Prepare()). 3. Пишем данные.
Под спойлером - все по порядку.
Спойлер
Код: Выделить всё
void LCD_Clear(uint16_t Color)
{
uint32_t index = 0;
LCD_SetCursor(0x00, 0x00);
LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
for(index = 0; index < 76800; index++)
{
LCD_WriteRegValue (Color);
}
}
/*************************************************
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
LCD_WriteReg(0x004E, Xpos);
LCD_WriteReg(0x004F, Ypos);
return;
}
/*************************************************
void LCD_WriteRAM_Prepare(void)
{
LCD_WriteRegIndex (0x0022);
}
Да.. функция заливки оперирует параметром "LCD_COLOR_GREEN". Вот его определение.
Думаю, объяснять, как он получен, не нужно. =)
Вроде все, если что-то забыл написать/указать - пишите. Удачи.