STM32使用TFT--LCD顯示列行式的字模資料
**
stm32驅動TFT LCD螢幕顯示字元原理
**
之前因為一直要弄OLED螢幕顯示字元,漢字,圖片等,然後剛好最近手上有一個stm32的開發板,也有一塊240*320的TFTLCD顯示屏,只是很早之前寫過一個驅動,顯示字元什麼的都沒有去實現,其實也是自己技術菜,好了,廢話不多說,直接上程式碼。
void Ili9341_IOInit(void)
{
RCC->APB2ENR |=1<<2; //開啟GPIOA的時鐘
RCC->APB2ENR |=1<<5; //開啟GPIOD的時鐘
RCC->APB2ENR |=1<<6; //開啟GPIOE的時鐘
GPIOA->CRH &=0xFFFFFFF0;
GPIOA->CRH |=0x00000003; //背光使用通用推輓輸出模式PA8
GPIOD->CRL &=0x0F00FF00;
GPIOD->CRL |=0xB0BB00BB; //PD0,1,4,5,7
GPIOD->CRH &=0x00FF0000;
GPIOD->CRH |=0xBB00BBBB; //PD8,9,10,11,14,15
GPIOE->CRL &=0x0FFFFFFF;
GPIOE->CRL |=0xB0000000; //PE7
GPIOE->CRH &=0x00000000;
GPIOE->CRH |=0xBBBBBBBB;
GPIOA->ODR &=~(1<<8);
//配置FMSMC相關暫存器
RCC->AHBENR |=1<<8; //開啟FSMC的時鐘
FSMC_Bank1->BTCR[0]=0x00000000;
FSMC_Bank1->BTCR[1]=0x00000000;
FSMC_Bank1E->BWTR[0]=0x00000000;//初始化
FSMC_Bank1->BTCR[0] |=1<<12; //儲存器寫使能
FSMC_Bank1->BTCR[0] |=1<<14; //讀寫資料使用不同的時序
FSMC_Bank1->BTCR[0] |=1<<4; //儲存資料使用16位的寬度
//讀時序的暫存器配置
FSMC_Bank1->BTCR[1] |=0<<28; //使用模式A
FSMC_Bank1->BTCR[1] |=1<<0; //地址建立的時間
FSMC_Bank1->BTCR[1] |=0xF<<8; //資料儲存時間為16個HCLK
//寫資料的時序配置暫存器
FSMC_Bank1E->BWTR[0] |=0<<28; //使用模式A
FSMC_Bank1E->BWTR[0] |=0<<0; //地址建立時間
FSMC_Bank1E->BWTR[0] |=3<<8; //資料儲存時間
FSMC_Bank1->BTCR[0] |=1<<0; //使能BANK1的第一塊區域
}
該函式為初始化與螢幕連線的IO口以及stm32的FSMC模組功能。
void Ili9341_Init(void)
{
Ili9341_IOInit(); //初始化相關IO以及FSMC
Delay_Ms(200); //延時一定時間等待
FSMC_LCD_CMD(0xCF);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0xC1);
FSMC_LCD_DATA(0X30);
FSMC_LCD_CMD(0xED);
FSMC_LCD_DATA(0x64);
FSMC_LCD_DATA(0x03);
FSMC_LCD_DATA(0X12);
FSMC_LCD_DATA(0X81);
FSMC_LCD_CMD(0xE8);
FSMC_LCD_DATA(0x85);
FSMC_LCD_DATA(0x10);
FSMC_LCD_DATA(0x7A);
FSMC_LCD_CMD(0xCB);
FSMC_LCD_DATA(0x39);
FSMC_LCD_DATA(0x2C);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x34);
FSMC_LCD_DATA(0x02);
FSMC_LCD_CMD(0xF7);
FSMC_LCD_DATA(0x20);
FSMC_LCD_CMD(0xEA);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_CMD(0xC0); //Power control
FSMC_LCD_DATA(0x1B); //VRH[5:0]
FSMC_LCD_CMD(0xC1); //Power control
FSMC_LCD_DATA(0x01); //SAP[2:0];BT[3:0]
FSMC_LCD_CMD(0xC5); //VCM control
FSMC_LCD_DATA(0x30); //3F
FSMC_LCD_DATA(0x30); //3C
FSMC_LCD_CMD(0xC7); //VCM control2
FSMC_LCD_DATA(0XB7);
FSMC_LCD_CMD(0x36); // Memory Access Control
FSMC_LCD_DATA(0x08); //螢幕描點方向為從零點開始,從左往右,從上往下的方式進行描點畫素點
//FSMC_LCD_DATA(0x48);
FSMC_LCD_CMD(0x3A);
FSMC_LCD_DATA(0x55);
FSMC_LCD_CMD(0xB1);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x1A);
FSMC_LCD_CMD(0xB6); // Display Function Control
FSMC_LCD_DATA(0x0A);
FSMC_LCD_DATA(0xA2);
FSMC_LCD_CMD(0xF2); // 3Gamma Function Disable
FSMC_LCD_DATA(0x00);
FSMC_LCD_CMD(0x26); //Gamma curve selected
FSMC_LCD_DATA(0x01);
FSMC_LCD_CMD(0xE0); //Set Gamma
FSMC_LCD_DATA(0x0F);
FSMC_LCD_DATA(0x2A);
FSMC_LCD_DATA(0x28);
FSMC_LCD_DATA(0x08);
FSMC_LCD_DATA(0x0E);
FSMC_LCD_DATA(0x08);
FSMC_LCD_DATA(0x54);
FSMC_LCD_DATA(0XA9);
FSMC_LCD_DATA(0x43);
FSMC_LCD_DATA(0x0A);
FSMC_LCD_DATA(0x0F);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_CMD(0XE1); //Set Gamma
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x15);
FSMC_LCD_DATA(0x17);
FSMC_LCD_DATA(0x07);
FSMC_LCD_DATA(0x11);
FSMC_LCD_DATA(0x06);
FSMC_LCD_DATA(0x2B);
FSMC_LCD_DATA(0x56);
FSMC_LCD_DATA(0x3C);
FSMC_LCD_DATA(0x05);
FSMC_LCD_DATA(0x10);
FSMC_LCD_DATA(0x0F);
FSMC_LCD_DATA(0x3F);
FSMC_LCD_DATA(0x3F);
FSMC_LCD_DATA(0x0F);
FSMC_LCD_CMD(0x2B);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x01);
FSMC_LCD_DATA(0x3f);
FSMC_LCD_CMD(0x2A);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0x00);
FSMC_LCD_DATA(0xef);
FSMC_LCD_CMD(0x11); //Exit Sleep
Delay_Ms(120);
FSMC_LCD_CMD(0x29); //display on
LCD_ON; //開啟背光
}
然後是螢幕的初始化函式,本人的開發板是買的技小新的stm32的開發板,以及技小新的2.8寸的TFT——LCD螢幕,想看硬體的可以去相關官網自行下載琢磨。
#define LCD_ON GPIOA->ODR |=1<<8
#define LCD_OFF GPIOA->ODR &=~(1<<8)
//FSMC的A16與螢幕連線,A16是地址匯流排,第17,16位一起控制是寫命令還是寫資料,在使用中,需要向左偏移一位
#define FSMC_LCD_CMD(cmd) ((*(volatile u16 )((u32)0x60000000))=((u16)cmd))
#define FSMC_LCD_DATA(data) (((volatile u16 *)((u32)0x60020000))=((u16)data))
這是驅動的標頭檔案相關巨集定義
void Ili9341_SetPos(u16 x, u16 y)
{
FSMC_LCD_CMD(0x2A); //設定長度座標
FSMC_LCD_DATA(x>>8); //得到高位的資料
FSMC_LCD_DATA(x&0xff); //得到低8位的資料
FSMC_LCD_CMD(0x2B); //設定寬度座標 FSMC_LCD_DATA(y>>8); FSMC_LCD_DATA(y&0xff); }
接著貢獻出設定起始座標點的函式。 設定好座標點,起始很好理解,解釋描點開始的位置,然後可以自己控制點的執行規則。是直接行描點,還是列描點。
void Ili9341_DisplayCharacter(u16 x, u16 y,u8 size, u16 color, u8 chr)
{ u8 mGetValue; u8 mChValue=chr - ’ ';//獲取字元的偏移量,陣列的第一個字元為空格
u8 i,j,k;
if(size == 12)
{
for(j=0;j < 6;j++) //列數增加
{
mGetValue = asc2_1206[mChValue][j];
for(k=0;k < 8;k++) //行數在增加
{
Ili9341_SetPos(x + j,y + k); //設定要顯示字元的開始位置 FSMC_LCD_CMD(0x2C); //開啟寫資料
if(mGetValue & 0x01)
{
FSMC_LCD_DATA(color);
}
else
{
FSMC_LCD_DATA(WHITE);
}
mGetValue>>=1; //向右偏移一位資料,得到低2位的資料
}
}
for(j=0;j < 6;j++) //列數增加 { mGetValue = asc2_1206[mChValue][j + 6]; for(k=0;k < 4;k++) //行數在增加 { Ili9341_SetPos(x + j,y + 8 + k); //設定要顯示字元的開始位置 FSMC_LCD_CMD(0x2C); //開啟寫資料 if(mGetValue & 0x01) FSMC_LCD_DATA(color); else FSMC_LCD_DATA(WHITE); mGetValue>>=1; //向右偏移一位資料,得到低2位的資料 } }
}
else if(size == 16) //8 X 16
{
for(j=0;j < 8;j++) //列數增加
{
mGetValue = asc2_1608[mChValue][j];
for(k=0;k < 8;k++) //行數在增加
{
Ili9341_SetPos(x + j,y + k); //設定要顯示字元的開始位置
FSMC_LCD_CMD(0x2C); //開啟寫資料
if(mGetValue & 0x01)
FSMC_LCD_DATA(color);
else
FSMC_LCD_DATA(WHITE);
mGetValue>>=1; //向右偏移一位資料,得到低2位的資料
}
}
for(j=0;j < 8;j++) //列數增加
{
mGetValue = asc2_1608[mChValue][j + 8];
for(k=0;k < 8;k++) //行數在增加
{
Ili9341_SetPos(x + j,y + 8 + k); //設定要顯示字元的開始位置
FSMC_LCD_CMD(0x2C); //開啟寫資料
if(mGetValue & 0x01)
FSMC_LCD_DATA(color);
else
FSMC_LCD_DATA(WHITE);
mGetValue>>=1; //向右偏移一位資料,得到低2位的資料
}
}
}
}
const unsigned char asc2_1206[95][12]={
//取模方式為:陰碼,逆向,列行式
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/" ",0/
{0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00},/"!",1/
};
然後這是字模資料的取模方式。
到此顯示就算完成了,其他的也可以參考。