# User Switch

## Lab 2: User Switch — อ่านปุ่มกด & Debounce

#### วัตถุประสงค์

* **GPIO Input**: อ่านค่าจาก Digital Input
* **Debounce**: ป้องกันการอ่านค่าผิดพลาดจาก Contact Bounce
* **State Machine**: เปลี่ยน LED state เมื่อกดปุ่ม

#### จะได้เรียนรู้อะไร?

* **GPIO Read**: Cy\_GPIO\_Read()
* **Active LOW**: ปุ่มกดลง = 0
* **Debounce Pattern**: Software debounce
* **Static Variables**: เก็บ state ระหว่าง function calls

#### **Hardware Information**

| Component           | Port/Pin          | หมายเหตุ                |
| ------------------- | ----------------- | ----------------------- |
| User LED1           | CYBSP\_USER\_LED1 | Active HIGH (HIGH = ON) |
| User Button 1 (SW2) | CYBSP\_USER\_BTN1 | Active LOW (กดลง = 0)   |
| User Button 2 (SW4) | CYBSP\_USER\_BTN2 | Active LOW (กดลง = 0)   |

***

### Lab 2.1 : อ่านปุ่มกดแบบ Polling

#### **เพิ่ม Button Macros:**

```c
/* เพิ่มหลัง LED macros */

/* Button Configuration */
#define USER_BTN_PORT       CYBSP_USER_BTN1_PORT
#define USER_BTN_PIN        CYBSP_USER_BTN1_PIN

/* Button Read Macro - Active LOW */
#define IS_BUTTON_PRESSED() (Cy_GPIO_Read(USER_BTN_PORT, USER_BTN_PIN) == 0)
```

#### **แก้ไขฟังก์ชั่น Main :**

```c
int main(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;
    
    /* Initialize */
    result = cybsp_init();
    if (CY_RSLT_SUCCESS != result) { handle_app_error(); }

    __enable_irq();
    init_retarget_io();

    printf("\x1b[2J\x1b[;H");
    printf("*** PSoC Edge: Button Demo ***\r\n");
    printf("Press SW2 to toggle LED\r\n\n");

    Cy_SysEnableCM55(MXCM55, CM55_APP_BOOT_ADDR, CM55_BOOT_WAIT_TIME_USEC);

    /* Main loop */
    for(;;)
    {
        /* ตรวจสอบปุ่ม */
        if (IS_BUTTON_PRESSED())
        {
            printf("Button pressed!\r\n");
        } else
        {
            printf("Button NOT pressed!\r\n");
        }

        /* หน่วงเวลาเล็กน้อยเพื่อลด CPU load */
        Cy_SysLib_Delay(10);
    }
}
```

***

### Lab 2.2 : Debounce แบบง่าย (Edge Detection)

**WHY: ทำไมต้องรู้?**

* **ปัญหา:** ปุ่มกดมีสัญญาณกระเด้ง (bouncing) ทำให้ detect หลายครั้ง (5-10 ครั้ง!)
* **ประโยชน์:** อ่านค่าปุ่มได้ถูกต้อง, ไม่มี false triggers
* **Hardware:** Mechanical switch มี contact bounce 10-50ms

```
ปุ่มกดจริงๆ:     ___████████████___
                 ↑ กด        ↑ ปล่อย

สัญญาณที่ MCU เห็น: ___█_█_██_█████___
                    ↑ Bouncing!
```

**CAUTION: ข้อควรระวัง**

| ข้อผิดพลาด       | ผลกระทบ               | วิธีป้องกัน              |
| ---------------- | --------------------- | ------------------------ |
| Delay สั้นเกินไป | ยัง bounce อยู่       | ใช้ 20-50ms              |
| Delay นานเกินไป  | ผู้ใช้รู้สึกว่า laggy | ไม่ควรเกิน 100ms         |
| Debounce ใน ISR  | Block interrupt นาน   | ใช้ timer-based debounce |

#### เพิ่ม debouncing และ Macro functions

```c
#define DEBOUNCE_DELAY_MS           (50U)

/* LED Control Macros */
#define LED_ON()                    Cy_GPIO_Clr(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)
#define LED_OFF()                   Cy_GPIO_Set(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)
#define LED_TOGGLE()                Cy_GPIO_Inv(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN)

/*******************************************************************************
* Function Prototypes
*******************************************************************************/
static bool read_button_with_debounce(void);

/*******************************************************************************
* Global Variables
*******************************************************************************/
static uint32_t button_press_count = 0;
```

#### สร้างฟังก์ชัน Debounce

{% hint style="info" %}
**ด้วยเทคนิค Delay-based Debounce**:

