# STM32 Code Examples

## โค้ดตัวอย่างที่ 1 PWM-based RGB LED Dimming

ตัวอย่างนี้สาธิตการสร้างสัญญาณ **PWM** แบบ 3 ช่องเอาต์พุต ความถี่คงที่ เช่น **500Hz** โดยใช้คลาส `pwmio`  สัญญาณ **PWM** นี้ จะถูกนำไปใช้ในการปรับความสว่างของ **RGB LED (active-low, common anode)** และได้เลือกใช้ขา **A0 / PA00,  A1 / PA01, A2 / PA02** ตามลำดับ สำหรับบอร์ด **STM32F411CE BlackPill**&#x20;

เมื่อทดสอบการทำงานของโค้ด จะเห็นว่า โมดูล **RGB LED** จะค่อย ๆ สว่างขึ้นและดับลง เลือกสี **(Red, Green, Blue)** ไปตามลำดับ&#x20;

```python
import time
import board
import math
import pwmio

###########################################################
class PWMArray:
    def __init__(self,pwm_objects):
        self.pwm_objects = pwm_objects
    def __iter__(self):
        self.index = 0
        return self
    def __next__(self):
        current = self.index
        self.index = (self.index+1) % len(pwm_objects)
        return pwm_objects[current]
###########################################################

led_pins = [board.A0, board.A1, board.A2]
pwm_objects = [
    pwmio.PWMOut(pin=led_pin,duty_cycle=65535,frequency=500)
    for led_pin in led_pins ]
# create an iterator for the list of three PWMOut objects
pwm_iter = iter(PWMArray(pwm_objects))

# create a table of (N+1) sine-wave values
N=128
sine_int = lambda i: int(65535*(1-math.sin(math.pi*i/N)))
values = [sine_int(i) for i in range(N+1)]

try:
    level = 0 # 0..N
    pwm = next(pwm_iter) # select the first PWM output
    t = int(1000*time.monotonic()) # time in msec
    while True:
        now = int(1000*time.monotonic()) # time in msec
        if now - t < 15:
            continue
        t = now # update timestamp
        pwm.duty_cycle = values[level]
        if level == N:
            level = 0
            pwm = next(pwm_iter) # select next PWM output 
        else:
            level += 1
except KeyboardInterrupt:
    pass
for pwm in pwm_objects:
    pwm.deinit()
print('Done')
```

