---
# System prepended metadata

title: LAB4 SWITCH BUTTON 控制跑馬燈方向
tags: [嵌入式系統]

---

# LAB4 SWITCH BUTTON 控制跑馬燈方向
## demo
<iframe width="560" height="315" src="https://www.youtube.com/embed/SMQRvmecGok?si=tWdpW80_wCcBL8w4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## 電路圖
![HW04_13_電路](https://hackmd.io/_uploads/Hkt2So5y1l.png)

## 程式碼說明
- 本程式有用到課本提供 `switch.h`
- 首先先講到我的跑馬燈，我使用OOP實作
    - 我的UML
        ```mermaid
        classDiagram
            class Light {
                - int* ledPins
                - int LEDcounts
                - int* speeds
                - unsigned char speedPointer
                - unsigned long lastUpdate
                - int currentIndex
                - bool left
                - bool running
                + void update()
                + void nextSpeedStage()
                + void stopOrRun()
                + void moveLeft()
                + void moveRight()
            }
        ```  
    - 接著說明我的函數
        - 首先是移動相關
            ```c++=
            void Light::moveLeft(){
                this->left = true;
            }

            void Light::moveRight(){
                this->left = false;
            }
            ```
        - 暫停與跑
            ```c++=
            void Light::stopOrRun(){
                this->running = !this->running;
            }
            ```
        - 加速減速
            ```c++=
            void Light::nextSpeedStage(){
                this->speedPointer = (this->speedPointer + 1) % 8;
            }
            ```
        - 更新LED
            ```c++=
            void Light::update(){
                unsigned long currentMillis = millis();
                if (running && currentMillis - lastUpdate >= speeds[speedPointer]) {
                    // turn off current LED
                    digitalWrite(ledPins[this->currentIndex], LOW); 
                    if (this->left) {
                        //turn left
                        currentIndex = (this->currentIndex - 1 + LEDcounts) % LEDcounts;
                    } 
                    else {
                        //turn right
                        this->currentIndex = (this->currentIndex + 1) % LEDcounts; 
                    }
                    // turn on new LED
                    digitalWrite(ledPins[this->currentIndex], HIGH); 
                    lastUpdate = currentMillis;
                }
            }
            ```
## 程式碼
- `main.ino`
    ```C++=
    #include <switch.h>
    #include "light.h"

    #define LED_COUNT 8
    #define BUTTON_LEFT 33
    #define BUTTON_RIGHT 25
    #define BUTTON_STOP 26
    #define BUTTON_SPEED 27

    int ledPins[LED_COUNT] = {23, 22, 21, 19, 18, 17, 16, 4};
    int speeds[8]     = {1000,875,750,625,500,375,250,125}; 

    Switch leftSw(BUTTON_LEFT, LOW, true);
    Switch rightSw(BUTTON_RIGHT, LOW, true);
    Switch stopSw(BUTTON_STOP, LOW, true);
    Switch speedSw(BUTTON_SPEED, LOW, true);
    Light  light  (ledPins, LED_COUNT, speeds);


    void setup() {
      // 設定 LED 腳位為輸出
      for (int i = 0; i < LED_COUNT; i++) {
        pinMode(ledPins[i], OUTPUT);
        digitalWrite(ledPins[i], LOW);
      }

      // 設定按鈕腳位為輸入
      pinMode(BUTTON_LEFT, INPUT_PULLUP);
      pinMode(BUTTON_RIGHT, INPUT_PULLUP);
      pinMode(BUTTON_STOP, INPUT_PULLUP);
      pinMode(BUTTON_SPEED, INPUT_PULLUP);
    }

    void loop() {
      switch (leftSw.check()){
        case Switch::RELEASED_FROM_PRESS:
        case Switch::PRESSING:
          light.moveLeft();
      }
      switch (rightSw.check()){
        case Switch::RELEASED_FROM_PRESS:
        case Switch::PRESSING:
          light.moveRight();
      }
      switch (stopSw.check()){
        case Switch::RELEASED_FROM_PRESS:
          light.stopOrRun();
      }
      switch (speedSw.check()){
        case Switch::RELEASED_FROM_PRESS:
          light.nextSpeedStage();
      }

      light.update();
    }
    ```
- light.cpp
    ```c++=
    #include "light.h"
    #include <Arduino.h>

    Light::Light(int ledPins[], int LEDcounts, int speeds[]){
        this->ledPins = ledPins;
        this->LEDcounts = LEDcounts;
        this->speeds = speeds;
        this->speedPointer = 0;
        this->lastUpdate = 0;
    }

    Light::~Light(){}

    void Light::stopOrRun(){
        this->running = !this->running;
    }

    void Light::moveLeft(){
        this->left = true;
    }

    void Light::moveRight(){
        this->left = false;
    }

    void Light::nextSpeedStage(){
        this->speedPointer = (this->speedPointer + 1) % 8;
    }

    void Light::update(){
        unsigned long currentMillis = millis();
        if (running && currentMillis - lastUpdate >= speeds[speedPointer]) {
            // turn off current LED
            digitalWrite(ledPins[this->currentIndex], LOW); 
            if (this->left) {
                //turn left
                currentIndex = (this->currentIndex - 1 + LEDcounts) % LEDcounts;
            } 
            else {
                //turn right
                this->currentIndex = (this->currentIndex + 1) % LEDcounts; 
            }
            // turn on new LED
            digitalWrite(ledPins[this->currentIndex], HIGH); 
            lastUpdate = currentMillis;
        }
    }
    ```
- light.h
    ```c++=
    #ifndef LIGHT_H
    #define LIGHT_H

    class Light
    {
    private:
        int *ledPins;
        int LEDcounts;
        int *speeds;
        unsigned char speedPointer;
        unsigned long lastUpdate;
        int currentIndex = 0;
        bool left  = true; 
        bool running = true;
    public:
        void update();
        void nextSpeedStage();
        void stopOrRun();
        void moveLeft();
        void moveRight();
    public:
        Light(int ledPins[], int LEDcountsm, int speeds[]);
        ~Light();
    };


    #endif
    ```