---
# System prepended metadata

title: SPI_ILI9341
tags: [嵌入式]

---

# 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. 更換背景色**
![3659_0](https://hackmd.io/_uploads/B1k0cjp7T.jpg)

![3660_0](https://hackmd.io/_uploads/HkECqjpmp.jpg)


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


---

**2. 圈圈叉叉**
![3658_0](https://hackmd.io/_uploads/r1vxso6Xp.jpg)

>**結論**
>先初始化繪製九宮格，
>(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
:::
