\documentclass[12pt,a4paper]{article}
\usepackage[top=0.75in, bottom=0.75in, left=0.75in, right=0.75in]{geometry}
\usepackage[utf8]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{xurl}
\usepackage{listings}
\usepackage{xcolor}

\usepackage{booktabs}

\lstset{ % General setup for the package
    language=C,
    basicstyle=\footnotesize\ttfamily,
    numbers=left,
     numberstyle=\small,
    frame=tb,
    tabsize=4,
    columns=fixed,
    showstringspaces=false,
    showtabs=false,
    keepspaces,
    commentstyle=\color{gray},
    keywordstyle=\color{blue}
}

\usepackage{xeCJK}
\setCJKmainfont{TW-Kai}
\setCJKmonofont{Noto Sans Mono CJK TC}
\author{1082B0006 林宏信}
\title{}


\begin{document}

\begin{titlepage}
  \begin{center}
    \vspace*{1cm}

    \Huge
    \textbf{國立臺北科技大學}

    \vspace{0.5cm}
    \textbf{學生實習心得報告}

    \vspace{1.5cm}

    \textbf{}

    \vspace*{\fill}

    \begin{flushleft}
      \large
      學期：110 學年度第 2 學期\\
      科別：智慧自動化控制科 \\
      班級：三年級 \\
      學號：1082B0004、1082B0006 \\
      姓名：劉予安、林宏信\\
      課程名稱：機電整合與實習\\
      授課老師：李政宏 博士\\
    \end{flushleft}
  \end{center}
\end{titlepage}

\section{單元名稱：LED 特效燈}
\section{實習設備與材料}

\begin{table}[h!]
  \begin{center}
    \begin{tabular}{c|c|c|c}
      \toprule
      項次 & 品名 & 數量 \\
      \midrule
      1 & Arduino & 1 \\
      2 & LED & 8 \\
      3 & 按鈕 & 4 \\
      \bottomrule
    \end{tabular}
  \end{center}
\end{table}

\section{實習步驟}

這次的實作是要製作一個可透過按鈕切換不同模式的特效燈，每個特效運用 8 個數位 LED 做出各式的效果。這個實作在一開始的設計就有一個需要注意之處：由於按鈕可能在任何時間被按下，然而一個模式跑的過程需要時間，若沒有特別設計，就會需要使用者按著按鈕直到一個模式的週期結束，而這是不佳的使用者體驗。因此我在此運用與第一次實作相同的技巧，用計時器來取代 delay，達到非阻塞的設計。

首先是切換模式的函式，本函式運用靜態區域變數 last 儲存前一個狀態，在按下按鈕時，將其設為對應的模式並回傳。

\lstinputlisting[linerange={41-51}]{week4-4.ino}

接著即是程式的主迴圈，每次依據現在的模式，呼叫對應的函式。

\lstinputlisting[linerange={103-118}]{week4-4.ino}

接著是這個程式最特別之處：call\_interval。這個函式會每隔 DELAY 的時間，執行傳入的函式指標 f。雖然目前是使用固定的 DELAY 常數，但這個函式可以透過多接受一個參數，來改變要等待的時間，就可以實現不同的模式跑不同的 delay。藉由 call\_interval 函式，各模式燈光控制的函式就可以簡化為一個單次執行的程式。

\lstinputlisting[linerange={26-33}]{week4-4.ino}

最後就是三種模式各別的控制函式，每個函式會接受一個 clk 或 value 的參數，用來代表目前執行到第幾次。首先是二進位模式，我使用右移運算元來將數字除二，接著再取餘，即可用一行程式碼做出二進位的燈光。

\lstinputlisting[linerange={57-61}]{week4-4.ino}

格雷碼則是先將輸入用格雷碼的公式運算後，代入前面的二進位程式。

\lstinputlisting[linerange={63-65}]{week4-4.ino}

最複雜的則是隨機點亮燈光的程式，由於一個燈光點亮後會持續 3 個週期，因此需要用變數儲存每個燈的狀態。我運用一個陣列來存每個燈光剩餘的「血量」，0 代表不亮，大於 0 則代表亮，每個週期會將亮著的燈血量減一。接著是隨機點亮的程式，使用 do while 迴圈，在選到沒亮的燈前，會不停抽選燈，將其點亮。

\lstinputlisting[linerange={71-95}]{week4-4.ino}

\section{問題與討論}

在 get\_mode 的地方仍然有個小 bug：當按著比較前面的按鈕時，同時按後面的按鈕，會讓後面的按鈕觸發。如按著 B4 還沒放開時，同時按下 B1，這時模式會被切為 1 號模式；但反之按著 B1 時按下 B4，仍然會是 1 號模式。這是由於程式是由前往後檢查，找到一個按下的按鈕就會回傳。但由於只要按鈕按著就會不停的重設計數器，要等到放開所有按鈕，燈光才會開始動作，經過評估沒有必要設計更複雜邏輯來解決。

\section{心得與建議}

這次的實驗過程體驗到了一個不斷讓程式碼精進的過程，從一開始的原型開發，專注在功能的實作，接著不斷的簡化、重構程式碼，使其愈加精鍊，最後得到了相當簡潔的程式碼，這樣的過程給了我很大的成就感。

\pagebreak{}

\section{完整程式碼}

\lstinputlisting{week4-4.ino}


\end{document}
