---
# System prepended metadata

title: STM32F411 開發板 教學
tags: [stm32]

---

# STM32F411 開發板 教學  
## **STM32F411 開發板簡介**  
STM32F411 開發板基於 **STM32F411** 微控制器（Cortex-M4 內核，最高時脈 100MHz），適用於高效能嵌入式應用。它具備豐富的 **GPIO、UART、SPI、I2C、ADC、PWM** 及 **USB OTG**，並支援 **DMA** 和 **FPU**，適合信號處理與控制應用。開發可使用 **STM32CubeIDE、Keil、IAR**，並透過 **HAL 庫或 LL 庫** 簡化開發流程。適用於 **IoT、數據處理、機器學習及低功耗應用**。
# Topic-1 GPIO  

## GPIO 簡介

### 什麼是GPIO（general purpose input output）
GPIO代表通用輸入/輸出。大多數 Pin 腳都有專用用途，例如向某個元件發送訊號， GPIO腳位(Pin) 的功能可以自訂並且由軟體控制。

## 功能模式：

#### General Purpose（通用功能）：
一般的控制模式，由使用者透過程式碼直接控制該 Pin 腳要輸出 High 還是 Low (輸出功能)，也可以由程式碼直接讀取該 Pin 腳的電壓準位(輸入功能)。
#### Alternate Function（複用功能）：
使用該 Pin 腳所擁有的特殊功能（例如：UART、PWM、I2C），使用者沒辦法用程式碼直接控制該 Pin 腳的 High 或 Low，而是由所指定之特殊功能暫存器(control register)來控制。
## 輸出電路組態：

#### Push-Pull（推挽）：
由一對互補的電晶體組成，可以直接輸出 High 或 Low 電位。
#### Open-Drain（汲極開路）：
FET 版的 Open-Collector。由一個 N 通道 FET 構成，只能輸出 Low（GND） 或 Open（開路）狀態，因此要外加一上拉電阻(pull-up resistor)才能使其輸出的 Open 狀態變成 High，而 High 狀態的實際電壓根據上拉電阻所接的電源而定，可以高或低於 IC 本身的電源電壓。而產生線接及閘（Wired AND）的特性。
## 輸入模式：

#### Analog（類比）：
使用 ADC 讀取類比電壓數值時。需要分配爲 ADC Channel 的 Pin 腳上才能正常使用。
#### Floating（浮接）：
一般的讀取模式。若不啓用 STM32 內部的上/下拉電阻，使用時外部電路應要有上/下拉電阻，否則該 Pin 腳浮接時可能無法正確讀值，使讀入值為亂碼。


## Demo  (LED, 蜂鳴器, 按鍵輸入)
:::success
功能:讓LED燈按照順序跑動，按鈕按下時跑馬燈會產生變化且蜂鳴器發出聲響
:::