1. ตรวจจับ rising edge (ปุ่มถูกกด)
2. รอ 50ms ด้วย `Cy_SysLib_Delay()`
3. อ่านค่าปุ่มอีกครั้งเพื่อยืนยัน
4. ถ้ายังกดอยู่ = valid press
   {% endhint %}

```c
/*******************************************************************************
* Function Name: read_button_with_debounce
********************************************************************************
* Summary:
*   อ่านค่าปุ่มพร้อม debounce เพื่อป้องกันการ bounce
*
* Parameters:
*   None
*
* Return:
*   true ถ้าปุ่มถูกกด (และ debounced แล้ว), false ถ้าไม่ได้กด
*
* Note:
*   ใช้ static variables เพื่อเก็บ state ระหว่าง calls
*******************************************************************************/
static bool read_button_with_debounce(void)
{
    static bool last_state = false;

    bool current_state = IS_BUTTON_PRESSED();

    /* Detect rising edge (button just pressed) */
    if (current_state && !last_state) {
        /* Wait for debounce period */
        Cy_SysLib_Delay(DEBOUNCE_DELAY_MS);

        /* Re-read to confirm button is still pressed */
        if (IS_BUTTON_PRESSED()) {
            last_state = true;
            return true;  /* Valid press detected */
        }
    }

    /* Update state when button is released */
    if (!current_state) {
        last_state = false;
    }

    return false;
}

```

#### แก้ไข Main Loop

```c
int main(void)
{
    cy_rslt_t result = CY_RSLT_SUCCESS;

    /* Initialize */
    result = cybsp_init();
    if (CY_RSLT_SUCCESS != result) { handle_app_error(); }

    __enable_irq();
    init_retarget_io();

    printf("\x1b[2J\x1b[;H");
    printf("*** PSoC Edge: Button Demo ***\r\n");
    printf("Press SW2 to toggle LED\r\n\n");

    Cy_SysEnableCM55(MXCM55, CM55_APP_BOOT_ADDR, CM55_BOOT_WAIT_TIME_USEC);

    /* Main loop */
    for(;;)
    {
       if (read_button_with_debounce()) {
          button_press_count++;  // เพิ่ม counter
          LED_TOGGLE();
          printf("Button pressed! Count: %lu, LED toggled.\r\n",
                  (unsigned long)button_press_count);
    }
    Cy_SysLib_Delay(10);
}
}
```

#### Debounce Flowchart

<figure><img src="/files/dNP5RvVkxxxVteVYrvP6" alt=""><figcaption></figcaption></figure>

***

### ทำความเข้าใจการเรียกใช้ Static Variables

```c
/* static ภายใน function = เก็บค่าระหว่าง calls */

void example(void)
{
    static int count = 0;  /* Initialize ครั้งเดียวตอนเริ่มโปรแกรม */
    count++;
    printf("Called %d times\n", count);
}

/* เรียก example() 3 ครั้ง:
 * Called 1 times
 * Called 2 times
 * Called 3 times
 */

/* ถ้าไม่ใช้ static: */
void bad_example(void)
{
    int count = 0;  /* Initialize ทุกครั้งที่เรียก! */
    count++;
    printf("Called %d times\n", count);
}

/* เรียก bad_example() 3 ครั้ง:
 * Called 1 times
 * Called 1 times
 * Called 1 times
 */
```

#### ✍️ Exercise

1. **Press Counter** : นับจำนวนครั้งที่กดปุ่มและแสดงผล

{% hint style="info" %}
**Hint**

ประกาศตัวแปร `uint32_t press_count = 0;` แล้วทำการเพิ่มค่า `press_count++;` ในลูป
{% endhint %}

2. **Long Press Detection** : ตรวจจับการกดค้าง (> 1 วินาที) และทำ action แตกต่าง

{% hint style="info" %}
**Hint**

เรียกใช้ฟังก์ชันนี้

```c
/* Long Press Detection using elapsed_time counter */
bool read_long_press(uint32_t hold_time_ms, uint32_t elapsed_time)
{
    static uint32_t press_start = 0;
    static bool counting = false;

    if (IS_BUTTON_PRESSED())
    {
        if (!counting)
        {
            counting = true;
            press_start = elapsed_time;
        }
        else if ((elapsed_time - press_start) >= hold_time_ms)
        {
            counting = false;  /* Reset for next detection */
            return true;       /* Long press detected! */
        }
    }
    else
    {
        counting = false;
    }

    return false;
}
```

{% endhint %}

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aic-eec.com/interfacing-with-infineon-psoc-tm-edge/basic-mcu-interfacing/workshops/user-switch.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
