TI MPS430 FR2311 - UART

更新 發佈閱讀 19 分鐘
raw-image

---------------------------------------------------
IDE: TI CCS 20.3.0
--------------------------------------------------

UART是MCU與外部溝通的常見的協定,
本來是TX RX RTS CTS 火 地 6條線,
但近年來RTS CTS很少用,
通常直接TX RX 火 地就好了,
常見的傳輸速率為11520bps 和 9600bps🏃‍➡️🏃‍➡️🏃‍➡️

程式碼

先看程式碼吧! 直接貼應該是要能build的過😳

#include <msp430.h>
#include <stdint.h>
//================================Define區=============================
//Uart Part
//協定常數
#define RX_HEAD  (0xAA)
#define RX_MAX   (254)

//接收狀態
typedef enum {
    RX_WAIT_HEAD = 0,
    RX_WAIT_LEN,
    RX_RECV_DATA,
    RX_WAIT_CHK
} rx_state_t;

//================================變數區================================
//Uart Part
static volatile rx_state_t rx_state = RX_WAIT_HEAD;
static volatile uint8_t rx_len = 0;
static volatile uint8_t rx_idx = 0;
static volatile uint8_t rx_chk = 0;
//接收完成後可由主迴圈讀取
static volatile uint8_t frame_ready = 0;
static volatile uint8_t frame_len   = 0;
static volatile uint8_t frame_buf[RX_MAX];   // 保存 payload
//可選:統計錯誤
static volatile uint16_t rx_err_chk = 0;
static volatile uint16_t rx_err_ovf = 0;

//================================函式區=================================
//UART Part---------------------------------------------------------------------
void setupUART_p16_p17(void)
{
    // P1.6 = RXD, P1.7 = TXD
    P1DIR  &= ~BIT6;                  // RXD 輸入
    P1DIR  |=  BIT7;                  // TXD 輸出
    P1SEL0 |=  (BIT6 | BIT7);         // P1SELx = 01 → UCA0RXD/UCA0TXD
    P1SEL1 &= ~(BIT6 | BIT7);
}

// 波特率: 9600 @ SMCLK=1MHz (UCBRx=104, UCBRS?1)
static void uart_init_1M_9600(void)
{
    PM5CTL0 &= ~LOCKLPM5;   // 保險再解一次
    // 腳位你已經在 setupUART_p16_p17() 設好了
    UCA0CTLW0  = UCSWRST;                 // 進 reset
    UCA0CTLW0 |= UCSSEL__SMCLK;           // BRCLK = SMCLK (1 MHz)
    UCA0BRW    = 6;                       // BRW
    UCA0MCTLW  = UCOS16                   // 開 oversampling
               | (13 << 4)                 // UCBRF = 13
               | (0x00 << 8);             // UCBRS = 0
    UCA0CTLW0 &= ~UCSWRST;                // 出 reset
    UCA0IE |= UCRXIE;                     // 要 RX 中斷再開
}

/* ===== 基礎傳送 ===== */
static inline void uart_putc(uint8_t c)
{
  while (!(UCA0IFG & UCTXIFG));
  UCA0TXBUF = c;
}

static void uart_send_bytes(const uint8_t *p, uint16_t n)
{
  while (n--) {
    uart_putc(*p++);
  }
}

/* 一次組好並送出整包(長度上限 255 byte 資料) */
static void uart_send_frame(const uint8_t *data, uint8_t len)
{
    uint8_t buf[255];   // Head + Len + Data
    uint8_t n = 0;

    buf[n++] = 0xAA;        // Head
    buf[n++] = len;         // Length

    uint8_t i;
    for (i = 0; i < len; i++) {
        buf[n++] = data[i];
    }

    uart_send_bytes(buf, n);  // 一次送出去

    // 小延遲,避免連續封包黏在一起
    __delay_cycles(16000);  // 約 16ms @1MHz
}

// 取走一包資料(回傳 1=OK, 0=尚未有新包)
uint8_t uart_frame_read(uint8_t *dst, uint8_t *len)
{
    uint8_t i;
    if (!frame_ready) return 0;
    uint8_t n = frame_len;
    for (i=0; i<n; ++i) dst[i] = frame_buf[i];
    *len = n;
    frame_ready = 0;   // 清旗標,允許下一包
    return 1;
}

