首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MSP430G2553 單片機 HC-SR04 超聲波測距 + UART 通訊完整固件原始碼

     編輯:Java 相關知識

注意:原文章標題為「Java/C++ 傳值/傳引用/指針」,但內容實為 TI MSP430 單片機 C 語言固件。本文依實際內容重寫。

本專案基於 TI MSP430G2553 低功耗單片機,結合 HC-SR04 超聲波測距模組 與 UART 串口,實現非阻塞式測距並將結果 (厘米,保留一位小數) 以文本格式發送至 PC 端。採用 Timer_A 捕獲模式測量回波脈衝寬度,中斷驅動 UART 發送,主循環輪詢觸發測量。

硬體資源分配

功能腳位模組/寄存器說明
LED 指示P1.0GPIO測量觸發指示
按鍵觸發P1.3 (S2)GPIO + 上拉按下持續測量,放開停止
HC-SR04 TrigP1.4GPIO 輸出10μs 高電平觸發
HC-SR04 EchoP2.2Timer1_A1 捕獲 (CCI1B)上升沿啟動、下降沿捕獲
UART TXP1.2USCI_A09600 8N1 發送測距結果

核心參數配置

#define SOUR_CLK       1045000L   // DCO 頻率 ~1.045 MHz
#define SYS_CLK        SOUR_CLK   // 系統時鐘
#define MIN_UNIT_TO1M  1000L      // 1m = 1000mm
#define ACCU_GRD       7          // 字串緩衝區 "xxx.x\0"
#define DISTANCE       45         // 最大量程 45dm = 4.5m (HC-SR04 理論 4m)
#define MAX_TIME       (DISTANCE * 2 * SYS_CLK / 340) // 最大回波時間對應計數值

完整固件原始碼

#include 

long current_time; // 捕獲到的 Timer 計數值

/* 硬體定義 */
#define LED_1     BIT0
#define SW_2      BIT3
#define TA1_1     BIT2   // P2.2 - Timer1_A1 CCI1B
#define TRIG      BIT4   // P1.4 - HC-SR04 Trig
#define UART_TXD  BIT2   // P1.2 - USCI_A0 TXD

/* 初始化 Timer1_A1 捕獲模式 */
void init_timer1() {
    P2SEL  |= TA1_1;      // P2.2 選為 Timer1_A1 功能
    P2DIR  &= ~TA1_1;     // 輸入方向
    TA1CTL = MC_0 + TASSEL_2;          // 停止模式, SMCLK 時鐘源
    TA1CCTL1 = CCIE + SCCI + CCIS_1 + SCS + CAP + CM_2; // 捕獲模式, 下降沿, 同步捕獲, 中斷使能
}

/* 初始化 UART 9600 8N1 */
void init_uart() {
    UCA0CTL1 |= UCSWRST;               // 軟體複位
    UCA0CTL1 |= UCSSEL_2;              // SMCLK 時鐘源
    UCA0BR0 = 0x6D;                    // 1.045MHz / 9600 ≈ 109 = 0x6D
    UCA0BR1 = 0x00;
    P1SEL  |= UART_TXD;                // P1.2 功能選擇
    P1SEL2 |= UART_TXD;
    P1DIR  |= UART_TXD;                // 輸出方向
    UCA0CTL1 &= ~UCSWRST;              // 釋放複位
}

/* 計算距離 (mm) : distance = 340 m/s * (time/2) = 170 * time_us */
/* Timer 計數值 current_time 對應時間 = current_time / SYS_CLK 秒 */
long cal_distance() {
    return (long)((340L * (0.5 * current_time / SYS_CLK) * MIN_UNIT_TO1M));
}

/* 粗略延遲 */
void delay() {
    unsigned char i, j;
    for (i = 124; i > 0; i--)
        for (j = 8; j > 0; j--);
}

/* 將長整數距離轉為 "xxx.x" 字串 (cm, 1 位小數) */
static char *translater(long distance_mm) {
    static char trans[ACCU_GRD]; // "xxx.x\0"
    long f = MIN_UNIT_TO1M;      // 1000 (mm 基數)
    trans[0] = ' ';
    if (distance_mm > 0) {
        for (int i = 1; i < ACCU_GRD - 1; i++) {
            if (i == 4) { trans[i] = '.'; continue; } // 小數點位置
            trans[i] = '0' + distance_mm / f;
            distance_mm %= f;
            f /= 10;
        }
    }
    trans[ACCU_GRD - 1] = '\0';
    return trans;
}

/* 發送單次觸發脈衝 (10μs) 並等待捕獲完成 */
void once_pro() {
    // 清除捕獲溢位標誌
    if (TA1CCTL1 & COV) TA1CCTL1 &= ~COV;

    // 按鍵按下 (低電平) 才觸發測量
    if (!(P1IN & SW_2)) {
        TA1R = 0;                 // 清零計數器
        P1OUT |= TRIG;            // Trig 拉高
        _EINT();                  // 開啟總中斷
        TA1CTL |= MC_2;           // 連續計數模式
        __delay_cycles(10);       // 10μs @ 1MHz (約 10 cycles)
        P1OUT &= ~TRIG;           // Trig 拉低
        P1OUT |= LED_1;           // LED 點亮
        while (TA1CCTL1 & CCIFG); // 等待捕獲中斷完成 (CCIFG 由 ISR 清除)
    } else {
        P1OUT &= ~LED_1;          // LED 熄滅
        _DINT();                  // 關閉總中斷
    }
}

