)
簡介基于STM32F103的四路MAX6675溫度采集工程面向嵌入式學習者與開發(fā)者解決多通道K型熱電偶數據采集、LCD1602實時顯示與串口上傳問題。工程完整既可直接燒錄驗證也可對照學習STM32的SPI主機配置、多從機片選切換、定時采樣及UART打印等關鍵環(huán)節(jié)。壓縮包共216個文件以c/h源碼、uvprojx工程、axf/hex固件及crf/o編譯中間文件為主sct鏈接腳本、map映射表等輔助文件齊全體積7.65MB便于排查鏈接與編譯細節(jié)。當前已有1143人學習。內容包含標準外設庫驅動、四路MAX6675共用SPI總線的采樣子程序、LCD1602顯示邏輯及串口輸出格式配套工程可快速移植到同類多點測溫項目中。通過閱讀代碼能掌握從硬件接線、SPI時序到人機交互與數據上送的完整開發(fā)流程適合作為STM32傳感器采集類項目的參考模板。 做過多路溫度采集項目的朋友應該都有體會單個傳感器方案好寫一旦擴展到四路、八路問題就全來了——通道之間互相干擾、SPI時序對不上、串口數據亂成一團、屏幕上顯示錯位。我這次把一個完整可跑的方案整理出來STM32F103 最小系統(tǒng)板做主機掛四路 MAX6675 模塊采集熱電偶溫度數據同時輸出到 LCD1602 顯示并通過串口打印到調試助手。整個工程文件打包后命名為“STM32F103 驅動四路MAX6675 采集溫度 LCD1602顯示 串口打印數據.zip”正好把硬件接線、軟件代碼、調試方法都包含了。這篇文章把我實際調通的思路和踩過的坑原樣寫出來供正在做類似項目的朋友參考。這套東西適合誰剛接觸 STM32 但已經會用標準庫跑 GPIO、USART 的人想從單路采集往多路擴展的或者需要在設備上配一個人機交互界面但又不想上屏幕方案太復雜的都可以直接照這個思路改。我會把每一條連線、每一段關鍵代碼、以及為什么這么寫的原因都講清楚保證你照著做能跑通。1. 項目整體思路四路溫度采集系統(tǒng)從需求到選型1.1 需求拆解與方案選型這個項目核心要解決的事情是用一塊主控芯片同時讀取四路 K 型熱電偶的溫度值然后一路送到 LCD1602 上顯示一路通過串口發(fā)送到上位機。聽起來不復雜但當你真的把四個 MAX6675 掛在同一條 SPI 總線上時就會遇到一個非常實際的問題——MAX6675 不是普通 SPI 從機它沒有寄存器地址每次片選拉低之后直接從 SO 引腳吐 16 位數據所以多路擴展只能靠片選去區(qū)分。選型上我沒有直接上 STM32F4 或者加外部 ADC而是選擇 STM32F103 四片 MAX6675原因很直接F103 的 SPI 外設完全夠用72MHz 主頻下跑這幾個傳感器綽綽有余MAX6675 自帶冷端補償和數字輸出省掉了熱電偶信號調理電路比用運放加 ADC 的方案簡單太多。單路 MAX6675 是 0.25℃ 分辨率測 0 到 1023.75℃ 范圍K 型熱電偶的典型應用場景都覆蓋了。有人會問為什么不用 DS18B20它便宜而且同樣是單總線但測溫范圍只有 -55 到 125℃工業(yè)環(huán)境測個發(fā)熱體、測個烤箱溫度就完全無能為力了。熱電偶加 MAX6675 才是這類場景的正解雖然單路成本稍高但換來的是量程和抗干擾能力。1.2 系統(tǒng)框架與數據流向整體數據流是這樣走的四路 MAX6675 的 SO 輸出線并接到同一個 GPIO 輸入引腳我這里用的是軟件模擬 SPI后文會講原因SCK 共用一根引腳每路各占一根片選 CS。主控輪流拉低不同通道的 CS等一小段時間后讀出 16 位數據換算成實際溫度值存入一個 float 數組。然后主循環(huán)里每隔幾百毫秒刷新一次 LCD1602 顯示同時通過串口中斷或輪詢方式把格式化好的字符串發(fā)給上位機。我用的是標準外設庫而不是 HAL 庫因為這種老項目在很多代碼倉庫里都是標準庫寫的移植起來方便而且像 F103 這種芯片標準庫的代碼量更少邏輯更直觀。軟件模擬 SPI 而不是用硬件 SPI也是因為四路 MAX6675 共用時鐘和數據線時軟件控制片選更靈活不用擔心硬件 SPI 從機管理帶來的片選信號同步問題。實際跑下來四路全部讀完一次也就幾毫秒完全不影響實時性。2. 硬件設計與連接細節(jié)2.1 STM32F103 與四路 MAX6675 的接線接線是整個項目里最容易出問題的一步別急著上電先把線對清楚。我用的最小系統(tǒng)板是 F103C8T6MAX6675 模塊是市面上最常見的紅色小板上面自帶 K 型熱電偶插座和濾波電容。四個模塊的 SO 引腳全部連接到單片機的 PB14MISO 方向SCK 全部連接到 PB13四路 CS 分別連接到 PA4、PA5、PA6、PA7。這里有個關鍵點四個 SO 引腳并在一起相當于開漏輸出再接一個公共上拉但 MAX6675 模塊的 SO 本身是推挽輸出所以不需要額外上拉直接并接即可。如果你發(fā)現并接之后某一路讀數不正常檢查一下是不是某個模塊的 CS 沒有完全拉高處于半選通狀態(tài)此時它會繼續(xù)往總線上輸出數據把其他通道的數據給干擾了。模塊供電統(tǒng)一接 3.3V注意不要接 5V。雖然很多 MAX6675 模塊上帶了穩(wěn)壓芯片能接受 5V 輸入但直接接 5V 后SO 輸出高電平會達到 5V而 STM32F103 的 GPIO 并不都是 5V 容忍的PB14 如果配置成輸入模式耐壓有限很容易把引腳搞壞。我在這上面燒過一塊芯片后來學乖了全部統(tǒng)一 3.3V 供電。2.2 LCD1602 顯示模塊的連接與電平問題LCD1602 是 5V 器件的典型代表而 STM32F103 的 GPIO 輸出是 3.3V直接接邏輯電平理論上能驅動但存在兩個隱患一是 3.3V 高電平對于 5V 供電的 LCD1602 來說可能達不到 VIH 閾值導致命令識別不穩(wěn)定二是 LCD1602 背光電路如果直接吃 5V控制引腳電平需要串電阻限流否則長時間運行會發(fā)熱。我的做法是LCD1602 供電接 5V但數據線和控制線通過 1kΩ 電阻串聯后接到 STM32 引腳上實測非常穩(wěn)定。RS 接 PB0EN 接 PB1D4-D7 接 PB2-PB5。用四線模式而不是八線模式省四個引腳。對比度調節(jié)引腳 V0 接一個 10kΩ 電位器中間抽頭接到 V0這個電位器必須接否則屏幕上可能什么都看不到這是很多新手第一次點不亮 LCD 的最大原因不是代碼問題是硬件對比度沒調好。2.3 電源、地線與噪聲處理四路 MAX6675 同時工作時的功耗并不大主要電流來自 LCD 背光和芯片本身但有一個坑要注意熱電偶線本身是一根金屬導線如果走線很長會像天線一樣接收環(huán)境噪聲尤其是工業(yè)現場有電機、開關電源的時候讀數可能產生跳動。我的處理方式是在 MAX6675 模塊的電源引腳旁邊加一個 10μF 電解電容和一個 0.1μF 陶瓷電容做二級濾波。模塊上本身有小電容但外加電容對長電源線的壓降和紋波有明顯的改善作用。另外熱電偶線不要和電源線、電機驅動線綁在一起走盡量分開。如果傳感器離主板很遠建議用屏蔽線屏蔽層單端接地。這些經驗都是從實際測試里得來的我在實驗室里第一次測試時就是因為熱電偶線繞過了開關電源讀數一直跳后來把線重新走位后才穩(wěn)定下來。3. 軟件實現與核心代碼解析3.1 SPI 初始化與多路片選管理軟件模擬 SPI 的好處是可以隨便映射引腳不受硬件外設引腳復用限制代碼邏輯也直白。初始化時把 PB13 配成推挽輸出PB14 配成浮空輸入或上拉輸入PA4-PA7 全部推挽輸出并默認拉高。這里要特別強調CS 引腳默認必須拉高否則上電瞬間 MAX6675 處于未知狀態(tài)可能在 SO 線上產生毛刺影響第一次讀取。實際讀取時先把對應通道的 CS 拉低然后延時 1-2 微秒再開始產生 16 個 SCK 上升沿。為什么要在 CS 拉低后延時因為 MAX6675 內部在 CS 下降沿后需要一小段時間準備數據如果立刻給時鐘讀到的前幾位可能不是有效數據。很多移植失敗的例子就是少了這個延時。每次讀完把 CS 拉高完成一次通道切換。// 片選引腳宏定義 #define CS1_PORT GPIOA #define CS1_PIN GPIO_Pin_4 #define CS2_PORT GPIOA #define CS2_PIN GPIO_Pin_5 #define CS3_PORT GPIOA #define CS3_PIN GPIO_Pin_6 #define CS4_PORT GPIOA #define CS4_PIN GPIO_Pin_7 #define SCK_PORT GPIOB #define SCK_PIN GPIO_Pin_13 #define SO_PORT GPIOB #define SO_PIN GPIO_Pin_14 uint16_t MAX6675_Read(uint16_t cs_port, uint16_t cs_pin) { uint16_t value 0; GPIO_WriteBit(cs_port, cs_pin, Bit_RESET); delay_us(2); for (uint8_t i 0; i 16; i) { GPIO_WriteBit(SCK_PORT, SCK_PIN, Bit_SET); delay_us(1); value 1; if (GPIO_ReadInputDataBit(SO_PORT, SO_PIN)) { value | 0x0001; } GPIO_WriteBit(SCK_PORT, SCK_PIN, Bit_RESET); delay_us(1); } GPIO_WriteBit(cs_port, cs_pin, Bit_SET); return value; }3.2 MAX6675 數據讀取與溫度換算MAX6675 每次輸出 16 位數據其中 bit15 始終為 0bit14 到 bit3 是溫度數據bit2 是熱電偶開路標志為 1 時表示熱電偶斷線或沒插好。溫度值的換算公式很直接把 bit14 到 bit3 這 12 位數據右移 3 位再乘以 0.25得到的就是實際溫度值單位是攝氏度。舉個例子讀到的原始值是 0x01B4二進制是 0000 0001 1011 0100。右移 3 位得到 0x36也就是十進制 54乘以 0.25 等于 13.5℃。這個換算過程在代碼里就一行但要注意數據類型的處理右移之前不能把 uint16_t 強轉成 int8_t否則高位會被截斷負溫度場景下直接就錯了。另外MAX6675 有熱電偶開路檢測讀取完成后先判斷 bit2 是否為 1如果是說明熱電偶斷開或者沒接好這時候溫度值沒有意義我習慣返回一個特殊值比如 -1000表示異常狀態(tài)方便上位機顯示報警。別忽略這個位它能幫你快速定位是傳感器問題還是程序問題。float MAX6675_GetTemp(uint16_t cs_port, uint16_t cs_pin) { uint16_t raw MAX6675_Read(cs_port, cs_pin); if (raw 0x0004) // 熱電偶開路檢測位 { return -1000.0f; } return (float)(raw 3) * 0.25f; }實際使用時四個通道輪流讀取每次讀取間隔建議至少 200 毫秒。因為 MAX6675 內部完成一次溫度轉換大約需要 170-220 毫秒如果連續(xù)快速讀取讀到的可能是上一次的舊數據或者轉換中間的不穩(wěn)定數據。我最初為了刷新率把讀取間隔壓到 50 毫秒結果四路數據輪流跳變后來在循環(huán)里加了一個 250 毫秒的延時數據就非常穩(wěn)定了。3.3 LCD1602 顯示與串口打印LCD1602 的驅動代碼網上很多但我這兒要提醒幾個容易忽略的細節(jié)。初始化時4 位模式必須按數據手冊規(guī)定的時序來先發(fā) 0x03 三次再發(fā) 0x02 切換到 4 位模式然后才是功能設置、顯示開關、清屏等命令。很多人直接套用網上代碼結果因為時序問題導致顯示亂碼問題就出在初始化階段。顯示邏輯上我用的是比較簡單的方式把四路溫度分別格式化到兩行顯示第一行顯示 CH1 和 CH2第二行顯示 CH3 和 CH4。每行可以顯示 16 個字符四路溫度加標識符綽綽有余。顯示溫度時要處理異常值如果返回值是 -1000就顯示 ERR 而不是一個怪異的數字。串口部分我用的 USART1PA9 做 TXPA10 做 RX波特率 1152008 位數據位1 位停止位無校驗。調試助手用常見的串口助手軟件就行注意 CH340 驅動要先裝好設備管理器里能看到 COM 口才能連上。打印格式我是這樣組織的printf(CH1: %.2f C CH2: %.2f C\r\n, temp[0], temp[1]); printf(CH3: %.2f C CH4: %.2f C\r\n, temp[2], temp[3]);記得在工程里重定向 fputc 函數到串口發(fā)送不然 printf 輸出到不了串口int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); return ch; }4. 調試過程與常見問題排查4.1 溫度讀數異常問題我調試過程中遇到的最典型問題是某一通道讀數始終是 0℃ 或者固定跳到某個數值。這種情況九成是熱電偶插反或者接觸不良。MAX6675 模塊上的熱電偶插座是有極性的K 型熱電偶的紅色線一般接正極黃色線接負極插反了溫度顯示會異常。還有一次是熱電偶插頭氧化導致接觸電阻變大讀數持續(xù)跳動。另外一類問題是所有通道都讀到同一個值而且這個值不變化。這多半是片選引腳配置問題比如四路 CS 全部被拉低了SO 總線同時被多個芯片驅動讀出來的數據是拼湊的亂碼。排查方法很簡單用萬用表量 CS 引腳電平確認只有當前通道是低電平。4.2 LCD1602 不顯示或顯示亂碼LCD1602 不顯示先查三件事對比度電位器調了沒有、背光正不正常、電源是不是 5V。我見過太多人在這上面折騰半天結果就是 V0 沒接電位器或者電位器旋到了最暗的位置。對比度調節(jié)的標準方法是慢慢旋轉電位器直到屏幕上出現一排黑色方塊。顯示亂碼的原因大多是初始化時序不對。我的經驗是每次寫命令或數據之間至少延時 1-2 毫秒特別是清屏命令需要更長的延時。如果 4 位模式下 D4-D7 接反了或者 RS、EN 接錯也會出現亂碼。檢查方法是用示波器看 EN 引腳確認每次寫入時 EN 有下降沿。4.3 串口打印數據異常串口打印出來是亂碼優(yōu)先級最高的是波特率配置。檢查 USART 初始化時 BRR 寄存器計算是否正確尤其是外部晶振頻率和你代碼里寫的 HSE_VALUE 是否一致。我用的是 8MHz 外部晶振如果代碼誤配成 12MHz波特率就會偏得離譜上位機收到全是亂碼。其次檢查 USB 轉 TTL 模塊的 TX、RX 有沒有接反。STM32 的 TX 要接模塊的 RXSTM32 的 RX 接模塊的 TX交叉連接這是新手最容易犯的錯誤。4.4 多路采集相互干擾的處理四路同時采集時如果發(fā)現某一路讀數會輕微影響其他路多半是讀取切換時產生的電氣干擾。我的解決方法是每讀完一路后將 CS 拉高然后延時 5 毫秒再操作下一路讓 SO 總線上的電平有一個穩(wěn)定的過程。如果還不行檢查四路模塊是否共地如果共地點接觸不良也會產生壓差干擾。還有一種情況是熱電偶引線過長感應到工頻干擾??梢园巡蓸又底鲆淮魏唵蔚幕瑒悠骄鶠V波比如連續(xù)讀五次去掉最大最小值再取平均雖然 MAX6675 本身已經有數字濾波但工程環(huán)境下加上軟件濾波會明顯提高穩(wěn)定性。一點實際體會最后再說一個我在測試時發(fā)現的細節(jié)MAX6675 手冊上寫的轉換時間可能因模塊設計和供電電壓不同而略有變化。我實際測試時四路通道在 3.3V 供電下200 毫秒的間隔穩(wěn)定可靠但如果我把電壓降到 3.1V 以下讀數偶爾會出現跳變說明模塊在低壓邊緣工作不穩(wěn)定。如果你的系統(tǒng)供電電壓有波動建議在程序里檢測 MAX6675 的異常值位同時電源部分多留點余量。這個項目整體調試下來最難的不是代碼而是硬件細節(jié)和耐心排查希望這份經驗能幫你少走彎路。本文還有配套的精品資源點擊獲取