// RX 中斷(eUSCI_A0)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
    switch (__even_in_range(UCA0IV, 0x08)) {
    case 0x02: { // UCRXIFG
        uint8_t b = UCA0RXBUF;
        switch (rx_state) {
        case RX_WAIT_HEAD:
            if (b == RX_HEAD) rx_state = RX_WAIT_LEN;
            break;
        case RX_WAIT_LEN:
            rx_len = b;
            rx_idx = 0;
            if (rx_len > RX_MAX) {
                rx_err_ovf++;
                rx_state = RX_WAIT_HEAD;
            } else {
                rx_state = RX_RECV_DATA;
            }
            break;
        case RX_RECV_DATA:
          {
              // 先取出 volatile,避免 ++ 與比較衝突
              uint8_t idx = rx_idx;
              uint8_t len = rx_len;
              if (idx < RX_MAX) {
                  frame_buf[idx] = b;
                  idx++;
                  rx_idx = idx;   // 回存
              } else {
                  rx_err_ovf++;
                  rx_state = RX_WAIT_HEAD;
                  break;
              }
              if (idx >= len) {
                  frame_len   = len;
                  frame_ready = 1;
                  rx_state    = RX_WAIT_HEAD;
                  __no_operation();   // debug 斷點
              }
          }break;
        }
    } break;
    default: break;
    }
}

void parser_uartdata(uint8_t *payload, uint8_t len)
{
    if (len < 1) return;
    uint8_t cmd = payload[0];
    if (cmd == 0x01) {
        uint8_t message[5];
        message[0] = 0x55;
        message[1] = 0x44;
        message[2] = 0x33;
        message[3] = 0x22;
        message[4] = 0x11;
        uart_send_frame(message, 5);
    }
}



//GPIO Part---------------------------------------------------------------------
static void gpio_input_init(void)
{
    // P1.1 當按鈕:內部上拉、下降緣中斷
    P1DIR  &= ~BIT1;               // Input
    P1REN  |=  BIT1;               // 啟用上/下拉
    P1OUT  |=  BIT1;               // 上拉
    P1IES  |=  BIT1;               // 高->低(按下)觸發
    P1IFG  &= ~BIT1;               // 清旗標
    P1IE   |=  BIT1;               // 開中斷
}

//=================== 中斷 ===================

#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
    if (P1IFG & BIT1) {
        P1IFG &= ~BIT1;
        P1IE  &= ~BIT1;         // 先關中斷避免彈跳重入

        uint8_t message[5];
        message[0] = 0x11;
        message[1] = 0x22;
        message[2] = 0x33;
        message[3] = 0x44;
        message[4] = 0x55;
        uart_send_frame(message, 5);

        // 重新設定下降緣(避免鬆開的上升緣誤觸)
        P1IES  |=  BIT1;        // 高->低
        P1IFG  &= ~BIT1;
        P1IE   |=  BIT1;        // 再次開啟按鈕中斷
    }
}



//================================主程式=================================

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer
    PM5CTL0 &= ~LOCKLPM5;                   // 解除高阻態,讓 GPIO 可用(即使本例沒用到腳位,建議保留)
    //GPIO init
    gpio_input_init();        // P1.1 按鈕 input
    //Uart Init
    setupUART_p16_p17();      // ★ 腳位切到 UCA0
    uart_init_1M_9600();      // ★ 設定 9600bps

    __enable_interrupt();     // 開啟中斷

    while(1){
        uint8_t buf[10], n;
        if (uart_frame_read(buf, &n)) {
            parser_uartdata(buf, n);// 這裡 buf[0..n-1] 就是解出的 payload
            __no_operation();       // (IAR 會產生一條 NOP 指令)
        }
    }
}



這次分享的程式碼有幾點要注意一下:

  1. 傳輸速率的部分AI跟網路上可能會建議用下圖數據
raw-image

