剛好手邊有塊Nokia 5110 LCD 就拿它來做測試吧~雖然這塊LCD年份久遠了,但還是很適合來做些小東西玩玩!
先介紹一下這塊LCD上面的接腳 :
腳位 | 說明 | 連接腳位 |
---|---|---|
RST | LCD 重置 | PB15 |
CS | 選擇腳位 | PB6 |
D/C | 資料或命令切換 | PB13 |
DIN | 資料輸入 | PA7 |
CLK | 系統時鐘 | PA5 |
VCC | 電源 | 3.3v |
BLC | 背光控制 | PB14 |
GND | 接地 | GND |
Nokia 5110 是使用SPI協議但沒有MISO只有MOSI,所以MISO透過程式模擬就可以了。
上方表是各個腳位的連接,在這邊我使用SPI1所以主要使用是PA5-7,CS透過軟體選擇則是PB6,除了電源與接地外其餘的腳位可以依照個人去更改。
接下來看看LCD的指令有哪些~
可以看到其中功能設置、寫指令、設置RAM XY位置等等,可以先將會使用到的函數先寫出來,方便之後去使用。
D | E | Mode |
---|---|---|
0 | 0 | 顯示空白 |
1 | 0 | 普通模式 |
0 | 1 | 打開所有顯示 |
1 | 1 | 反轉 |
上方功能中的RAM是什麼?可以把它想成顯示pixel的地址,這一塊是48x84的LCD也就是說共有4032個pixel,每一個Pixel都會像下圖一樣排好各有各的地址。
水平尋址於垂直尋址又是什麼呢?下方是整個LCD的RAM格式尋址,在垂直的部分為6x8 = 48,而x的部分則為0-83共84剛好對應到了48x84的LCD。
#define NOP 0x00
#define FunSetVE 0x23 //垂直尋址 擴展模式
#define FunSetHE 0x21 //水平尋址 擴展模式
#define FunSetVS 0x22 //垂直尋址 標準模式
#define FunSetHS 0x20 //水平尋址 標準模式
#define DisplayBlack 0x08//空白模式
#define DisplayNormalk 0x0C //正常模式
#define DisplayALL 0x09 //顯示段全開
#define DisplayInverse 0x0D //反轉模式
//CS_LOW
static void StartSPI(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
}
//CS_High
static void StopSPI(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
}
//傳送
static void SPI_Tx(uint8_t data)
{
HAL_SPI_Transmit(&hspi1, &data, 1, 10);
}
//接收
//回傳值為接收到的資料
static uint8_t SPI_Rx(void)
{
uint8_t retVal;
HAL_SPI_Receive(&hspi1, &retVal, 1, 10);
return retVal;
}
void LCD_Writebyte(unsigned char data, unsigned char dc)
{
StartSPI();
if(dc==0)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,RESET); //命令
else
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,SET); //資料
SPI_Tx(data);
StopSPI();
}
void LCD_Init(void)
{
//Reset
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,RESET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,SET);
StartSPI();
HAL_Delay(1);
StopSPI();
HAL_Delay(1);
LCD_Writebyte(FunSetHE, 0);
LCD_Writebyte(0xBD,0);
LCD_Writebyte(0x13,0);
LCD_Writebyte(0x13,0);
LCD_Writebyte(FunSetHS, 0);
LCD_Writebyte(DisplayNormalk, 0);
}
void LCD_SetPosition(uint8_t X, uint8_t Y)
{
LCD_Writebyte(0x40 | Y, 0); // column
LCD_Writebyte(0x80 | X, 0); // row
}
void LCD_Clear(void)
{
uint16_t i;
LCD_Writebyte(0x0c, 0);
LCD_Writebyte(0x80, 0);
for (i = 0; i < 504; i ++)
{
LCD_Writebyte(0, 1);
}
}
看了那麼多函式可能還不太懂如何去將字體顯示在LCD上方,下方這張圖可以搭配看可能會比較好理解,假設希望產生下方英文:
while (1)
{
HAL_GPIO
LCD_Clear();
LCD_Writebyte(0x02, 1);
LCD_Writebyte(0x02, 1);
LCD_Writebyte(0x02, 1);
LCD_Writebyte(0x02, 1);
LCD_Writebyte(0xFE, 1);
LCD_SetPosition(8,0);
LCD_Writebyte(0x82, 1);
LCD_Writebyte(0x82, 1);
LCD_Writebyte(0xFE, 1);
LCD_Writebyte(0x82, 1);
LCD_Writebyte(0x82, 1);
LCD_SetPosition(15,0);
LCD_Writebyte(0xF0, 1);
LCD_Writebyte(0x48, 1);
LCD_Writebyte(0x44, 1);
LCD_Writebyte(0x48, 1);
LCD_Writebyte(0xF0, 1);
HAL_Delay(500);
}
上方只是為了好理解如何將文字顯在在LCD上,網路上有些軟體可以直接提取對應的位置,就不用這麼麻煩一個一個去寫,可以直接透過[]數組的方式去顯示就可以了~