大同大學科學開源服務社
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: 2025 電資創客營 - 對講機製作共筆 tags: 電資創客營 --- :::info # 2025 電資創客營 - 對講機製作共筆 **時間**:2025/08/12 9:00 ~ 2025/08/13 16:55 **地點**:挺生大樓 A3 - 200 教室 ::: ## 目錄 **上午** - ESP32 介紹 - 開發環境介紹 - ESP-IDF - FreeRTOS - WiFi 模式 - MAC 位址 - ESP - NOW - 數位類比 - 時脈 - 主機從機 - 周邊介面介紹 - 元件介紹 **下午** # 上午 ## ESP32 介紹 ![NodeMCU-32S-details-3](https://hackmd.io/_uploads/BJSKAZudll.jpg) - 開發版 - 豐富社群資源 - 適合初學者使用 |功能|Arduino|ESP32| |-|-|-| |處理速度|16 MHz|高達 240 MHz| 記憶體|2 kB SRAM|約 520 KB SRAM WiFi / BLE | :x:|內建 多核心|:x:|雙核心 模擬輸出|:x:|內建 DAC 感應器支援|基本|更強大 ## 開發環境介紹 - Arduino IDE - 提供更簡化介面 - 更簡化程式語法 ## ESP-IDF Espressif IoT Development Framework - ESP32指的是晶片,電路板上的微控制器 - 開發版指的是搭載 ESP32 的電路板 - 工具箱 - 核心引擎 - FreePTOS:內建即時作業系統,管理 ESP32 上的所有任務的執行、排程、資源分配、同步 - 無線通訊能力 - WiFi - Bluetooth - ESP - NOW - 周邊介面與功能(輸出介面) - GPIO - ADC/DAC - I2C/SPI/UART - I2S - PWM ## FreeRTOS - 開源的即時**作業系統** - 輕量級,專為嵌入式系統設計的,廣泛應用於微控制器 - 沒有像 Linux、Windows 一樣的先進特徵 - 簡潔與速度,因為太過輕量化,有時候被認為是執行緒函式庫而非作業系統 ### POTS 即時作業系統 - 是一種能在嚴格時間內完成工作的作業系統,並根據優先順序快速切換,確保關進任務準時執行 ### 微控制系統 - 小型電腦,被設計來執行特定任務,常見於嵌入式系統 - 通常整合了處理器、記憶體、與輸出入介面於一塊 ### 嵌入式系統 - 一種類似被遷入在其他設備中的電腦系統 - 可以針對電器、被遷入機器的同客製化功能 ## WiFi 模式 - STA(station 無線終端) - 定位:無限收發器 - 運作:是一個專心對講機頻道(訊號接收)的機器 - AP (Access Point) - 定位:網路中繼站 - 運作:專心做網路通訊中繼站 ## MAC 位址 - MAC 位址(Media Access Control Address) - 定義:裝置在硬體層面的**實體位址**或硬體位址 - 格式:由**12 個十六進位數字**組成,用冒號分隔 例:00:1A:2B:3C:4D:5E 用途: 主要用於區域網路 (LAN) 內的數據傳輸,確保數據包在同一個網段內能**被正確的裝置接收**,在 Wi-Fi 通訊中,AP 和 STA 之間就是透過 MAC 位址來識別和建立連接的。 > 就像送信要知道對方的地址一樣,才能讓信送到正確的人那裡。 ## ESP - NOW - 專為 ESP32 的發明的通訊協議 - 獨立於 WiFi 網路,可直接透過 WiFi 協議進行通訊,不需要經過路由器 - 基於 MAC 位址即可建立傳輸或連接 ## 數位類比 - 類比(Analog) 類比訊號是==連續==的,可以有很多種值 例如:自然現象(聲音、光線、溫度) 類比訊號:麥克風(聲音)、溫度感測器的電壓輸出(溫度->電壓) > 圖案看起來像是**溜滑梯(slide)** - 數位(Digital) 數位訊號是==離散==的,只有特定幾種值(例如 0 和 1) 電腦、微控制器只能處理數位訊號(還記得嗎?電腦只認識0101、也就是**二進位**) 數位訊號:開跟關、二進位資料 > 圖案看起來像是**階梯(stairs)** ## 時脈 時脈(clock):電腦的節拍器 - 週期(Period) - 一次幾秒 - 頻率(frequency)是一秒幾次 - 脈波(Clock Pulse) - 協調各個元件的動作時機 > 沒有穩定的時脈,數位系統就無法協調運作 ## 主機從機 主機(Master)和從機(Slave)的概念 - 核心思想是在描述一種不對等的控制與被控制、主動與被動的關係 簡單來說: - 主機(Master):**ESP32** - 是系統中的主導者,負責發起命令、控制和管理整個系統的運作 - 通常是主動的一方,決定什麼時候發起通訊、傳輸什麼資料,並協調從機行為 - 從機(Slave):**麥克風、音訊模組、按鈕、喇叭** - 是系統中的執行者,它負責接收主機的指令並執行 - 從機通常是被動的一方,等待主機發出命令,然後根據命令進行**資料回傳**或**執行特定操作** <!-- 應該是 --> ## 周邊介面介紹 <!-- 他目錄是錯的 --> ### GPIO - General-Purpose Input/Output, 通用輸入/輸出 - 可透過軟體程式來**控制**這些引腳的**行為** 依現實考量可作為通用輸入(GPI)或通用輸出(GPO)或通用輸入與輸出(GPIO) ### SPI > 串行:一次只傳輸一個位元 串行外設介面(Serial Peripheral Interface Bus,SPI),是一種用於**晶片通訊**的同步串行通訊介面規範,主要應用於**單晶片系統**中的訊號傳遞 由 Motorola 在 1980 年代提出,廣泛應用於感測器、記憶體、顯示器、音訊晶片、SD 卡等設備與微控制器之間 SPI匯流排規定了4個保留邏輯訊號介面: - SCLK(Serial Clock):串行時脈,由主機發出 - MOSI(Master Output, Slave Input):主機輸出,從機輸入訊號(資料由主機發出) - MISO(Master Input, Slave Output):主機輸入,從機輸出訊號(資料由從機發出) - SS(Slave Select):片選訊號,由主機發出,一般是低電位有效 > 共用 SCLK 時脈訊號 ![image](https://hackmd.io/_uploads/BJKnGN_Oxe.png) ### I2C I²C 或 I2C(Inter-Integrated Circuit)是IC間**傳輸控制與資料**的一種序列介面標準 由飛利浦半導體在 1982 年設計,廣泛應用於感測器、記憶體、顯示器、實時時鐘(RTC)、音訊編碼器等設備與微控制器之間 特色:兩條訊號線進行通訊 SCL(Serial Clock Line):由主機產生的時鐘訊號,控制資料傳輸節奏 SDA(Serial Data Line):雙向資料線,負責傳送與接收資料 ### I2S I²S 或 I2S (Inter-IC Sound)是IC間傳輸數位**音訊**資料的一種介面標準 由飛利浦半導體在1986年提出,廣泛應用於音訊編碼器、數位音訊處理器、微控制器與 DAC/ADC 等設備之間 ESP32 的 ESP-IDF 提供了完整的 I2S 驅動程式,可以設定為: 傳送(TX)或接收(RX)模式 多個時鐘信號: 通常包含時鐘線 (BCLK)、字時鐘線 (WS 或 LRCLK) 和數據線 (SD 或 DATA),確保數據的精確同步 | 訊號線 | 功能 | | -------------------- | ------------------------------------- | | SCK(Serial Clock) | 又稱 BCLK,控制每個 bit 的傳輸時序 | | WS(Word Select) | 又稱 LRCLK,決定目前傳輸的是左聲道還是右聲道 | | SD(Serial Data) | 傳輸音訊資料的位元流 | | MCLK(Master Clock) | 系統中頻率最高的時鐘,保持時脈準確性(非必須) | ## 核心(Core) 什麼是核心? - 核心(Core) 是 CPU 中能夠獨立執行程式指令的處理單元 - 就像是一間工廠裡的一個工人,有自己的一套工具(ALU、控制單元、暫存器等),能夠自成為一個完整的生產線 那 CPU core 和 CPU 晶片的關係是什麼? - CPU core 和 CPU 晶片的關係就像是工人和工廠 - 每個工人(核心)都能獨立地接訂單、生產產品 - 工廠內會提供共用的資源(快取記憶體、記憶體控制器等) ### ESP32 的雙核心架構 ESP32 是一個為物聯網(IoT)設計的微控制器,更強調協作和專門化 - 工人 0 號:通訊與後勤核心(Core 0, Protocol_CPU) 角色:專注於通訊協議的專家 例:處理系統底層的任務,像是Wi-Fi、藍牙、FreeRTOS等 - 工人 1 號:應用程式核心(Core 1 或稱為 Application_CPU) 角色:專注於執行你的應用程式的工程師 例:負責使用者的應用程式邏輯,處理你的業務邏輯、運算、數據處理等 ## 元件介紹 - ESP32開發板 - 麵包板 - INMP441 麥克風 - MAX98357A 音訊模組 # 下午 ## 標頭檔 我們這兩天會用到的標頭檔 - <WiFi.h>:處理 WiFi 相關功能,用來抓 MAC 位址 - <esp_now.h>:ESP-NOW 無線通訊協定函式庫 - <driver/i2s.h>:I2S 數位音訊介面函式庫 使用以下兩行得知你的MAC位址 ```Ariduino= WiFi.mode(WIFI_STA) //設定WiFi模式 Serial.println(WiFi.macAddress()) //印出MAC位址 ``` ## i2s初始化 初始化的東西放在setup裡面。 有兩個**結構**負責定義許多參數: - i2s_config_t 例如:工作模式(mode)、取樣率(sample_rate)、位元深度(bits_per_sample)、通道格式(channel_format) - i2s_pin_config_t 負責指定 I2S 的訊號線的 GPIO 腳位: .bck_io_num:連接 I2S 的 BCLK (位元時脈) 腳位 .ws_io_num:連接 I2S 的 WS (字元選擇/左右聲道時脈) 腳位 .data_in_num:連接 I2S 的輸入腳位,連接SD .data_out_num:連接 I2S 的輸出腳位 > config_t 是指 configuration type > 只有mode、usr_apll、tx_desc_auto_clear、fixed_mclk我們會修改到。 ### 初始化的最後三劍客 - i2s_driver_install:安裝 I2S 驅動的主要函式 - i2s_set_pin:設定 I2S 所使用的 GPIO 腳位 - i2s_zero_dma_buffer:清空緩衝區,避免殘值 例如: i2s_driver_install ( I2S_PORT, &i2s_config, 0, NULL ); i2s_set_pin ( I2S_PORT, &pin_config); i2s_zero_dma_buffer ( I2S_PORT ); ### i2s_config_t設定 - .mode: - 讀取:(i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), - 輸入:(i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), - .use_apll:今天都是false - .tx_desc_auto_clear: - 輸入:true - 不輸入:false - .fixed_mclk:今天都是0 ### 腳位設定 利用 #define 設定: 使用格式:#define 名稱 值 :::spoiler 詳細設定 #define I2S_WS 25 // I2S Word Select (LRCLK) 腳位 #define I2S_BCLK 26 // I2S Bit Clock 腳位 #define I2S_SD 32 // I2S Serial Data (資料輸入) 腳位 #define BUTTON_PIN 33 // 定義按鈕連接的 ESP32 腳位 #define I2S_PORT I2S_NUM_0 // 使用 I2S 端口 0 #define SAMPLE_RATE 16000 // 音訊取樣率 (每秒取樣次數),16kHz 是語音常用頻率 #define BUFFER_LEN 64 // 每次讀取/傳送的音訊樣本數量 (緩衝區大小) ::: ## i2s read跟write ## esp_now指令 ## 濾波處理 ## ESP-NOW 接收 (更新版) ``` #include <WiFi.h> #include <esp_now.h> /* ==== 音量處理參數 ==== */ #define NOISE_THRESHOLD 30 // 音量低於此值視為靜音 #define FILTER_TAP_COUNT 2 // 移動平均濾波器抽頭數 void filter_data(int16_t *samples, int sampleCount){ /* 移動平均濾波器(簡單實作)*/ for (int i = 0; i < sampleCount; i++) { long sum_filter = 0; int count_filter = 0; for (int j = 0; j < FILTER_TAP_COUNT; j++) { if (i - j >= 0) { sum_filter += samples[i - j]; count_filter++; } } samples[i] = (int16_t)(sum_filter / count_filter); } } void sound_update(int16_t *samples, int sampleCount){ float gain = 4.0; // 設定增益係數,例如 2.0 代表音量加倍 for (int i = 0; i < sampleCount; i++) { // 確保不會超過 16 位元整數的最大值 long amplified_sample = (long)samples[i] * gain; if (amplified_sample > 32767) { samples[i] = 32767; } else if (amplified_sample < -32768) { samples[i] = -32768; } else { samples[i] = (int16_t)amplified_sample; } } } void wifi_mode_setup(){ /* 設定為 STA 模式 */ WiFi.mode(WIFI_STA); WiFi.disconnect(); // 確保不連接 AP delay(100); Serial.print("📡 接收端 MAC 地址:"); Serial.println(WiFi.macAddress()); } void espInit_setup(){ // 初始化 ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("❌ ESP-NOW 初始化失敗"); return; } } void onDataReceive(const esp_now_recv_info_t *info, const uint8_t *data, int len) { /* Step 1 */ int16_t *samples = (int16_t *)data; int sampleCount = len / sizeof(int16_t); /* Step 2 */ /* 計算平均音量 */ uint32_t sum = 0; for (int i = 0; i < sampleCount; i++) { sum += abs(samples[i]); } int avgVolume = sum / sampleCount; /* Step 3 */ if (avgVolume < NOISE_THRESHOLD) { // 如果平均音量低於閾值,則將所有樣本設為 0 (靜音) for (int i = 0; i < sampleCount; i++) { samples[i] = 0; } Serial.println("📥 接收音訊:靜音中 (低於閾值)"); } else { /* Step 4 */ //filter_data(samples, sampleCount); } /* Step 5 */ /* 印出處理後的音量資訊 */ Serial.print("📥 接收到 "); Serial.print(len); Serial.print(" bytes,平均音量:"); Serial.println(avgVolume); } void setup(){ /* Step 1 */ Serial.begin(115200); delay(1000); /* Step 2 */ wifi_mode_setup(); /* Step 3 */ espInit_setup(); /* Step 4 */ esp_now_register_recv_cb(onDataReceive); /* Step 5 */ Serial.print("接收端初始化啟動..."); } void loop(){ } ``` // 麥克風測試Day3 ``` #include <driver/i2s.h> // 引入 I2S 數位音訊介面函式庫 /* I2S 設定 (喇叭輸出腳位) */ #define I2S_DOUT 27 // I2S Data Out (資料輸出) 腳位,實際音訊資料線 #define I2S_BCLK 26 // I2S Bit Clock 腳位 #define I2S_WS 25 // I2S Left/Right Clock (LRCLK) 腳位 #define I2S_PORT I2S_NUM_0 #define SAMPLE_RATE 16000 // 音訊取樣率,需與傳送端一致 #define BUFFER_LEN 64 // 每次寫入的音訊樣本數量 (緩衝區大小) // 簡單的正弦波數據,用於測試喇叭播放 int16_t test_tone[BUFFER_LEN]; void setupI2S(){ const i2s_config_t i2s_config = { // 設定為 I2S 主模式 (ESP32 提供時脈) 和 接收模式 (從麥克風接收) .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), //填入(I2S_MODE_MASTER | I2S_MODE_RX)或(I2S_MODE_MASTER | I2S_MODE_TX) .sample_rate = SAMPLE_RATE, // 音訊取樣率,需與麥克風輸出相符 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // 每個音訊樣本使用 16 位元來表示 .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 設定為左聲道 .communication_format = I2S_COMM_FORMAT_I2S_MSB,// I2S通訊格式,通常是MSB最高有效位元優先 .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // 中斷分配旗標,設定中斷優先級 .dma_buf_count = 8, // DMA 緩衝區的數量,DMA 讓音訊資料高效傳輸,不佔用 CPU .dma_buf_len = 64, // 每個 DMA 緩衝區的長度 (樣本數) .use_apll =false , .tx_desc_auto_clear = true, .fixed_mclk = 0 }; const i2s_pin_config_t pin_config = { // 不使用的腳位填I2S_PIN_NO_CHANGE .bck_io_num = I2S_BCLK, // BCLK 腳位 .ws_io_num = I2S_WS, // WS/LRCLK 腳位 .data_out_num = I2S_DOUT, // 資料輸出腳位 .data_in_num = I2S_PIN_NO_CHANGE // 腳位,用於接收麥克風的資料 }; i2s_driver_install(I2S_PORT, &i2s_config , 0, NULL); // 安裝 I2S 驅動程式 i2s_set_pin(I2S_PORT, & pin_config); // 設定 I2S 腳位 i2s_zero_dma_buffer(I2S_PORT); // 清空 DMA 緩衝區,準備接收新資料 } void sin_tone(){ /* 生成一個簡單的正弦波測試音 */ for (int i = 0; i < BUFFER_LEN; i++) { test_tone[i] = (int16_t)(sin(i * 2 * PI / BUFFER_LEN * 5) * 10000); // 5個週期,振幅10000 } } void loop_print(){ uint32_t sum = 0; for(int i=0; i<BUFFER_LEN; i++) sum+=abs(test_tone[i]); int avgVolume = sum / BUFFER_LEN; Serial.print("音量:"); Serial.println(avgVolume); } void setup() { /* Step 1 */ Serial.begin(115200); /* Step 2 */ setupI2S(); /* Step 3 */ sin_tone(); Serial.println("🔊 喇叭播放測試啟動..."); } void loop() { /* Step 1 */ size_t bytesWritten; /* Step 2 */ i2s_write(I2S_NUM_0, test_tone, sizeof(test_tone), &bytesWritten, portMAX_DELAY); /* Step 3 */ loop_print(); /* Step 4 */ delay(10); // 稍微延遲,避免播放過快 } ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully