iT邦幫忙

0

STM32-11 SPI Nokia 5110 LCD 實作

  • 分享至 

  • xImage
  •  

Nokia 5110 LCD 介紹

剛好手邊有塊Nokia 5110 LCD 就拿它來做測試吧~雖然這塊LCD年份久遠了,但還是很適合來做些小東西玩玩!
https://ithelp.ithome.com.tw/upload/images/20220316/20146325Px76bqYoBu.png
先介紹一下這塊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的指令有哪些~
https://ithelp.ithome.com.tw/upload/images/20220316/20146325LoOBH4ZG0p.png
可以看到其中功能設置、寫指令、設置RAM XY位置等等,可以先將會使用到的函數先寫出來,方便之後去使用。

  1. Function Set (功能設置) : 在D/C設為0,後續填入00100 PD V H,PD為0時表示選中1表示失能,V為0則代表水平尋址1則代表垂直尋址,H為0是使用標準指令及1則是擴展指令及。
  2. Write data (寫指令) : 在D/C設為1,後續填入要寫入的8個bit,用途為寫資料到RAM上。
  3. Display control (顯示控制) : D/C設置為0,後續填入 00001 D 0 E,用途為控制顯示模式
D E Mode
0 0 顯示空白
1 0 普通模式
0 1 打開所有顯示
1 1 反轉
  1. Set Y address of RAM (設置RAM的Y位置) : D/C設置為0,後續填入01000 Y2 Y1 Y0,同時(0≤Y≤5)。
  2. Set Y address of RAM (設置RAM的Y位置) : D/C設置為0,後續填入1 X6 X5 X4 X3 X2 X1 X0,同時(0≤X≤83)。

上方功能中的RAM是什麼?可以把它想成顯示pixel的地址,這一塊是48x84的LCD也就是說共有4032個pixel,每一個Pixel都會像下圖一樣排好各有各的地址。
https://ithelp.ithome.com.tw/upload/images/20220316/20146325avncHUVZzp.png
水平尋址於垂直尋址又是什麼呢?下方是整個LCD的RAM格式尋址,在垂直的部分為6x8 = 48,而x的部分則為0-83共84剛好對應到了48x84的LCD。
https://ithelp.ithome.com.tw/upload/images/20220316/20146325zChlARGDyp.png

  1. 垂直尋址 : 對應上方的六大格編號為0-5垂直往下接著換下一行接續,所以上方才會說Y必須小於等於5 (0b00000101)
    https://ithelp.ithome.com.tw/upload/images/20220316/20146325hpR8pwvv3G.png
  2. 水平尋址 : 由縱向改為橫向地址編排, 0-83接著換下一列繼續接續,也就是X小於等於83 (0b01010011)
    https://ithelp.ithome.com.tw/upload/images/20220316/20146325v74f4w8B0R.png
    上述圖片來源:手冊

IOC檔設置

  1. Ioc檔設置:先點選左側的Connectivity可以在裡面找到SPI1、SPI2、SPI3,會看到SPI1是禁止的,原因是因為板載LED將PA5設置為Output,取消PA5就可以選擇了選擇最上方的Reset_State。
    https://ithelp.ithome.com.tw/upload/images/20220316/201463250QFZdae0PV.png
  2. 接著在上方模式的部分選擇Full-Duplex Master(全雙工Master),讓STM32做為Master。下方NSS的部分選擇Disable,因為我透過軟體方式去控制CS腳位。
    https://ithelp.ithome.com.tw/upload/images/20220316/20146325rf4DfvFhC3.png
  3. 下方詳細配置中可以點選GPIO Settings ,會清楚地看到MISO MOSI SCK腳位在哪,將LCD對應的接上去即可,但由於剛剛選擇透過軟體控制CS,所以我們要將原先的CS(PB6)腳位選擇為OutPut。
    https://ithelp.ithome.com.tw/upload/images/20220316/20146325W2pdLO0jfq.png
    https://ithelp.ithome.com.tw/upload/images/20220316/20146325315uN5p6uO.png
  4. 接著點選回Parameter Settings,當中將Data Size改為8bit。下方預分頻係數可以依照傳輸鮑率去做選擇,這邊我選為Prescaler 64 Baud Rate則是1.25MBits/s。再往下會看到CPOL與CPHA設置的選項,這部分可以參考前一篇介紹去做設置。如果要使用中斷方式的話記得要到NVIC當中將SPI中斷打開!
    https://ithelp.ithome.com.tw/upload/images/20220316/201463252FvcqHSW58.png
  5. 接下來已經將LCD上剩下RST、BLC、DIN我們還沒有接上,這部分可以依照個人選擇腳位,如果有其他設備不要占用到功能腳位即可,這邊我選擇PB13-15去做這三條線的連接。
    https://ithelp.ithome.com.tw/upload/images/20220316/20146325KEWgOyr1VP.png

實作程式碼

  1. 定義SPI指令
#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 //反轉模式
  1. 定義CS_LOW與CS_High來做位時序的啟動於停止
//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);
}
  1. 接著我們可以將HAL_SPI的庫寫成一次傳送與接收1個byte,方便之後使用~
//傳送
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;
}
  1. 對LCD寫入資料
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();
}
  1. 初始化LCD
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);
}
  1. 設置Xy起始位置
void LCD_SetPosition(uint8_t X, uint8_t Y)
{
	LCD_Writebyte(0x40 | Y, 0);		// column
	LCD_Writebyte(0x80 | X, 0);    // row
}
  1. 清除LCD
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上方,下方這張圖可以搭配看可能會比較好理解,假設希望產生下方英文:
https://ithelp.ithome.com.tw/upload/images/20220316/20146325n3Vue0D1QF.png

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);
}

https://ithelp.ithome.com.tw/upload/images/20220316/20146325SInrIhmwmK.jpg
上方只是為了好理解如何將文字顯在在LCD上,網路上有些軟體可以直接提取對應的位置,就不用這麼麻煩一個一個去寫,可以直接透過[]數組的方式去顯示就可以了~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言