因為G蛋自己環境實測出來,我用上面數據量到的速率都不是9600,會偏一點💣💣
也不知道為啥,上面G蛋的數據是調出來的🫣🫣,
若一開始您也收不到,可以往這部分調整。
(有遇到的也請留言下唷😁)
------------------
心得: 韌體就是這樣,千奇百怪的問題,不合理的邏輯也蠻常出現的,習慣就好🤣🤣 所有Bug ,都要盡量懷疑盡量試,有時也是要憑運氣跟靈感😐
------------------

  1. 程式碼裡含按鈕的部分,主要是驗證Tx用。
  2. 軟體沒有做CRC等偵錯機制,可依需求自己加。
  3. 驗證Tx Rx 有沒有通,還是透過外部裝置來驗證比較簡單,
    本來我想直接一條線 TX 接 RX 就好,自己發自己收,
    但會遇到時序問題,
    例如:你發送的時候還沒開始收,可能就會收不到。
  4. 驗證會需要用以下
    4.1 UART 轉 USB Dongle 。

    4.2 對接軟體 - AccessPort137 。
    (google一下應該很好找,找不到在留言跟G蛋說)。
    (其他COM Port軟體也行)。
UART 轉 USB Dongle (範例)

UART 轉 USB Dongle (範例)


驗證

連接架構:

raw-image

接法:

記得
😈😈Dongle 的Tx要接開發板的Rx😈😈。
😈😈Dongle 的Rx要接開發板的Tx😈😈。
這提醒很蠢,但還是有人常常Tx接Tx,Rx接Rx 🫣🫣🫣。

raw-image


  • 通道連線設定
    1.在電腦上開啟 AccessPort137 選擇 Dongle所對應的COM Port。
    2.設定(確認)連線參數。
    3.連線成功。
選擇埠號 & 設定參數

選擇埠號 & 設定參數

確認參數

確認參數

  • 驗證Tx
    1.連上軟體後,按下開發板的按鈕(P1.1)。
    2.軟體應該要收到
    0x11 0x22 0x33 0x44 0x55 。
    0xAA : 為傳輸標頭。
    0x05 : 資料長度 。



Tx 驗證

Tx 驗證

  • 驗證Rx
    1.在軟體下方輸入 AA 05 01 02 03 04 05
    2.按下發送👇
    3.應該要收到 AA 05 55 44 33 22 11
    (表示Rx有收到資料 並又發送了新資料給軟體)
驗Rx

驗Rx


有些用文字的可能也說不清楚👀👀
有不清楚的在留言討論吧🙋‍♀️🙋‍♀️🙋‍♀️🙋‍♂️🙋‍♂️🙋‍♂️
或是之後拍支影片講解一下🙇‍♂️🙇‍♂️🤣🤣


raw-image







