# MicroPython操作每一顆LED

## 輪流點亮每一顆LED

micro:bit除了可以利用show和scroll來操作LED矩陣之外，每一個LED也都有自己的x, y座標，透過這些x, y座標即可獨立地操作每一顆LED的亮度，而操作這些個別的LED的指令是set\_pixel函數。請練習以下的程式：

```python
from microbit import *

for x in range(5):
    for y in range(5):
        display.set_pixel(x, y, 9)
        sleep(200)
```

在上面的程式中會從左上角的LED開始，由上而下，由左而右依序點亮每一顆LED，直到點亮全部的LED為止。請再練習以下的程式，比較看看和上一個程式執行結果有何不同：

```python
from microbit import *

for y in range(5):
    for x in range(5):
        display.set_pixel(x, y, 9)
        sleep(200)
```

仔細觀察上面兩個程式的差異，相信同學們對於LED矩陣的x, y座標就能夠有更加清楚的理解了。那麼，接下來，如果我們不想要填滿整個LED矩陣，而只是想讓那個LED在畫面上移動呢？答案是只要適時地加入display.clear()指令清除畫面即可，程式如下：

```python
from microbit import *

while True:
    for x in range(5):
        for y in range(5):
            display.clear()
            display.set_pixel(x, y, 9)
            sleep(200)
```

## 為每一顆LED編個別的號碼

如果不使用display.clear()的話，為了清除上一個LED，需要使用另外一個變數來記錄上一個LED的位置，為了避免記錄2個數字，我們只使用1個數字來代替每一個LED，實際要顯示時再進行數字的轉換：

```
from microbit import *
counter, old = 0, 0
while True:
    x = old % 5
    y = old // 5
    display.set_pixel(x, y, 0)

    x = counter % 5
    y = counter // 5
    display.set_pixel(x, y, 9)
    sleep(200)
    old = counter
    counter = counter + 1
    if counter > 24: 
        counter = 0
```

程式的邏輯是這樣的，把LED矩陣的最左上角那顆LED編號為0，它的右邊的編號是1，再來是2，也就是第一列（其實是第0列）的LED分別是0到4，第二列（其實在內部是第1列）為5到9，依此類推。原有以x, y座標編號的LED如下圖所示：

![](https://2988174335-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LMo8UCGGycRFYs2Gx9M%2F-LeP9NP9CWERV5ZhbEo4%2F-LePApdFpSdFrCX5MR2C%2Fassets_-LMo8UCGGycRFYs2Gx9M_-LPYDF9QukIBT8_OtP8A_-LPYDMdi6LAzkpyGO8EF_2018-10-24_07-16-35.png?alt=media\&token=18e913e5-6c8b-4392-acab-0a7dc1d4d3d1)

我們以單一數字來編號的情形是以下這樣的：

![](https://2988174335-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LMo8UCGGycRFYs2Gx9M%2F-LeP9NP9CWERV5ZhbEo4%2F-LePBGkpEVj6X1jHD7AM%2Fassets_-LMo8UCGGycRFYs2Gx9M_-LP8GW4XStpvUKF18Gvj_-LP8HBx0SCtQeFL4nEzl_2018-10-19_06-19-26.png?alt=media\&token=5e15670e-9031-429b-bb9d-5cd0ccce9c78)

對照兩者之間的差異，意思是在程式內部編號4的那顆LED實際要顯示的時候其座標是(4, 0)，編號5的那顆座標是(1,1)，編號24的那顆是(4, 4)，依此類推。假設要顯示編號是n的LED，則(x, y)座標轉換的公式如下：

$$
x = n % 5 \\
y = n // 5
$$

其中%是取餘數，而//則是取整數的意思。瞭解了上述的原理，相信同學們應該就可以理解上述程式的邏輯了。我們設定了2個變數分別是counter和old，一開始兩個變數都設為0（第2行），每一次要顯示新的LED之前要先把舊的LED關閉（第6行），在顯示了新的LED之後，就把新的LED編號記在old變數之中（第12行），之後再新增counter的內容（第13行）。

不過每一次在顯示LED的時候都要進行一次轉換（第4行到第5行以及第8行和第9行），比較方便的方法是設計一個副程式來專心做這件事，方法如下：

```python
from microbit import *

def setLED(number, value):
    x = number % 5
    y = number // 5
    display.set_pixel(x, y, value)
    
counter, old = 0, 0
while True:
    setLED(old, 0)
    setLED(counter, 9)
    sleep(200)
    old = counter
    counter = counter + 1
    if counter > 24: 
        counter = 0
```

雖然程式的行數看起來差不多，但是有了這個副程式setLED(number, value)，在主程式的邏輯就會更容易理解。有了這個編號的方式，就可以使用程式讓LED依自訂的順序點亮，例如要倒過來點亮（移動）也只要做些小改變就好了：

```python
from microbit import *

def setLED(number, value):
    x = number % 5
    y = number // 5
    display.set_pixel(x, y, value)
    
counter, old = 24, 24
while True:
    setLED(old, 0)
    setLED(counter, 9)
    sleep(200)
    old = counter
    counter = counter - 1
    if counter < 0: 
        counter = 24
```

## 電 子輪盤

以下是電子輪盤的程式碼：

```
from microbit import *

def setLED(number, value):
    x = number % 5
    y = number // 5
    display.set_pixel(x, y, value)

seq = [0, 1, 2, 3, 4, 9, 14, 19, 24, 23, 22, 21, 20, 15, 10, 5]
counter, old = 0, 0
while True:
    setLED(seq[old], 0)
    setLED(seq[counter], 9)
    sleep(100)
    old = counter
    counter = counter + 1
    if counter >= len(seq): 
        counter = 0
```

以下是正轉加上反轉的程式範例，不同於上面程式，這次我們利用for迴圈的方式來解決這個問題：

```python
from microbit import *

def setLED(number, value):
    x = number % 5
    y = number // 5
    display.set_pixel(x, y, value)

seq = [0, 1, 2, 3, 4, 9, 14, 19, 24, 23, 22, 21, 20, 15, 10, 5]
old = seq[0]
while True:
    for counter in seq:
        setLED(old, 0)
        setLED(counter, 9)
        sleep(100)
        old = counter
    for counter in reversed(seq):
        setLED(old, 0)
        setLED(counter, 9)
        sleep(100)
        old = counter
```

{% hint style="info" %}
其實上面這個程式的兩個內迴圈的內容幾乎是一樣的，但是old和counter這兩個變數所代表的意義是不一樣的，同學們可以看得出來嗎？
{% endhint %}

透過以上的顯示能力，接下來就可以搭配按鈕玩電子輪盤的遊戲了。