![รูปภาพ: ตัวอย่างการต่อวงจรสำหรับโมดูล RGB LED](https://969412697-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MIHfYo9IV3uTFm2tkDn%2F-MQ5SOXfozDnM7rEUfoU%2F-MQ5UWA9-7C420lPSLiw%2Fcircuitpython_stm32_rgb_led_demo.png?alt=media\&token=d03bc677-fddd-4a1c-b30c-17b7977aaa18)

## โค้ดตัวอย่างที่ 2: RGB LED + Push Button

ตัวอย่างนี้สาธิตการตรวจสอบการกดปุ่มจำนวน 1 ปุ่ม เมื่อมีการกดปุ่มแต่ละครั้ง จะทำให้ **RGB LED** เปลี่ยนสีไปตามลำดับ วงจรปุ่มกดภายนอกที่ได้นำมาต่อเพิ่มนั้นรับอินพุตแบบดิจิทัลที่ขา **B8 / PB08** และขาเอาต์พุตสำหรับ **RGB LED (active-low, common anode)** คือ **A0 / PA00,  A1 / PA01, A2 / PA02** ตามลำดับ

คำสั่งที่ใช้สำหรับ **Digital I/O** มาจากไลบรารี `digitalio` ([**API**](https://circuitpython.readthedocs.io/en/latest/shared-bindings/digitalio/))

```python
import time
import board
import digitalio

button_pin = board.B8
button = digitalio.DigitalInOut(button_pin)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP

led_pins = [board.A0, board.A1, board.A2]
leds = [ digitalio.DigitalInOut(pin) for pin in led_pins]
for led in leds:
    led.direction =  digitalio.Direction.OUTPUT
    led.drive_mode = digitalio.DriveMode.PUSH_PULL
    led.value = True

try:
    index = 0
    while True:
        if button.value == 0: # button pressed
            while button.value != 1: # wait until released
                pass
            leds[index].value = True
            index = (index+1) % len(leds)
            leds[index].value = False
        time.sleep(0.05)
except KeyboardInterrupt:
    pass
button.deinit()
for led in leds:
    led.value = True
    led.deinit()
print('Done')

```

![รูปภาพ: ตัวอย่างการต่อวงจรสำหรับโมดูล RGB LED และ Push Button](https://969412697-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MIHfYo9IV3uTFm2tkDn%2F-MQ5gt-LCeSPfIPRKDtG%2F-MQ5hjj3RahqCA0lvxEG%2Fcircuitpython_stm32_rgb_led_button.png?alt=media\&token=1b97d25f-a223-4493-9d60-520b36c73d43)

## โค้ดตัวอย่างที่ 3: PCF8574 I/O Expander (Output)

ตัวอย่างนี้สาธิตการใช้งานโมดูล **PCF8574 I/O Expander** ขนาด 8 บิต โดยใช้ในโหมดเอาต์พุตทั้ง 8 ขา และใช้ควบคุมสถานะลอจิกของ **LED Bar** **(active-low, common-anode)** ที่มีทั้งหมด 8 ดวง

โมดูลนี้ใช้ไอซี **PCF8574** ที่เชื่อมต่อข้อมูลด้วยวิธีบัส **I2C (default address 0x20)** ดังนั้นเราจะใช้คำสั่งจากไลบรารี `busio`  ([**API**](https://circuitpython.readthedocs.io/en/latest/shared-bindings/busio/))

พฤติกรรมการทำงานของโค้ดตัวอย่างมีดังนี้ เริ่มต้นให้ **LED** หนึ่งดวงอยู่ในสถานะ **ON** (ตรงกับตำแหน่ง **LSB**) จากนั้นตำแหน่งของ **LED** ที่อยู่ในสถานะ **ON** จะเลื่อนไปทางซ้ายทีละตำแหน่ง เมื่อไปจนถึงซ้ายสุด (ตรงกับตำแหน่ง **MSB**) ให้เลื่อนกลับไปทางขวา และทำในลักษณะนี้ซ้ำไปเรื่อย ๆ&#x20;

```python
import time
import busio
from board import SCL, SDA

PCF8574_ADDR = 0x20
i2c = busio.I2C(SCL, SDA,frequency=100000) # 100kHz speed

# attempt to lock the i2c bus
while not i2c.try_lock():
    pass
addr_found = []
addr_found = i2c.scan()
print("I2C found:", [hex(addr) for addr in addr_found])
i2c.unlock()


if PCF8574_ADDR not in addr_found:
    print('PCF8574 not found')

shift_left  = lambda x: ((x << 1) | (x >> 7)) & 0xff
shift_right = lambda x: ((x >> 1) | (x << 7)) & 0xff

try:
    data = 0x01
    direction = 1 # shift left
    buf = bytearray(1)
    while True:
        if i2c.try_lock():
            buf[0] = data ^ 0xff # inverting output
            i2c.writeto(PCF8574_ADDR, buffer=buf,start=0,end=1)
            i2c.unlock()
        if data == 0x80:   # MSB is 1.
            direction = 0 # change direction to shift-right
        elif data == 0x01: # LSB is 1.
            direction = 1  # change direction to shift-left
        if direction == 1:
            data = shift_left(data)
        else:
            data = shift_right(data)
        time.sleep(0.1)
except KeyboardInterrupt:
    pass
i2c.deinit()
```

หรือเราอาจใช้คำสั่งของไลบรารี `adafruit_bus_device` ([**API**](ttps://circuitpython.readthedocs.io/projects/busdevice/en/latest/api.html#adafruit-bus-device-i2c-device-i2c-bus-device)) สำหรับ **I2C Device** จาก **Adafruit Library Bundle** ก็ได้ดังนี้

```python
import time
import busio
from board import *
from adafruit_bus_device.i2c_device import I2CDevice

PCF8574_ADDR = 0x20
i2c = busio.I2C(SCL, SDA, frequency=100000) 
dev = I2CDevice(i2c, PCF8574_ADDR)

shift_left  = lambda x: ((x << 1) | (x >> 7)) & 0xff
shift_right = lambda x: ((x >> 1) | (x << 7)) & 0xff

try:
    data = 0x01
    direction = 1 # shift left
    buf = bytearray(1)
    while True:
        buf[0] = data ^ 0xff # inverting output
        with dev:
            dev.write(buf)
        if data == 0x80:   # MSB is 1.
            direction = 0  # change direction to shift-right
        elif data == 0x01: # LSB is 1.
            direction = 1  # change direction to shift-left
        if direction == 1:
            data = shift_left(data)
        else:
            data = shift_right(data)
        time.sleep(0.1)
except KeyboardInterrupt:
    pass
i2c.deinit()
```

![รูปภาพ: การต่อวงจรทดลองบนเบรดบอร์ดสำหรับ PCF8574 + LED Bar](https://969412697-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MIHfYo9IV3uTFm2tkDn%2F-MQ6Uy_GIKcxCsByOAWv%2F-MQ6VFR8sLZZbvsYfeSh%2Fcircuitpython_stm32_pcf8574_leds.png?alt=media\&token=b06aa699-0c97-4e64-afd7-b821501ffdd4)

## โค้ดตัวอย่างที่ 4: PCF8574 I/O Expander (Input)

ตัวอย่างนี้สาธิตการใช้โมดูล **PCF8574** ตรวจสอบสถานะของปุ่มกดภายนอก (**Push Buttons**) เช่น จำนวน 3 ปุ่ม ซึ่งทำงานแบบ **Active-Low** และรับอินพุตที่ขา **P0, P1, P2** ตามลำดับของไอซี **PCF8474**

```python
import time
import busio
from board import *
from adafruit_bus_device.i2c_device import I2CDevice

PCF8574_ADDR = 0x20
i2c = busio.I2C(SCL, SDA, frequency=100000) 
dev = I2CDevice(i2c, PCF8574_ADDR)

STATES = ['LOW','HIGH']
try:
    buf = bytearray(1)
    t = int(1000*time.monotonic()) # time in msec
    last_value = 0xff
    while True: # press Ctrl+C to stop
        now = int(1000*time.monotonic()) # time in msec
        if now - t < 50:
            continue
        # update every 50 msec
        t = now
        buf[0] = 0xff # must be 1's for input checking
        with dev:
            dev.readinto(buf)
        value  = buf[0]
        change = value ^ last_value
        if change != 0: # state change detected
            if change & 1 != 0: # SW1 
                print('SW1:', STATES[value & 1])
            if change & 2 != 0: # SW2
                print('SW2:', STATES[value>>1 & 1])
            if change & 4 != 0: # SW3
                print('SW3:', STATES[value>>2 & 1])
        last_value = value
except KeyboardInterrupt:
    pass
i2c.deinit()
print('Done')
```

![รูปภาพ: การต่อวงจรทดลองบนเบรดบอร์ดสำหรับ PCF8574 + Push Buttons](https://969412697-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MIHfYo9IV3uTFm2tkDn%2F-MQ6W4HWOFbB1dYFs9Zb%2F-MQ6W8hz3t4Pj1cFtID4%2Fcircuitpython_stm32_pcf8574_buttons.png?alt=media\&token=6034c9e1-fdbf-4d2d-8d7d-ac429abc4912)

{% hint style="info" %}
**เผยแพร่ภายใต้ลิขสิทธิ์**\
**Attribution-ShareAlike 4.0 International (**[**CC BY-SA 4.0**](https://creativecommons.org/licenses/by-sa/4.0/)**)**
{% endhint %}