留言
avatar-img
臭G蛋
2會員
33內容數
臭G蛋
臭G蛋的其他內容
2025/11/05
[廠商] Texas Instruments [晶片或平台] MSP430FR2311 [主題功能] PWM [語言/工具]C [IDE]CCS
2025/11/05
[廠商] Texas Instruments [晶片或平台] MSP430FR2311 [主題功能] PWM [語言/工具]C [IDE]CCS
2025/11/05
[廠商] Texas Instruments [晶片或平台] MSP430FR2311 [主題功能] GPIO [語言/工具]C [IDE]CCS
2025/11/05
[廠商] Texas Instruments [晶片或平台] MSP430FR2311 [主題功能] GPIO [語言/工具]C [IDE]CCS
2025/11/03
[廠商] Texas Instruments [晶片或平台] MSP430FR2311 [主題功能] FRAM [語言/工具]C [IDE]CCS
Thumbnail
2025/11/03
[廠商] Texas Instruments [晶片或平台] MSP430FR2311 [主題功能] FRAM [語言/工具]C [IDE]CCS
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
今天帶你用 測試驅動開發(TDD) 的方式,在 Rust 裡從零打造一個命令列搜尋工具:minigrep。 這是《Rust 程式設計語言》書中的經典範例,用來學習測試、模組化與生命週期。 Let's go 🚀 首先建立專案: cargo new minigrep cd minigrep
Thumbnail
今天帶你用 測試驅動開發(TDD) 的方式,在 Rust 裡從零打造一個命令列搜尋工具:minigrep。 這是《Rust 程式設計語言》書中的經典範例,用來學習測試、模組化與生命週期。 Let's go 🚀 首先建立專案: cargo new minigrep cd minigrep
Thumbnail
自從 2022 年 FED 步入升息循環以來,利率已提升至超過 5%的水準,美國公債殖利率也跟著創下近 10 年來的新高。在利率大幅上升的影響下,導致去年債市的行情相當低迷,也對國內的金融業造成莫大衝擊;不僅銀行設定存放款利率是一大難題,擁有龐大美債部位的壽險也在資產配置上也面臨相當沉重的壓力
Thumbnail
自從 2022 年 FED 步入升息循環以來,利率已提升至超過 5%的水準,美國公債殖利率也跟著創下近 10 年來的新高。在利率大幅上升的影響下,導致去年債市的行情相當低迷,也對國內的金融業造成莫大衝擊;不僅銀行設定存放款利率是一大難題,擁有龐大美債部位的壽險也在資產配置上也面臨相當沉重的壓力
Thumbnail
開發金控4月稅後純益7.09億,累計今年前四月稅後純益42.11億,EPS為0.25元。 中國人壽受惠整體避險成本降低,經常性收益表現穩定。開發金2日以12.9元作收,上漲0.1元或漲幅0.78%,整周漲0.39%。 三大法人合計周賣超36,193張,外資周賣超58,291張,投信周買超20,666
Thumbnail
開發金控4月稅後純益7.09億,累計今年前四月稅後純益42.11億,EPS為0.25元。 中國人壽受惠整體避險成本降低,經常性收益表現穩定。開發金2日以12.9元作收,上漲0.1元或漲幅0.78%,整周漲0.39%。 三大法人合計周賣超36,193張,外資周賣超58,291張,投信周買超20,666
Thumbnail
開發金控31日舉行法人說明會,受到美國升息衝擊,子公司中國人壽獲利年減9成,首季僅賺3.2億元。 為強化資本結構,將發行100億元10年期以上次順位債,資本適足率(RBC)有望從3月底260%回升至近300%。開發金雙重槓桿比率目前已降至125%法定水準。未來將視市場情況再評估發債。 有關併購擴大金
Thumbnail
開發金控31日舉行法人說明會,受到美國升息衝擊,子公司中國人壽獲利年減9成,首季僅賺3.2億元。 為強化資本結構,將發行100億元10年期以上次順位債,資本適足率(RBC)有望從3月底260%回升至近300%。開發金雙重槓桿比率目前已降至125%法定水準。未來將視市場情況再評估發債。 有關併購擴大金
Thumbnail
本專欄透過各類股票、多家企業、多種 ETF,帶大家從各式各樣公開且可搜尋到的一般性之證券投資訊息來觀察一間公司,並透過資訊歷史資料的彙整,來去整理出明年可能會配發的股息、全年 EPS 以及現價買進的預期殖利率。
Thumbnail
本專欄透過各類股票、多家企業、多種 ETF,帶大家從各式各樣公開且可搜尋到的一般性之證券投資訊息來觀察一間公司,並透過資訊歷史資料的彙整,來去整理出明年可能會配發的股息、全年 EPS 以及現價買進的預期殖利率。
Thumbnail
本專欄透過各類股票、多家企業、多種 ETF,帶大家從各式各樣公開且可搜尋到的一般性之證券投資訊息來觀察一間公司,並透過資訊歷史資料的彙整,來去整理出明年可能會配發的股息、全年 EPS 以及現價買進的預期殖利率。 本專欄會廣泛的使用各種案例來討論不同類股,以教學為主並非針對個股做推薦,也絕非提供個股
Thumbnail
本專欄透過各類股票、多家企業、多種 ETF,帶大家從各式各樣公開且可搜尋到的一般性之證券投資訊息來觀察一間公司,並透過資訊歷史資料的彙整,來去整理出明年可能會配發的股息、全年 EPS 以及現價買進的預期殖利率。 本專欄會廣泛的使用各種案例來討論不同類股,以教學為主並非針對個股做推薦,也絕非提供個股
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News