/* UART 發送字串 (過濾前導零) */
void uart_txstring(char *str) {
    int i = 0;
    while (str[i]) {
        // 過濾前導零: 百位、十位為零時不發送
        if (i == 1 && str[i] == '0') { i++; continue; }
        if (i == 2 && str[i] == '0' && str[i-1] == '0') { i++; continue; }
        UCA0TXBUF = str[i++];
        delay(); // 簡易波特率延遲,確保發送緩衝區就緒
    }
}

/* ========== 中斷服務程式 ========== */

/* UART TX 中斷: 發送測距結果 */
#pragma vector = USCIAB0TX_VECTOR
__interrupt void usci_txdistance() {
    uart_txstring("\n\r");
    uart_txstring(" Current distance: ");
    uart_txstring(translater(cal_distance()));
    uart_txstring(" cm");
    IE2 &= ~UCA0TXIE; // 關閉 TX 中斷,避免重複進入
}

/* Timer1_A1 捕獲中斷: 回波下降沿 */
#pragma vector = TIMER1_A1_VECTOR
__interrupt void capture() {
    current_time = TA1CCR1;       // 讀取捕獲值
    TA1CTL &= ~MC_2;              // 停止計數器
    TA1CCTL1 &= ~CCIFG;           // 清除中斷標誌
    IE2 |= UCA0TXIE;              // 使能 UART TX 中斷發送結果
}

/* ========== 主程式 ========== */
void main() {
    WDTCTL = WDTPW + WDTHOLD;     // 關閉看門狗
    DCOCTL = 0;
    BCSCTL1 = CALBC1_1MHZ;        // 校準 1MHz DCO
    DCOCTL = CALDCO_1MHZ;

    P1OUT = 0; P2OUT = 0;
    P1REN |= SW_2;                // P1.3 上拉電阻使能
    P2REN |= TA1_1;               // P2.2 上拉 (可選)
    P1OUT |= SW_2;                // 上拉輸出高
    P1DIR &= ~SW_2;               // P1.3 輸入
    P1DIR |= TRIG + LED_1;        // P1.4, P1.0 輸出

    init_timer1();
    init_uart();

    while (1) {
        // 簡易去抖動延遲
        int c = 8;
        while (c--) delay();

        // 清除可能的殘留捕獲標誌
        if (TA1CCTL1 & CCIFG) TA1CCTL1 &= ~CCIFG;

        once_pro(); // 嘗試觸發測量
    }
}

關鍵技術點解析

1. Timer_A 捕獲模式測量脈衝寬度

  • CM_2:下降沿捕獲。Trig 觸發後,Echo 拉高 → Timer 開始計數 → Echo 拉低 (下降沿) → 硬體自動將 TA1R 值鎖存至 TA1CCR1 並觸發中斷。
  • CCIS_1:選擇 CCI1B (P2.2) 作為捕獲輸入源。
  • SCS:同步捕獲,避免競態。

2. 距離計算公式推導

聲速 v ≈ 340 m/s = 340,000 mm/s
往返時間 t = current_time / SYS_CLK (秒)
單程距離 d = v * t / 2 = 340,000 * (current_time / SYS_CLK) / 2
          = 170,000 * current_time / SYS_CLK (mm)
程式碼: 340 * (0.5 * current_time / SYS_CLK) * 1000 → 等價

3. 非阻塞架構設計

  • 主循環 while(1) 輕量輪詢按鍵狀態,發起觸發。
  • 測量過程完全由硬體 Timer + 中斷自動完成,CPU 空閒。
  • 結果在捕獲中斷中觸發 UART TX 中斷異步發送。

4. 字串格式化優化

  • 定點數轉字串避免 printf/sprintf 佔用大量 Flash/RAM。
  • 過濾前導零:將 " 12.3" 發送為 "12.3",節省頻寬。

PC 端驗證方法

  1. USB-TTL 轉接板連接 P1.2 (TX)、GND。
  2. 串口工具 (PuTTY, SecureCRT, Arduino Serial Monitor) 設定 9600, 8, N, 1。
  3. 按住開發板 S2 按鍵 (P1.3),觀察輸出:
 Current distance:  12.3 cm
 Current distance:  12.4 cm
 Current distance:  12.3 cm

常見問題排查

擴展方向

  • 加入 WDT 間歇喚醒 + LPM3 低功耗模式,電池供電場景。
  • 多傳感器時分複用:單 Timer 多通道捕獲或 GPIO 模擬多路 Trig。
  • Kalman 濾波平滑抖動數據。
  • 移植至 MSP430FR 系列 (FRAM 非易失性記憶體) 實現斷電保護數據記錄。

這個精簡固件展示了 MSP430 硬體外設 (Timer 捕獲、UART、GPIO、中斷) 協同工作的經典模式,是超聲波測距、紅外測速、脈寬調制等時序敏感應用的範本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
現象可能原因解決
無輸出 / 亂碼波特率不匹配、TX 腳位錯誤、GND 未共地核對 UCA0BR0/BR1、P1SEL/P1SEL2、共地
距離異常大/為 0Echo 腳位未接/接錯、Timer 捕獲配置錯誤、超時無回波檢查 P2.2 連線、CM_2/CCIS_1 設定、加入超時邏輯
按鍵無反應上拉電阻未使能、按鍵接法反向P1REN|=SW_2; P1OUT|=SW_2; 確認原理圖
LED 長亮不滅捕獲中斷未觸發、CCIFG 未清除導致 while 死循環檢查 ISR 中 TA1CCTL1 &= ~CCIFG、Echo 信號質量