{%youtube P3TdjOzSB_E%}
## STM32CubeIDE設定
### 點選 File -> New -> STM32 Project
![image](https://hackmd.io/_uploads/SkfRDudt1g.png)

---
### 選取開發板型號：NUCLEO-F411RE

![image](https://hackmd.io/_uploads/BkyJTUyelx.png)


---
### 建立專案
![image](https://hackmd.io/_uploads/SkFkBKOK1e.png)


---
### Pinout -> Clear Pinouts 移除用不到的Pin腳
![image](https://hackmd.io/_uploads/SkDmytuKkx.png)
![image](https://hackmd.io/_uploads/rJeByKuFkx.png =30%x)


---
### 設定 RCC 時鐘源
![image](https://hackmd.io/_uploads/HJtTpuOYyg.png)


---
 ### Debug 設定
![image](https://hackmd.io/_uploads/Bk5kC__Kyx.png)


---
### Pin腳啟用 

**按鈕1、2**：
PB0、PB1 (GPIO_Input)
**蜂鳴器**：
PC4 (GPIO_Output)
**LED**：
PA4、PA5、PA6、PA7 (GPIO_Output)

![image](https://hackmd.io/_uploads/S1BLngzqye.png)

NUCLEO-F411RE Pinout
![nucleo_pinout_13](https://hackmd.io/_uploads/B1gl-zz9yl.png)

接線
![GPIO](https://hackmd.io/_uploads/BJ10T_Bjye.png)


---

### Pin腳設定 

![image](https://hackmd.io/_uploads/HJwK2xGqJe.png)



---
### 點擊分開其他初始化設定

![image](https://hackmd.io/_uploads/rkD5ieGcyl.png)

### 設置完成 點選齒輪生成程式碼 

![image](https://hackmd.io/_uploads/B11qzFOFkl.png)

---
### 沙盒模式
:::info
STM32的沙盒模式（Sandbox Mode）是一種安全防護機制，用於將應用程式執行環境隔離，防止不受信任的程式碼對系統造成損害。此模式常見於嵌入式系統中，特別是在執行敏感操作或連接網絡時。透過沙盒模式，系統能夠限制應用程式訪問硬體、記憶體或外部設備的權限，有效防止漏洞被惡意利用。此外，STM32還可以透過硬體的安全特性（如記憶體保護單元MPU）來實現沙盒環境，保障系統的穩定性與安全性。
:::
## 程式碼

::: spoiler main.c
{%gist /shiaw87/3353f55b1fdb1e3416f2b60e6e445b22 %}
:::

---

# Topic-2 Interrput TIM  
## 定時器(Timer)
通常用於測量時間間隔，從零開始向上計數以測量經過的時間的計時器，它是一種從指定時間間隔開始倒計時並用於產生時間延遲的設備，例如秒錶

### 定時器用法
Interrupt：
TIMER的應用多，微處理機中常見的中斷(interrupt)讓CPU定時做一件事情，多久做一次的時間要告訴它，所以我們需要Timer。
Delay： 
產生延遲會需要等待幾秒鐘，這時候就需要Timer來計算delay的時間
PWM：
產生一個週期性的信號，例如可供馬達控制
![tim](https://hackmd.io/_uploads/SkG63TY5yx.png)


### STM32 定時器（Timer）計數週期 T 的計算公式
![time](https://hackmd.io/_uploads/rkOa36Kqyx.png)
此公式用來計算 STM32 定時器的定時週期，也就是計時器從 0 計數到 ARR（自動重裝載值）後發生一次溢出的時間。

### Prescaler (PSC)
預分頻器值
### Period (ARR)
自動重裝載值
### PCLK 時鐘頻率
計時器的輸入時鐘頻率
### T
定時器週期( 0 到 ARR 需要的時間)

### 舉例:
設定 1 秒計時
假設：

PCLK1（APB1 時鐘）= 72MHz
PSC = 7199 （分頻 7200）
ARR = 9999 （計數範圍 0 ~ 9999）
![image](https://hackmd.io/_uploads/rJ3nSD3qkx.png)
定時器每 1 秒 產生一次溢出，觸發中斷。

###  脈波寬度調變Pulse width modulation（PWM）
PWM是將類比信號轉換為脈波，一般轉換後脈波的週期固定，但脈波的占空比會依類比信號的大小而改變。

在使用 PWM 時我們會需要控制兩種參數：頻率與 Duty Cycle（佔空比）。頻率的部分和 Timer 一樣，由 PSC 與 ARR 的值來設定，而 Duty Cycle 則由 CCR （Capture/Compare Register，捕獲/比較暫存器）來指定。
#### 佔空比(Duty Cycle)
佔空比是指輸出的PWM當中，高電位保持的時間與整個週期之比。可以看到下圖當中最上方為50%的佔空比，也就是高電位與低電位各佔50%。
![image](https://hackmd.io/_uploads/ryhwAP25yl.png)

![image](https://hackmd.io/_uploads/SkK3Cv25Jx.png)
Timer使用PWM輸出模式時，CNT計數值大於CCRx的時候會輸出高電位，相反的低於CCRx時則是低電位。
ARR : 主要控制的是頻率，也就是綠框的部分
CCRx : 主要為控制佔空比，也就是藍框的部分

求Duty Cycle:
![image](https://hackmd.io/_uploads/rJINQ_2ckx.png)

## 中斷(Interrupt)
在嵌入式系統中，中斷是一個機制，用於處理各種外部事件或內部條件的發生。這些事件可以是來自硬體設備的訊號，例如按鈕按下、計時器計時完成，或是軟體內部的條件，如：數據溢出或滿足一些特定條件。當一個中斷事件發生時，MCU會中斷正在執行的程式，轉而執行相應的中斷服務程式（Interrupt Service Routine，ISR），處理該事件，然後繼續執行原來的程式。

### 中斷的類型
MCU支援多種不同類型的中斷，以下是一些常見的中斷類型：

外部中斷： 由外部硬體觸發的中斷，例如按鈕按下、感測器觸發等。

定時器中斷： 由MCU內部定時器計時完成時觸發，用於執行定時任務。

UART中斷： 用於處理串列通信中的數據接收或傳送完成事件。

ADC中斷： 用於類比數位轉換（ADC）完成時，通常用於讀取模擬數據。

內部中斷： 由MCU內部條件觸發的中斷，例如除以零的錯誤。

看門狗定時器中斷： 用於檢測系統錯誤並執行相應的動作。

### 中斷優先級
當多個中斷事件同時發生時，MCU需要確定哪個中斷應該首先處理。這就涉及到中斷優先級的概念。每個中斷都有一個優先級，通常是數字越小，優先級越高。當多個中斷事件同時發生時，MCU會首先處理優先級最高的中斷，然後再處理其他中斷，以此類推。

## 實作Demo
{%youtube Aiw47c68cww %}
### STM32CubeIDE設定
### PIN 設定
![image](https://hackmd.io/_uploads/SyOag_n9ke.png)

---
### GPIO設定
PA5 EXIT5 中斷開啟
![image](https://hackmd.io/_uploads/SkSEpPhc1x.png)

---
PA7 output
![image](https://hackmd.io/_uploads/BJsw6D2q1g.png)

---
### RCC設定
![image](https://hackmd.io/_uploads/BJk0pw3qkl.png)

---
### SYS設定
![image](https://hackmd.io/_uploads/H1U-Rv2q1x.png)

---
### TIM設定
開啟tim3 pwn設定頻率2kHz
![image](https://hackmd.io/_uploads/HksZ6Ih91x.png)

---
開啟tim4 設定每毫秒跑一次
![image](https://hackmd.io/_uploads/ryPUaL291l.png)

---
### NVIC 設定
![image](https://hackmd.io/_uploads/H1JNCwn9yx.png)

---
### Clock設定
![image](https://hackmd.io/_uploads/S1_W1uhqkg.png)

---
### 外設檔案分開+生成
![image](https://hackmd.io/_uploads/HJMkxu29yl.png)
![image](https://hackmd.io/_uploads/ryhExd2qJe.png)

---
### Nucleo_Pinou
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖
![bse202536](https://hackmd.io/_uploads/HJvSyAUskx.png)

---

### PWM 實作

### 流程圖
```mermaid
flowchart TD
    A(開始)
    B[初始化計時器]
    C[進入主迴圈]
    
    subgraph LED 亮度控制
        D[pwm_led 函數]
        D1{flag_led == 1?}
        D2[調整 duty_num]
        D3[更新 PWM]
        D4[flag_led = 0]
    end
    
    subgraph PWM 啟動/停止
        E[pwm_state 函數]
        E1{flag_brk == 0?}
        E2[啟動 PWM]
        E3[停止 PWM]
    end

    subgraph 計時中斷 TIM4
        F[TIM4 IRQHandler]
        F1[每 5 毫秒: 更新 LED 狀態]
        F2[每 5 秒: 切換 PWM 啟動/停止]
    end

    subgraph GPIO 中斷
        G[HAL_GPIO_EXTI_Callback]
        G1{PA5_Pin 低電位?}
        G2[切換 PA7_Pin 狀態]
    end

    A --> B --> C
    C --> D
    D --> D1
    D1 -- 是 --> D2 --> D3 --> D4
    D1 -- 否 --> E
    C --> E
    E --> E1
    E1 -- 是 --> E2
    E1 -- 否 --> E3

    F --> F1
    F --> F2

    G --> G1
    G1 -- 是 --> G2

```
### 程式碼
:::spoiler main.c
{%gist /shiaw87/07463454e9dddbf86939bbed58b15442 %}
:::

:::spoiler stm32f4xx_it.c
{%gist /shiaw87/6cda9f8265aa6c4ac61c2523016e45ad %}
:::
# Topic-3 WWDG  
## Watchdog簡介  

看門狗（Watchdog Timer, WDT）是一種計時器，其主要功能是在 **微控制器發生異常時（如進入無窮迴圈或程式崩潰）自動重新啟動系統**，確保裝置能夠恢復運行，提升系統的可靠性。  

STM32 內建兩種看門狗：
1. **獨立看門狗（IWDG，Independent Watchdog）**
2. **窗口看門狗（WWDG，Window Watchdog）**

### **獨立看門狗（IWDG）**
IWDG 的運作方式是透過 **遞減計數器倒數**，當計數器歸零時，若 MCU **沒有在期限內「餵狗」（重置計數器）**，則系統會觸發 **重置（Reset）**。

### **窗口看門狗（WWDG）**
WWDG 的機制與 IWDG 相似，但有額外的 **時間窗口限制**：
- 若 **太晚餵狗**（計數器低於下限 0x40），系統 **將重啟**。
- 若 **太早餵狗**（計數器值仍高於窗口值），系統 **也會重啟**。

這表示 **WWDG 需要在特定時間範圍內刷新計數器**，避免過早或過晚操作，這就是 **「窗口」** 機制的由來。

### **簡單對比**
| 看門狗類型 | 觸發條件 | 主要特性 |
|------------|------------|------------|
| **IWDG** | 遞減計數器歸零 | 只要在倒數結束前餵狗即可 |
| **WWDG** | 計數器超過或低於窗口 | 需在指定窗口時間內餵狗 |

---

## **窗口看門狗 (WWDG)**

## **WWDG 時序圖**
- **🔴 紅色箭頭**：如果計數器值 **大於 W[6:0]** 時刷新，**系統將觸發重置（Reset）**。
- **🟢 綠色箭頭**：要防止 WWDG 觸發重置，應在 **計數器值小於 W[6:0] 時執行刷新**。
- **🔵 藍色箭頭**：當 **計數器值從 0x40 遞減到 0x3F** 時，**系統將觸發重置（Reset）**。

![WWDG 時序圖](https://hackmd.io/_uploads/Hy-1KSEoke.png)

---

### 1. 看門狗超時時間計算公式  
$$
T_{WWDG} = \left( \frac{1}{f_{PCLK}} \right) \times 4096 \times 2^{WDGTB} \times (T - W)
$$

其中：  

- \\( T_{WWDG} \\)：看門狗超時時間（秒）  
- \\( f_{PCLK} \\)：APB 時鐘頻率（Hz），例如 48 MHz（48,000,000 Hz）  
- \\( WDGTB \\)：時鐘分頻器（prescaler），可能取值 \\( 0, 1, 2, 3 \\)，對應 \\( 2^0, 2^1, 2^2, 2^3 \\)  
- \\( T \\)：窗口看門狗計數器的起始值（最大 127）  
- \\( W \\)：窗口值（一般比 T 小，例如 80 或 63）  

---  

### 2. 計算範例  
假設：  
- APB 時鐘頻率 \\( f_{PCLK} = 48 \\) MHz  
- 分頻係數 \\( WDGTB = 3 \\)（即 \\( 2^3 = 8 \\)）  
- 計數器起始值 \\( T = 127 \\)  
- 窗口值 \\( W = 80 \\) 或 \\( W = 63 \\)  

#### 2.1 最小刷新時間（進入允許刷新區間）  
$$
T_{\text{min}} = \left( \frac{1}{48000000} \right) \times 4096 \times 2^3 \times (127 - 80)
$$
$$
= \left( \frac{1}{48000000} \right) \times 4096 \times 8 \times 47
$$

$$
\approx 32 \text{ ms}
$$

#### 2.2 最大刷新時間（超時重啟前的時間）
$$
T_{\text{max}} = \left( \frac{1}{48000000} \right) \times 4096 \times 2^3 \times (127 - 63 + 1)
$$
$$
= \left( \frac{1}{48000000} \right) \times 4096 \times 8 \times 65
$$
$$
\approx 45 \text{ ms}
$$

---

### 3. 解析
-  **必須在 32 ms ~ 45 ms 之間** 呼叫 `HAL_WWDG_Refresh(&hwwdg)`，否則：  
      - **小於 32 ms**：看門狗仍在保護區間，不允許刷新（視為非法操作，重啟）。  
      - **大於 45 ms**：系統超時，將觸發復位（系統重啟）。  

這樣的機制可以防止 MCU 進入無限迴圈或掛起時失去監控，確保系統穩定運行。  




## 實作 Demo  

{%youtube a5LS9gKlels %}  

## STM32CubeIDE設定  
### PIN 設定  
![image](https://hackmd.io/_uploads/SyOag_n9ke.png)

---
### GPIO設定  
開啟PA5 PA6 (output)、PB0(input,pull down)  
![image](https://hackmd.io/_uploads/BJqLFS4jye.png)

---
### RCC設定  
![image](https://hackmd.io/_uploads/BJk0pw3qkl.png)

---
### SYS設定  
![image](https://hackmd.io/_uploads/H1U-Rv2q1x.png)

---
### WWDG設定  
![image](https://hackmd.io/_uploads/S1Ew0SVs1g.png)

---
### TIM設定  
![image](https://hackmd.io/_uploads/SksqvT0oJx.png)

---
### Clock設定  
![image](https://hackmd.io/_uploads/HkvxVL4jkx.png)

---
#### WWDG clock  
APB1 48MHZ
![image](https://hackmd.io/_uploads/ryIdQ84o1e.png)

---
### 外設檔案分開  
![image](https://hackmd.io/_uploads/HJMkxu29yl.png)
![image](https://hackmd.io/_uploads/ryhExd2qJe.png)

---
### Nucleo_Pinout  
![nucleo_pinout_13](https://hackmd.io/_uploads/H1V4ROSs1x.png)

---

### 電路圖  
![132 (2)](https://hackmd.io/_uploads/Bku7684ikx.png)

---
## WWDG實作  
###   
:::spoiler 流程圖  
```mermaid  
flowchart TD
    subgraph LED燈閃爍
        A(開始)
        B[for 迴圈]
        D[切換 LED1 狀態]
        G{迴圈結束?}
    end
    subgraph  
            H(進入 while)
        I[延遲 100ms]
        J{BTN1 是否被按下?}
        K[關閉TIM3]
        M[切換 LED2 狀態]
    end

    RE(超時重啟)

    A --> B --> D --> G
    G -- 否 --> B
    G -- 是 --> H
    
    H --> I --> J
    J -- 是 --> K --> RE 
    J -- 否 --> M --> I

```
:::
### 程式碼
:::spoiler main.c
{%gist /shiaw87/9a4ff2ba262a6fc1d8ecaa23e15afe42 %}
:::

:::spoiler stm32f4xx_it.c
{%gist /shiaw87/096f191b7b35a42ec5687c4e097f3005 %}
:::

---

# Topic-4 USART
## USART(universal synchronous asynchronous receiver transmitter)
通用同步/非同步收發傳輸器，常被用於一般的串列傳輸應用。
![image](https://hackmd.io/_uploads/BJW-G9c2yl.png)

---
### Asynchronous 非同步傳輸

在傳送資料時插入額外資訊，表示資料起始、結束。好處是設定時間短、硬體成本低、機器時脈不同也能傳資料，缺點是單次傳輸的資料量較少。

---
### Synchronous 同步傳輸

額外提供時脈訊號，使兩端機器在溝通時能夠藉此同步收發資料。比起非同步傳輸，同步傳輸不需要start/stop bit，因此能夠一次傳較多的資料。同步傳輸需要解決時鐘偏移對資料傳輸造成的影響，除此之外，額外的時脈分佈網也需要大量的驅動電路，比起非同步傳輸增加了更多的耗能。一般同步系統會用阻斷時脈的方式(clock gating)，來令不需運作的模組進入睡眠狀態(sleeping mode)到省電的目的，這個機制需要額外的電路及再次同步的額外延遲，不僅造成多餘的能源損耗，也增加了電路設計上的困難度。

![image](https://hackmd.io/_uploads/HyHdW5c3Je.png)


## 實作
### Demo
{%youtube Yw_P2MaAFDQ %}

### 需準備
#### LED\*4 & 1K電阻\*4
![image](https://hackmd.io/_uploads/rkn0exhnyl.png)


#### CP2102 模組
![S__258564101_0](https://hackmd.io/_uploads/HJXbBmt3Jg.jpg)
[CP2102驅動](https://www.silabs.com/developer-tools/usb-to-uart-bridge-vcp-drivers?tab=downloads)

#### 串口調試助手

![image](https://hackmd.io/_uploads/rkEBVxhn1x.png)

## STM32CubeIDE設定
### PIN 設定
![PinoutClear](https://imgur.com/VJNPOvV.png)

---  
### GPIO設定
![image](https://hackmd.io/_uploads/rkEkh0j2yl.png)

---
### RCC設定
![RccSet](https://imgur.com/7kPTJ9A.png)

---
### SYS設定
![SysSet](https://imgur.com/rNjjVDv.png)

---
### USART設定  

#### 先設定USART1 TX跟RX接腳再開啟USART1
![image](https://hackmd.io/_uploads/S1YZj0snye.png)
![image](https://hackmd.io/_uploads/BJ5MoCsnJe.png)
![image](https://hackmd.io/_uploads/BkRojCi2kx.png)
#### 啟用USART1中斷功能
![image](https://hackmd.io/_uploads/SyTpjCshye.png)


---
### Clock設定
![ClockSet](https://imgur.com/SlT0y70.png)


---
### 外設檔案分開+生成
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)
#### 生成程式碼
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---
### Nucleo_Pinout
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖
![image](https://hackmd.io/_uploads/S1wUuAihkx.png)
![image](https://hackmd.io/_uploads/Sk4P_Ao3Jl.png)


---
### 程式碼
:::spoiler usart.c
{%gist /shiaw87/c282151b383edad45a15f85a704ca816 %}
:::

---

# Topic-5 RTC(DS1302)

## **RTC (Real-Time Clock) 即時時鐘介紹**

### **1. RTC 概念**
RTC（Real-Time Clock，即時時鐘）是一種特殊的時鐘裝置，用於提供持續的時間計時，即使系統關機或重啟，它仍能保持計時功能。RTC 主要應用於計算機、嵌入式系統、智慧型裝置等，確保系統能夠準確地追蹤時間和日期。

### **2. RTC 的特點**
- **低功耗**：RTC 主要依靠獨立的低功耗電池 (VBAT) 運作，即使主系統電源關閉，RTC 仍能運行。
- **獨立計時**：RTC 內部包含一個 32.768 kHz 的石英晶振，用於保持時間精確度。
- **日期與時間管理**：RTC 通常具備秒、分、時、日、月、星期和年等時間信息，並支援閏年自動調整。
- **支援低功耗模式**：某些 RTC 內建低功耗模式，適用於電池供電的嵌入式系統。

### **3. RTC 的應用**
- **計算機和嵌入式系統**：確保系統開機後能獲取正確時間。
- **智慧家庭**：用於定時設備，如智慧燈光控制。
- **數據記錄器**：確保數據紀錄時間的準確性，例如工業監測設備。
- **消費性電子產品**：如智慧手錶、行動裝置、MP3 播放器等。

---

## **DS1302 RTC 晶片介紹**
DS1302 是一款低功耗、串列介面的 RTC 晶片，適用於各種微控制器應用，如 STM32、Arduino、Raspberry Pi 等。

### **1. DS1302 主要特點**
- **串列通訊介面**：使用三線 SPI (SCLK, I/O, CE) 介面與微控制器通訊，易於連接。
- **時間與日期管理**：支援秒、分、時、日、月、星期與年計時，並具備 12/24 小時格式選擇。
- **低功耗設計**：當主電源關閉時，可使用備用電池 (VBAT) 維持計時功能。
- **內建 RAM**：提供 31 個 8-bit RAM 寄存器，其中 8 個用於 RTC，其他 23 個可作為 SRAM 使用。
- **工作電壓範圍廣**：支援 2V~5.5V 工作電壓，適用於不同應用環境。
- **時鐘精準度校正**：具備時間補償功能，可透過軟體校正計時誤差。

### **2. DS1302 內部架構**
- **主時鐘電路**：由 32.768 kHz 石英晶振提供時鐘訊號，確保時間計時準確。
- **備用電池管理**：當主電源 (VCC) 斷電時，RTC 自動切換至 VBAT 電源，確保時間保持不變。
- **通訊介面**：使用簡單的三線 SPI 介面，可輕鬆與各種微控制器連接。

### **3. DS1302 應用**
- **數據記錄設備**：確保時間戳記的準確性，如溫度監測器、氣象站等。
- **智慧家居**：應用於定時開關、電器控制等場景。
- **電腦與嵌入式系統**：提供系統時間維持功能，如 BIOS 時鐘。
- **低功耗設備**：適用於需要長期運行且低能耗的電子裝置。

---

## **RTC 在 STM32F411 上的應用**
STM32F411 內建 RTC 模組，支援低功耗模式，並可使用 VBAT 保持時間資訊，因此在 STM32F411 上通常不需要外接 DS1302 等外部 RTC 晶片。內建 RTC 具有以下優勢：
- 低功耗運作，適合電池供電應用。
- 內建時鐘補償機制，提高計時準確性。
- 支援警報與定時喚醒功能，可用於節能應用。


## 實作
### Demo
{%youtube RJDkueZB_64 %}


### 需準備
#### DS1302 RTC 時鐘模組
![S__258564100_0](https://hackmd.io/_uploads/By1-HQt2kl.jpg)

#### CP2102 模組
![S__258564101_0](https://hackmd.io/_uploads/HJXbBmt3Jg.jpg)
[CP2102驅動](https://www.silabs.com/developer-tools/usb-to-uart-bridge-vcp-drivers?tab=downloads)

#### 串口調試助手

![image](https://hackmd.io/_uploads/rkEBVxhn1x.png)

## STM32CubeIDE設定
### PIN 設定
![PinoutClear](https://imgur.com/VJNPOvV.png)

---  
### GPIO設定
![image](https://hackmd.io/_uploads/B1ZKsRP3yg.png)


---
### RCC設定
![RccSet](https://imgur.com/7kPTJ9A.png)

---
### SYS設定
![SysSet](https://imgur.com/rNjjVDv.png)

---
### USART設定

#### 先設定USART1 TX跟RX接腳再開啟USART1
![image](https://hackmd.io/_uploads/S1YZj0snye.png)
![image](https://hackmd.io/_uploads/BJ5MoCsnJe.png)
![image](https://hackmd.io/_uploads/BkRojCi2kx.png)

---
### Clock設定
![ClockSet](https://imgur.com/SlT0y70.png)

---
### 外設檔案分開+生成
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)
#### 生成程式碼
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---
### Nucleo_Pinou
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖
![DS1302_circult](https://hackmd.io/_uploads/Hk1u4yO3yl.png)

---

## 實作

###  
:::spoiler 流程圖
```mermaid
flowchart TD
    A[啟動程式] --> B[系統初始化]
    B --> C[初始化 DS1302]
    C --> D{檢查初始化標記}
    D -- 未初始化 --> E[設定時間]
    E --> F[寫入初始化標記]
    D -- 已初始化 --> G[讀取當前時間]
    F --> G
    G --> H["顯示時間"]

    H --> L
    subgraph L[while loop]
        J[每秒讀取 DS1302 時間]
        J --> K["顯示時間"]
    end

```
:::

---

### 程式碼
:::spoiler main.c
{%gist /shiaw87/d4d88f4814441c62f4b4ef650f071140 %}
:::

:::spoiler usart.c
{%gist /shiaw87/09dec84840d9a0b98cf144d9f2969985 %}
:::

:::spoiler ds1302.h
{%gist /shiaw87/38d37860ba6695d59cc50f6bf85b84ac %}
:::

:::spoiler ds1302.c
{%gist /shiaw87/03271f9ceae503589b128a8ec9fa541d %} 
:::

---
### 資料來源(驅動)
[GitHub 驅動程式來源](https://github.com/aaron-ev/driver-ds1302-stm32f4)


# Topic-6 SDIO
## 🔌 SDIO 是什麼？

**SDIO（Secure Digital Input Output）** 是一種擴充在 SD 記憶卡標準上的介面，支援 **資料儲存功能以外的 I/O 裝置**，例如：

- Wi-Fi 模組
- 藍牙模組
- GPS 模組
- 通用 I/O 模組（GPIO）

👉 在嵌入式應用中，SDIO **最常用來做為 SD 卡的資料傳輸介面**，提供比 SPI 更快的速度。

---

### 📶 SDIO 模式 vs SPI 模式

| 項目            | SDIO 模式              | SPI 模式              |
|-----------------|-------------------------|------------------------|
| 傳輸速度        | 高速（最高 50 MHz）     | 低速（通常 20 MHz 以下） |
| 傳輸資料寬度    | 1-bit / 4-bit 資料線     | 單線（MOSI/MISO）     |
| 效率            | 高                       | 中等                   |
| 實作難度        | 較高（需 DMA）           | 較低                  |
| 硬體資源占用    | 多（需 SDIO 外設）       | 少（只要 SPI 控制器） |

🔧 若你的 MCU（例如 STM32）有內建 SDIO 介面，推薦使用 SDIO 模式搭配 **DMA（Direct Memory Access）** 傳輸，加快 SD 卡讀寫效率。

---

### 🧩 SDIO 的資料線（4-bit 模式）

| 腳位     | 功能               |
|----------|--------------------|
| CLK      | 時鐘訊號           |
| CMD      | 指令傳輸線         |
| D0–D3    | 資料線（1-bit / 4-bit） |

👉 實際使用中，**最少需 CMD、CLK、D0 三條線** 就能運作 1-bit 模式。若要跑 4-bit 模式，就要全部 D0～D3 都連接。

---

### 🧪 在 STM32 中使用 SDIO 的典型流程：

1. 初始化 SDIO 硬體（設定時脈、模式、腳位）
2. 掛載 FATFS 檔案系統（如使用 `f_mount()`）
3. 開啟檔案 / 寫入 / 讀取  
4. 卸載檔案系統（` f_mount(NULL, "", 0); `）

🧠 STM32 HAL 提供了 `HAL_SD_Init()`、`HAL_SD_ReadBlocks()`、`HAL_SD_WriteBlocks()` 等 API

---

### 📦 實際應用場景

- 📁 使用 SD 卡記錄 Log 檔案（像是車用資料記錄器）
- 📸 儲存相機拍下的照片
- 🎮 從 SD 卡載入遊戲素材、音樂
- 📡 接 Wi-Fi 模組作資料上傳（藉由 SDIO I/O 擴充）

---

## 實作
## Demo

![image](https://hackmd.io/_uploads/ryAdUsqnyl.png)

## STM32CubeIDE設定
### PIN 設定
![PinoutClear](https://imgur.com/VJNPOvV.png)

---  
### GPIO設定
PA5 設定INPUT
![image](https://hackmd.io/_uploads/HJxin95h1l.png)


---
### RCC設定
![RccSet](https://imgur.com/7kPTJ9A.png)

---
### SYS設定
![SysSet](https://imgur.com/rNjjVDv.png)

---
### SDIO設定
CMD D0 啟用pull up
![image](https://hackmd.io/_uploads/B1gasq9hyl.png)
開啟DMA
![image](https://hackmd.io/_uploads/SkSWnq5nke.png)

---
### USART設定
![image](https://hackmd.io/_uploads/Skw4nc531x.png)

### NVIC 設定
![image](https://hackmd.io/_uploads/r1RSh552kl.png)

---

### Clock設定
![ClockSet](https://imgur.com/SlT0y70.png)

---
### FatFS設定
![image](https://hackmd.io/_uploads/HkcbTc5hJx.png)
input 選PA5這是用來檢查SD卡插入的
![image](https://hackmd.io/_uploads/S1v769chkg.png)

---
### 外設檔案分開+生成
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)
#### 生成程式碼
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---
### Nucleo_Pinout
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖
![bse2025321](https://hackmd.io/_uploads/H1dT1s5hJx.png)


---

## SDIO+FATFS實作

###  
:::spoiler 流程圖
```mermaid
flowchart TD
    A(開始)
    B[掛載 SD 卡 f_mount]
    C{掛載成功？}
    D[printf 錯誤訊息]
    E[開啟 test.txt 寫入模式]
    F{開啟成功？}
    G["寫入 TEST\\r\\n"]
    H[關閉檔案]
    I[開啟 test.txt 讀取模式]
    J{開啟成功？}
    K[讀取內容]
    L[關閉檔案]
    M[printf 輸出 buff]
    Z(結束)
    aa[卸載SD卡]
    A --> B
    B --> C
    C -- 否 --> D 
    C -- 是 --> E
    E --> F
    F -- 否 --> D 
    F -- 是 --> G --> H --> I
    I --> J
    J -- 否 --> D --> aa -->Z
    J -- 是 --> K --> L --> M --> aa
```
:::

---
### 程式碼
:::spoiler usart.c
{%gist /shiaw87/09dec84840d9a0b98cf144d9f2969985 %}
:::

:::spoiler main.c
{%gist /shiaw87/078036c6645318b9fdc12f6bcbf9cf67 %}
:::

:::spoiler fatfs.c
{%gist /shiaw87/3f4bbc214ec6f5a51674fb1531d103f9 %}
:::

---
### 參考資料
[📖參考資料](https://www.youtube.com/watch?v=1MxWZyayiTw)
# Topic-7 I²C

## I²C 簡介
I²C（Inter-Integrated Circuit，或稱 IIC）是一種常用的串列通訊協定，主要用於短距離設備之間的通訊。由 Philips（現為 NXP）於 1982 年設計，目的是用來在集成電路（IC）間傳輸資料。I²C 在許多嵌入式系統中被廣泛應用，適合多個設備之間的低速數據通訊。

### I²C 基本特點

1. **雙線通訊**：
   - **SCL（Serial Clock Line）**：提供時鐘訊號，由主設備（Master）控制。
   - **SDA（Serial Data Line）**：傳送資料和控制訊號，支持雙向通訊。

2. **多主多從架構**：
   - 一條 I²C 線路可以連接多個主設備（Master）和多個從設備（Slave）。
   - 主設備負責控制通訊的起始、停止和資料流向；從設備僅在主設備的控制下進行通訊。

3. **同步通訊**：
   - 主設備透過 SCL 時鐘訊號與從設備同步，使多個設備能在相同時鐘訊號下準確進行資料通訊。

4. **位址分配**：
   - 每個 I²C 從設備都有一個唯一的位址，由主設備透過位址碼選擇通訊的目標設備。
   - 通常使用 7 位元位址，但也有擴展格式支持 10 位元位址。

### I²C 工作原理
![image](https://hackmd.io/_uploads/SkN1qiwR1g.png =80%x)

I²C 通訊包括「起始條件」、「資料傳輸」和「停止條件」等步驟：
1. **起始條件（Start Condition）**：
   - 主設備將 SDA 拉低，SCL 保持高電位，表示開始傳輸。
   
2. **資料傳輸**：
   - 每次傳輸一個字節，I²C 會傳送 8 位元的數據，從最高位（MSB）傳送到最低位（LSB）。
   - 每次傳輸結束後，從設備會回應 ACK（應答訊號），主設備根據 ACK 決定是否繼續或結束傳輸。

3. **停止條件（Stop Condition）**：
   - 主設備將 SDA 拉高，SCL 也保持高電位，表示結束傳輸。

### 優缺點

**優點**：
- **雙線設計**使得硬體連接簡單且成本低。
- 支援**多主多從設備**，可連接多個設備，擴展性佳。
- 傳輸速率相對較高，適合低速或中速通訊。

**缺點**：
- **傳輸距離有限**，適合用於短距離的設備間通訊。
- 資料速率不及 SPI，通常用於需要較低傳輸速率的應用。
- I²C 協定本身是半雙工的，不能同時進行接收和傳輸。在同一條 I²C 線上，資料只能單向傳輸。

### I²C 應用範例

I²C 協定廣泛應用於嵌入式系統中，例如：
- 溫度感測器、EEPROM、RTC 時鐘、顯示驅動 IC 等設備。
- 在開發板如 Arduino、Raspberry Pi、STM32 等嵌入式控制器上都能看到 I²C 通訊的應用。

---

## AT24C02 EEPROM 介紹

**AT24C02** 是 Microchip 公司推出的一款 2Kb（256 字節）I²C EEPROM 記憶體，常用於儲存系統配置、校準數據等非揮發性數據。以下是 AT24C02 的詳細介紹。

### 基本參數
- **容量**：2Kb（256 字節）
- **介面**：I²C 通訊
- **工作電壓**：1.8V - 5.5V（支援寬電壓範圍）
- **記憶體組織**：32 頁，每頁 8 字節

### 記憶體結構
- 每頁包含 8 個字節，因此 AT24C02 擁有 32 頁。
- 每頁可以作為寫入單位，但在同一頁內的寫入數據不能超過 8 個字節。

![AT24C02](https://hackmd.io/_uploads/ryRg9iDRJe.png)


### 通訊協定（I²C）
- **位址範圍**：AT24C02 的 I²C 7 位位址為 `0x50` 到 `0x57`（可根據 A0、A1、A2 接腳設定）。
- **傳輸速率**：支援標準模式（100kHz）和快速模式（400kHz）。
- **位址選擇**：A0、A1 和 A2 接腳可設置位址，最多支援 8 個設備在同一 I²C 線上。

![image](https://hackmd.io/_uploads/HkUzcsPRkg.png)


### 讀寫操作
- **寫入操作**：
  - 支援單字節和頁寫入，頁寫入時最多寫入 8 字節，超出頁大小的數據將覆蓋頁的開頭。
  
- **讀取操作**：
  - 支援隨機讀取和循環讀取，可以從指定地址開始，連續讀取多字節數據。

![image](https://hackmd.io/_uploads/BkMEqiwCkg.png)

### 特點
- **非揮發性**：斷電後數據仍保留，適合需要長期保存的配置數據。
- **壽命**：擦寫壽命達 1,000,000 次，數據保存期達 100 年。
- **低功耗**：適合低功耗應用場景。

### 應用場景
- **配置參數儲存**：儲存系統配置和校準參數。
- **紀錄數據儲存**：在物聯網、家電等設備中儲存長期保存的數據。
- **消費電子**：應用於家電和電子設備，儲存設定或狀態數據。

```c
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
```

![image](https://hackmd.io/_uploads/B1NB9oDAkg.png)

---

## 實作

### Demo  
![螢幕擷取畫面 2025-04-09 145958](https://hackmd.io/_uploads/BJMr2qm0Jx.png)

### STM32CubeIDE 設定

#### PIN 設定  
![PinoutClear](https://imgur.com/VJNPOvV.png)

---

#### RCC 設定  
![RccSet](https://imgur.com/7kPTJ9A.png)

---

#### SYS 設定  
![SysSet](https://imgur.com/rNjjVDv.png)

---

#### I²C 設定  
![image](https://hackmd.io/_uploads/SyeO29X0ye.png)

---

#### UART 設定  
![UartSet](https://hackmd.io/_uploads/ry4_sc7CJe.png)

---
#### Clock 設定  
![ClockSet](https://imgur.com/SlT0y70.png)

---

#### 外設檔案分開+生成  
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)

##### 生成程式碼  
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---

#### Nucleo_Pinou  
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---

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

---

## I²C-AT24CXX 實作  

### 流程圖  
```mermaid
flowchart TD
    A(開始)
    B[讀取並顯示數據]
    C[寫入 64 字節到 EEPROM]
    D[再次讀取並顯示數據]
    E[清空 EEPROM]
    F[清空後再次讀取並顯示數據]
    G[寫入 32 字節到 0x20 位置]
    H(結束)

    A --> B
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H
```

---

### 程式碼

:::spoiler usart.c
{%gist /shiaw87/09dec84840d9a0b98cf144d9f2969985 %}
:::

:::spoiler i2c.h 
{%gist /shiaw87/b71d6ed106a3852ebe20dc0a6b0d9298 %}
:::

:::spoiler i2c.c
{%gist /shiaw87/387f06012300f11e8d7167f5d5f4c14e %}
:::

:::spoiler main.c 
{%gist /shiaw87/788d786e54baca6dda47c928cc27712c %}
:::

---

## SSD1306 OLED(IIC通訊)

### SSD1306 OLED 0.96''是一種點陣顯示器（Dot-matrix display）,是由可亮滅的許多小單元（燈或其它結構）排成陣列,來顯示文字或圖形內容的顯示裝置。 

![image](https://hackmd.io/_uploads/SJJtXUcAkx.png)


![image](https://hackmd.io/_uploads/S18lVUqC1e.png)
### SSD1306這塊驅動晶片的任務是用於執行接收數據、顯示儲存數據、掃描刷新等。

驅動接口：128個SEG接腳和64個COM接腳，對應128×64像素點陣顯示屏。

圖形顯示數據RAM-Graphic Display Data RAM（GDDRAM）：128×64位元（128×8位元組）SRAM。

通訊介面：8位元6800/8080並行，3/4線SPI，I2C。

![image](https://hackmd.io/_uploads/ryvMVI9Cyl.png)
SEG 引腳（Segment Pins）
SEG 引腳負責驅動顯示器上的各個像素直向排列的部分（通常是一列像素的各個點）。
SSD1306 的 SEG 引腳標籤通常是從 SEG0 到 SEG127，對應 128 列。

COM 引腳（Common Pins）
COM 引腳負責驅動顯示器上的每一行。
在 SSD1306 中，COM 引腳標籤從 COM0 到 COM63，對應 64 行。
![image](https://hackmd.io/_uploads/SkHNV85Ryx.png)
![image](https://hackmd.io/_uploads/BJIrV85Rkl.png)
![image](https://hackmd.io/_uploads/Sk3IVI90Je.png)
![image](https://hackmd.io/_uploads/B1GPV89Ryl.png)

---

![image](https://hackmd.io/_uploads/rJtjVU5Rke.png)
![image](https://hackmd.io/_uploads/Hkw3NUcAye.png)
![image](https://hackmd.io/_uploads/SJf6ELq0ke.png)



## 實作  
## Demo  
{%youtube akr9O4ziHuY %}
![image](https://hackmd.io/_uploads/Bka4SI501e.png)
## STM32CubeIDE設定  
### PIN 設定  
![PinoutClear](https://imgur.com/VJNPOvV.png)
---
### RCC設定  
![RccSet](https://imgur.com/7kPTJ9A.png)

---
### SYS設定  
![SysSet](https://imgur.com/rNjjVDv.png)

---
### I2C設定  
![image](https://hackmd.io/_uploads/ryovSUq01x.png)


---
### Clock設定  
![ClockSet](https://imgur.com/SlT0y70.png)

---
### 外設檔案分開+生成  
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)
#### 生成程式碼
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---
### Nucleo_Pinou  
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖  
![image](https://hackmd.io/_uploads/HklPPIc01e.png)

---
### 程式碼  
:::spoiler codetap.h
{%gist /shiaw87/595fb6ef69a81548be1988125da4c780 %}
:::

:::spoiler oled.h  
{%gist /shiaw87/0fdf353befad22229bdd8274c3210928 %}
:::  

:::spoiler oled.c
{%gist /shiaw87/f95f17a65ab6842076ea1399e8a13bd2 %}
:::

::: spoiler main.c  
{%gist /shiaw87/8f48ccf12d6448b3d0c7ddf32ecf2527 %}
:::

---


# Topic-8 SPI (NOR flash、ILI9341)  
##  SPI (Serial Peripheral Interface)  

SPI（Serial Peripheral Interface）是一種常見的串列通訊協議，用於在MCU和外部設備之間進行高速數據傳輸。SPI通訊通常用於連接MCU與各種外部設備，如感測器、螢幕、儲存裝置、無線模組等。

### 基本原理

#### SPI通訊是一種同步通訊協議，它基於主從（Master-Slave）架構。以下是SPI通訊的基本原理:

**主機（Master）**：MCU當主機，生成時鐘訊號並控制數據傳輸。
**從機（Slave）**：外部設備（如感測器或儲存裝置）當從機，按照主機的時鐘訊號進行數據傳輸。

#### SPI通訊使用四條訊號線進行通訊
SCLK（Serial Clock）：主機生成的時鐘訊號，用於同步數據傳輸。
MISO（Master In Slave Out）：從機到主機的數據傳輸線，用於將數據從從機傳輸到主機。
MOSI（Master Out Slave In）：主機到從機的數據傳輸線，用於將數據從主機傳輸到從機。
CS/SS（Chip Select/Slave Select）：選擇要與主機通訊的從機的信號線。當CS/SS訊號為低電位時，表示該從機被選擇。

![image](https://hackmd.io/_uploads/SJjAhxER1x.png)

![image](https://hackmd.io/_uploads/HyxeagVAJx.png)


#### SPI(Serial Peripheral Interface)為主從式同步串列通訊,可分為單工/全雙工

單工:線路上的訊號只能做單向傳送
半雙工:線路上的訊號可以雙向傳送 , 但是不能同時傳送
全雙工:線路上的訊號可以同時雙向傳送
同步:傳送端和接收端共用同一個CLOCK
所有的傳輸都會根據一個共同的頻率訊號 , 此頻率訊號產生自”主控裝置(Master端)”, 從屬裝置(Slave端)會用此頻率訊號來對收到的位串流進行同步

如果有多個周邊晶片被連到同一個SPI介面 , 主控裝置能透過SS pin腳的電位高低來選擇接收資料的周邊裝置
![image](https://hackmd.io/_uploads/BJQWTx4Rkx.png)




SPI_CR1 中有兩個 bits 時鐘極性CPOL 和 時鐘相位CPHA 控制取值的時間關係，總共有4種組合。

CPOL(clock polarity) 決定閒置時 clock 的電位。

CPOL = 0 表閒置時為低電位。

CPOL = 1 表閒置時為高電位。

CPHA(clock phase) 決定在 clock 的哪個 edge 取值。

CPHA = 0 表示在第一個 edge (Rising,when CPOL=0.Falling,when CPOL=1.)取值。

CPHA = 1 表示在第二個 edge (Falling,when CPOL=1.Rising,when CPOL=0.)取值。
![image](https://hackmd.io/_uploads/HyVdbLigkx.png)


## W25Q32FV - Serial NOR Flash
快閃記憶體(NOR Flash)是一種非揮發性記憶體技術，廣泛應用於嵌入式系統和儲存設備中。
### 基本特性
非揮發性：即使在沒有電力的情況下，存儲在 NOR Flash 中的數據也不會丟失。

可擦寫性：數據可以寫入、讀取和擦除，但在操作上一般需要擦除整個扇區或區塊，而不是單個字節。

Nor Flash主要應用在程式碼的儲存，容量較小、寫入速度慢，但因隨機讀取速度快，不適合朝大容量發展，主要用在手機上，目前以16Mb、32Mb為主。

![image](https://hackmd.io/_uploads/H1u9UUslke.png)
![image](https://hackmd.io/_uploads/By6a5Usl1g.png)



### W25Q32 記憶體結構：
W25Q32 共有 64 個block，因此總容量為 4MB。

區塊 (block)：
每個block的大小為 64KB。 1 block = 16 sector。

扇區 (sector)：
每個sector的大小為 4KB。1 sector = 16 page。

頁 (page)：
1 page = 256byte。

字節 (byte)：
1 byte = 8 bit。每個byte有唯一的address。

位 (bit)：
最小的單位是bit，每個bit的值是 1 或 0。每 8 bit 構成 1 個byte。
### W25Q32 常用指令集(非所有指令)
![image](https://hackmd.io/_uploads/S1akR2jxJx.png)

## 實作
## Demo
{%youtube _nCUfQEKNps %}

## STM32CubeIDE設定
### PIN 設定
![PinoutClear](https://imgur.com/VJNPOvV.png)

---  
### GPIO設定
![image](https://hackmd.io/_uploads/rJP5Ee4CJe.png)


---
### RCC設定
![RccSet](https://imgur.com/7kPTJ9A.png)

---
### SYS設定
![SysSet](https://imgur.com/rNjjVDv.png)

---
### SPI1啟用
![image](https://hackmd.io/_uploads/Hy8nNxVRJe.png)
![image](https://hackmd.io/_uploads/H1ja4xVRye.png)


---
### UART設定
![UartSet](https://hackmd.io/_uploads/ry4_sc7CJe.png)

---
### Clock設定
![ClockSet](https://imgur.com/SlT0y70.png)

---
### 外設檔案分開+生成
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)
#### 生成程式碼
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---
### 建立 W25Q32.c及W25Q32.h

![image](https://hackmd.io/_uploads/B1hHBlE0ke.png)
![image](https://hackmd.io/_uploads/B1z8BlERkg.png)


---
### Nucleo_Pinou
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖
![image](https://hackmd.io/_uploads/S1wUuAihkx.png)
![image](https://hackmd.io/_uploads/HJs0DgN0yx.png )


---

## SPI + NOR flash(W25Q32) 實作

### 程式碼
####
:::spoiler usart.c
{%gist /shiaw87/09dec84840d9a0b98cf144d9f2969985 %}
:::

:::spoiler main.c
{%gist /shiaw87/b172cbb82083f4db644f06ee211c9e0f %}
:::

:::spoiler W25Q32.c
{%gist /shiaw87/3d47ed11c466c0f53215366897a76ec3 %}
:::

:::spoiler W25Q32.h
{%gist /shiaw87/5a889b19d7637e58fdc874d0cc99ef37 %}
:::

## TFT ILI9341實作
## Demo
{%youtube _0Ot_U6uRhs %}

## STM32CubeIDE設定
### PIN 設定
![PinoutClear](https://imgur.com/VJNPOvV.png)

---  
### GPIO設定
![image](https://hackmd.io/_uploads/S1v2Erwyll.png)


---
### RCC設定
![RccSet](https://imgur.com/7kPTJ9A.png)

---
### SYS設定
![SysSet](https://imgur.com/rNjjVDv.png)

---
### TIM設定
![image](https://hackmd.io/_uploads/BkLH78klxe.png)
![image](https://hackmd.io/_uploads/HkbOmUylee.png)


---
### SPI設定
選
![image](https://hackmd.io/_uploads/BJKrBBvkxl.png)
![image](https://hackmd.io/_uploads/rJNQrSP1gx.png)
![image](https://hackmd.io/_uploads/S1_NrrvJgl.png)

---
### NVIC 設定
![image](https://hackmd.io/_uploads/HJLtSrvJgl.png)

---
### CRC設定
![image](https://hackmd.io/_uploads/SkSP0Bw1gx.png)

___
### touchGFX設定
![image](https://hackmd.io/_uploads/rkcM0SP1lg.png)
![image](https://hackmd.io/_uploads/Bkc40SPkeg.png)

___
### Clock設定  
![ClockSet](https://imgur.com/SlT0y70.png)

---
### 外設檔案分開+生成  
![GeneratorSet](https://imgur.com/Lo1x0Fc.png)
#### 生成程式碼
![CodeGenerator](https://imgur.com/LDLzPZb.png)

---
### Nucleo_Pinou  
![nucleo_pinout](https://imgur.com/pW4VU4f.png)

---
### 電路圖  
![image](https://hackmd.io/_uploads/SJPcPLyeeg.png)



---

## ILI9341實作  

[下載touchGFX](https://www.st.com/en/development-tools/touchgfxdesigner.html)

---

### 程式碼  

:::spoiler main.c  
{%gist /shiaw87/0dd6c5c81c47d50fdc3edbd5700aa713 %}
:::  

:::spoiler z_displ_ILI9XXX.h
{%gist /shiaw87/c222e228084efeaa4c7390281a45a624 %}
:::

:::spoiler z_displ_ILI9XXX.c
{%gist /shiaw87/85c629b6727ed8f86417e8e40731e0eb %}
:::

:::spoiler z_touch_XPT2046.h
{%gist /shiaw87/20cb8f64c8fdcf0e66f641228f63564e %}
:::

:::spoiler z_touch_XPT2046.c
{%gist /shiaw87/cbf270d4f1dcb77e41a1c4680b26f07f %}
:::

:::spoiler STM32TouchController.cpp
{%gist /shiaw87/8ba7a2dc1d99c53064082cc37f9d6713 %}
:::
### touchGFX設定
點擊
![image](https://hackmd.io/_uploads/H1i6ABvJll.png)
![image](https://hackmd.io/_uploads/rk4H1UvJex.png)
![image](https://hackmd.io/_uploads/SJRSyLD1gg.png)
調整UI介面
![image](https://hackmd.io/_uploads/H1IuJIDkgg.png)
添加背景
![image](https://hackmd.io/_uploads/SJPqkLw1eg.png)
把原本的背景刪除
![image](https://hackmd.io/_uploads/HkFTy8Pklx.png)
可以模擬看看成效
![image](https://hackmd.io/_uploads/rkiWeLPyxl.png)
完成後就可以生成程式碼了
![image](https://hackmd.io/_uploads/HJGEeUDyle.png)

##
[📖參考資料](https://www.youtube.com/watch?v=g1siKaPox88)


