# SPI_ILI9341
#### 組員: A1105129 吳祥毅 M1115114 楊皓翔
#### 指導老師:林宏益
---
### 一、實驗目的
SPI是一種微控制器常用的通訊界面,常用於顯示屏幕和感測器,本次實驗使用Raspberry Pi和ILI9341搭配實踐顯示和觸控功能。
### 二、實驗原理
* SPI是一種一主多從的介面,MISO、MOSI作為雙向資料傳輸,SCLK作為同步時鐘線,SS作為選擇從屬裝置(每個從屬裝置都有一條獨立的SS線,且只有SS線是獨立的)。
* SPI支持全雙工通訊,資料可以同時在兩個方向上傳輸。
* 在多從機的情況下,需要更多的引腳,不如I2C那樣節省線路。
* ILI9341是一種低功耗TFT LCD,具320x240像素解析度,支持觸控功能。
### 三、實驗材料
1. 樹莓派(Raspberry Pi 1)
2. UART模組
3. ILI9341
### 四、實驗步驟
**1. 背景色更換**
```python=
from PIL import Image, ImageDraw, ImageFont
import RPi.GPIO as GPIO
import spidev
from time import sleep
from lib_tft24T import TFT24T
# Raspberry Pi配置
DC = 24
RST = 25
LED = 18
PEN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
spi = spidev.SpiDev()
TFT = TFT24T(spi, GPIO, landscape=True)
TFT.initLCD(DC, RST, LED)
TFT.backlite(True)
TFT.initTOUCH(pen=PEN, ce=1, spi_speed=100000)
draw = TFT.draw()
colors = ["red", "green", "blue", "yellow", "purple"]
color_index = 0
draw.rectangle((0, 0, 240, 320), fill=colors[color_index])
TFT.display()
while True:
if TFT.penDown():
color_index = (color_index + 1) % len(colors)
draw.rectangle((0, 0, 240, 320), fill=colors[color_index])
TFT.display()
sleep(0.3)
sleep(0.1)
```
**2. 圈圈叉叉**
```python=
import RPi.GPIO as GPIO
import spidev
from time import sleep
from lib_tft24T import TFT24T
DC = 24
RST = 25
LED = 18
PEN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
spi = spidev.SpiDev()
TFT = TFT24T(spi, GPIO, landscape=True)
TFT.initLCD(DC, RST, LED)
TFT.backlite(True)
TFT.initTOUCH(pen=PEN, ce=1, spi_speed=100000)
draw = TFT.draw()
board = [" "] * 9
current_player = "X"
def draw_board():
draw.rectangle((0, 0, 240, 240), fill="black")
for i in range(3):
for j in range(3):
x = j * 80
y = i * 80
draw.rectangle((x, y, x + 80, y + 80), outline="white", width=2)
if board[i * 3 + j] == "X":
draw.line((x + 10, y + 10, x + 70, y + 70), fill="red", width=5)
draw.line((x + 70, y + 10, x + 10, y + 70), fill="red", width=5)
elif board[i * 3 + j] == "O":
draw.ellipse((x + 10, y + 10, x + 70, y + 70), outline="blue", >
TFT.display()
draw_board()
def check_win(player):
for i in range(3):
if (board[i * 3] == board[i * 3 + 1] == board[i * 3 + 2] == player or
board[i] == board[i + 3] == board[i + 6] == player):
return True
return (board[0] == board[4] == board[8] == player or
board[2] == board[4] == board[6] == player)
def get_cell(pos):
x, y = pos
if x >= 240 or y >= 240:
return None
cell_index = int(x // 80) + (int(y // 80) * 3)
if 0 <= cell_index < 9:
return cell_index
else:
return None
while True:
if TFT.penDown():
pos = TFT.penPosition()
if pos != [0, 0]:
cell = get_cell(pos)
if cell is not None and board[cell] == " ":
board[cell] = current_player
if check_win(current_player):
print(f"Player {current_player} wins!")
break
current_player = "O" if current_player == "X" else "X"
draw_board()
sleep(0.1)
```
**3. PIN腳選擇**
**BCM pin numbers**
+5 -> +5
GND > GND
CE -> CE0
RESET -> GPIO25
D/C -> GPIO24
SDO/MOSI -> MOSI
SCK -> SCLK
LED -> GPIO18
SDI/MISO -> n/c
t_CLK -> SCLK
t_CS -> CE1
t_DIN/MOSI -> MOSI
t_DO/MISO -> MISO
t_IRQ -> GPIO17
>**解釋**
D/C用於指示樹莓派發送的數據是控制命令還是顯示數據,而SDO/MOSI線用於實際傳輸這些數據。
### 五、實驗結果
**1. 更換背景色**


>**結論**
>
>使用lib_tft24T操作硬體、spidev用於SPI通訊,定義一個顏色陣列,如果偵測到觸摸,顏色的index增加,從而改變顏色。
---
**2. 圈圈叉叉**

>**結論**
>先初始化繪製九宮格,
>(1)定義draw_board的函式繪製 O 和 X 。
>(2)定義check_win檢查是否有同列、同行和對角是否連線判斷勝利。
>(3)定義get_cell檢查點擊位置是否在九宮格內。
---
### 六、實驗討論&心得
在實驗中,我們學習到SPI的通訊方式,並且使用TFT LCD實踐整個專案流程,對SPI的硬體操作建立了基礎,由於顯示端MISO不用傳回資料給樹梅派所以可以空下,讓觸控端的MISO使用即可。
### 七、參考文獻
:::danger
參考文獻 :
* [ILI9341] https://github.com/pcbcrew-org/pcbcrew-raspi-spilcd
:::