
簡介這份資源是面向工業(yè)自動化初學者與嵌入式開發(fā)者的空壓機控制軟件工程包基于C8051微控制器與C語言實現(xiàn)重點解決壓縮機運行中溫度、壓力實時監(jiān)測與安全保護問題。包內共151個文件以69個h頭文件、39個inc包含文件、12個c源文件為核心代碼另有obj、lst編譯中間文件、lib庫文件、uvproj與uvopt工程配置、hex燒錄文件及少量jpg截圖壓縮包約2.66MB結構完整可直接導入Keil環(huán)境編譯研究。軟件通過ADC采集溫度與壓力傳感器信號設定閾值觸發(fā)過溫保護與加載卸載調節(jié)并借助UART、SPI及LCD或LED實現(xiàn)人機交互與遠程數據交換還包含F(xiàn)lash讀寫、按鍵處理、系統(tǒng)調度等模塊便于理解實際項目代碼組織方式。目前已有634人學習下載適合希望掌握C8051外設驅動、傳感器集成與壓縮機控制邏輯的讀者參考借鑒。1. 空壓機控制軟件從傳感器采樣到繼電器輸出的完整閉環(huán)空壓機控制軟件聽起來像是工業(yè)現(xiàn)場才用得上的東西但真把它拆開看核心邏輯并不復雜一顆 C8051 單片機定時讀溫度傳感器跟設定閾值比較決定壓縮機啟停、風扇轉停同時把狀態(tài)碼刷到數碼管或串口屏上。這套邏輯跑在螺桿機、活塞機、渦旋機的控制板上管的是排氣溫度、油溫、電機過載這些要命的參數。我手上這份源碼包就是一套典型的空壓機控制器固件C8051F 系列 MCU 打底NTC 熱敏電阻做溫度采集繼電器組驅動接觸器和風扇帶 RS485 上傳。適合誰看做工業(yè)控制固件的、接非標設備改造的、想拿一套能跑通的 C8051 項目練手的都能從里面摳出能直接復用的模塊。溫度采樣這塊的玄學在于 NTC 非線性查表還是算 Steinhart-Hart代碼里怎么處理后面細說。2. 硬件抽象層拆解C8051 外設初始化與溫度采樣鏈路2.1 系統(tǒng)時鐘與 ADC 配置C8051F 系列跟 STM32 不一樣它的交叉開關和優(yōu)先權交叉開關是繞不開的坎。這份代碼里系統(tǒng)時鐘配到 24.5MHz 內部振蕩器ADC0 用定時器 2 溢出觸發(fā)采樣率設在 1kHz 左右。為什么不用軟件查詢因為空壓機現(xiàn)場干擾大軟件查詢容易采到開關噪聲定時器觸發(fā)能保證采樣間隔均勻后面做滑動濾波才有意義。// 系統(tǒng)時鐘與ADC初始化C8051F340 void SysClk_Init(void) { OSCICN 0x83; // 使能內部振蕩器不分頻24.5MHz CLKSEL 0x00; // 時鐘源選內部振蕩器 while((OSCICN 0x10) 0); // 等待振蕩器穩(wěn)定 } void ADC0_Init(void) { REF0CN 0x03; // 使能內部基準VREF2.4V AMX0P 0x0C; // P3.0作為ADC0正輸入接NTC分壓 ADC0CF 0xF8; // 轉換時鐘系統(tǒng)時鐘/8增益1 ADC0CN 0x02; // 定時器2溢出觸發(fā)右對齊 EIE1 | 0x08; // 使能ADC0轉換結束中斷 AD0EN 1; // 使能ADC0 }這里有個參數要盯住ADC0CF 0xF8把 SAR 時鐘設成 3MHz 左右24.5MHz 系統(tǒng)時鐘下轉換一次大概 2.5us留足了采樣保持時間。AMX0P 0x0C選的是 P3.0 通道對應 NTC 分壓點。如果你換板子這個通道號得跟著原理圖改改錯了采回來就是滿量程或者零別問我是怎么知道的。2.2 NTC 溫度換算查表加線性插值NTC 10K 的阻值-溫度曲線是非線性的直接套公式算浮點對 C8051 來說太奢侈。代碼里用的是分段查表加線性插值表按 5℃ 一檔存 ADC 碼值實際溫度落在兩檔之間就插值。這樣既省 CPU精度也能做到 ±0.5℃ 以內對空壓機排氣溫度保護來說夠用了。// NTC溫度查表-20℃到150℃5℃一檔 const unsigned int NTC_Table[] { 3720, 3510, 3280, 3040, 2790, 2540, 2290, 2050, 1820, 1600, 1400, 1220, 1060, 920, 790, 680, 580, 495, 420, 355, 300, 253, 213, 180, 152, 128, 108, 91, 77, 65, 55, 47, 40, 34, 29 }; int Get_Temperature(unsigned int adc_val) { unsigned char i; int temp; // 超出表格范圍直接返回邊界值 if(adc_val NTC_Table[0]) return -20; if(adc_val NTC_Table[34]) return 150; for(i 0; i 34; i) { if(adc_val NTC_Table[i1] adc_val NTC_Table[i]) { // 線性插值溫度 低檔溫度 比例 * 5℃ temp -20 i * 5; temp (int)((long)(NTC_Table[i] - adc_val) * 5 / (NTC_Table[i] - NTC_Table[i1])); return temp; } } return 0; }NTC_Table數組是按 ADC 碼值從大到小排的因為溫度越高 NTC 阻值越小分壓點電壓越低ADC 碼值越小。插值那行用long強轉是為了防止乘法溢出C8051 的 int 是 16 位(NTC_Table[i] - adc_val) * 5最大能到 18000 多不轉 long 會翻車。這個表你得根據自己用的 NTC 型號重新標定B 值不同曲線差很多直接抄表溫度能偏出十幾度。2.3 滑動濾波與斷線檢測ADC 采回來的原始值不能直接用現(xiàn)場接觸器吸合那一下能干擾出幾十個碼值的跳動。代碼里做了 8 點滑動平均同時判斷采樣值是否在合理范圍內超出范圍認為傳感器斷線直接報故障停機。#define FILTER_LEN 8 unsigned int Adc_Buf[FILTER_LEN]; unsigned char Buf_Index 0; unsigned int Filter_Adc(unsigned int new_val) { unsigned long sum 0; unsigned char i; Adc_Buf[Buf_Index] new_val; Buf_Index (Buf_Index 1) % FILTER_LEN; for(i 0; i FILTER_LEN; i) { sum Adc_Buf[i]; } return (unsigned int)(sum / FILTER_LEN); } // 斷線檢測ADC值持續(xù)為滿量程或零 bit Check_Sensor_Open(unsigned int adc_val) { static unsigned char open_cnt 0; if(adc_val 4000 || adc_val 20) { open_cnt; if(open_cnt 50) { // 連續(xù)50次異常約50ms open_cnt 0; return 1; // 傳感器斷線 } } else { open_cnt 0; } return 0; }濾波長度 8 是我試出來的平衡點再長響應就遲鈍了排氣溫度漲得快的時候保護會滯后。斷線檢測的閾值 4000 和 20 對應分壓電路的上拉和下拉極限你要是改了分壓電阻這兩個數得跟著調。open_cnt 50是防抖避免干擾脈沖誤報。3. 控制邏輯實現(xiàn)閾值比較、狀態(tài)機與繼電器輸出3.1 壓縮機啟停狀態(tài)機空壓機的啟停不是簡單的大于開小于關得有回差、有延時、有故障鎖死。代碼里用了一個四狀態(tài)機待機、啟動延時、運行、故障。溫度超過上限進入啟動延時延時到了才吸合接觸器溫度降到下限以下再延時停機防止頻繁啟停把接觸器燒了。typedef enum { STATE_IDLE 0, STATE_START_DELAY, STATE_RUNNING, STATE_FAULT } SystemState; SystemState sys_state STATE_IDLE; unsigned int delay_cnt 0; void Control_Logic(int temp) { switch(sys_state) { case STATE_IDLE: if(temp TEMP_START) { // 超過啟動閾值 sys_state STATE_START_DELAY; delay_cnt 0; } break; case STATE_START_DELAY: delay_cnt; if(delay_cnt START_DELAY_MS) { // 啟動延時到 RELAY_MAIN 1; // 吸合主接觸器 RELAY_FAN 1; // 風扇同時啟動 sys_state STATE_RUNNING; } if(temp TEMP_START - TEMP_HYST) { // 溫度回落取消啟動 sys_state STATE_IDLE; } break; case STATE_RUNNING: if(temp TEMP_STOP) { // 低于停機閾值 RELAY_MAIN 0; RELAY_FAN 0; sys_state STATE_IDLE; } if(temp TEMP_FAULT) { // 超溫故障 RELAY_MAIN 0; RELAY_FAN 0; sys_state STATE_FAULT; } break; case STATE_FAULT: RELAY_MAIN 0; RELAY_FAN 0; // 需要手動復位或斷電重啟才能退出 if(FAULT_RESET_BTN 0 temp TEMP_START) { sys_state STATE_IDLE; } break; } }TEMP_START、TEMP_STOP、TEMP_FAULT這三個閾值一般設 85℃、75℃、105℃回差TEMP_HYST給 5℃。啟動延時START_DELAY_MS通常 3000 到 5000ms看電機功率。故障狀態(tài)必須手動復位這是血淚教訓——自動復位的話傳感器真壞了會反復啟停把機頭干廢。3.2 繼電器輸出與互鎖繼電器輸出這塊有個坑C8051 的 IO 口上電默認是高阻如果繼電器驅動電路是低電平有效上電瞬間會全部吸合一下。代碼里在初始化最前面就把所有繼電器口置高硬件上再加下拉電阻。// 繼電器引腳定義低電平有效 sbit RELAY_MAIN P1^0; // 主接觸器 sbit RELAY_FAN P1^1; // 風扇 sbit RELAY_ALARM P1^2; // 報警輸出 void Relay_Init(void) { P1MDOUT | 0x07; // P1.0-P1.2推挽輸出 P1 | 0x07; // 先全部置高繼電器不動作 RELAY_MAIN 1; RELAY_FAN 1; RELAY_ALARM 1; } // 互鎖風扇故障時禁止啟動主電機 bit Check_Interlock(void) { if(RELAY_FAN 0 FAN_FEEDBACK 1) { return 0; // 風扇沒轉起來不允許啟動主機 } return 1; }P1MDOUT設推挽是為了驅動能力夠直接推光耦或者三極管?;ユi邏輯里FAN_FEEDBACK是風扇接觸器的輔助觸點沒有這個反饋風扇皮帶斷了主機還在轉機頭幾分鐘就過熱。這個互鎖在代碼里是硬判斷不經過狀態(tài)機任何情況下風扇沒反饋都不讓主機吸合。3.3 故障碼存儲與串口上傳故障碼存在片內 Flash 里掉電不丟。C8051F340 有 4KB 的 Flash 可以當 EEPROM 用代碼里劃了最后 512 字節(jié)存故障記錄每條記錄 8 字節(jié)循環(huán)覆蓋。#define FAULT_BASE 0xF000 // 故障記錄起始地址 #define FAULT_MAX 64 // 最多存64條 typedef struct { unsigned char code; // 故障碼 int temp; // 故障時溫度 unsigned int runtime; // 累計運行時間 unsigned char reserved; } FaultRecord; void Save_Fault(unsigned char code, int temp) { unsigned char i; FaultRecord rec; unsigned int addr; rec.code code; rec.temp temp; rec.runtime total_runtime; // 找空位或覆蓋最舊 for(i 0; i FAULT_MAX; i) { addr FAULT_BASE i * sizeof(FaultRecord); if(Flash_Read_Byte(addr) 0xFF) { break; } } if(i FAULT_MAX) i 0; // 滿了從頭覆蓋 addr FAULT_BASE i * sizeof(FaultRecord); Flash_Write(addr, (unsigned char *)rec, sizeof(FaultRecord)); }Flash_Write是底層擦寫函數C8051 寫 Flash 前必須先擦除整個扇區(qū)所以實際代碼里是先把整個扇區(qū)讀到 RAM改完再擦再寫回去。這個操作耗時大概 20ms期間不能斷電否則記錄全丟。我一般會在寫之前先把看門狗喂了再關中斷寫完再開。4. 避坑與排查C8051 空壓機控制器的常見翻車點4.1 溫度跳變導致頻繁啟?,F(xiàn)象是空壓機運行幾分鐘就停停了沒一會又啟接觸器啪啪響。原因多半是 NTC 采樣線跟電機線走在一起了變頻器或者接觸器線圈的干擾耦合進來ADC 值跳變超過回差。解決分兩步硬件上把 NTC 線換成屏蔽線屏蔽層單端接地軟件上把滑動濾波長度從 8 加到 16同時在狀態(tài)機里加一個“溫度必須連續(xù) 3 次超過閾值才動作”的判斷。4.2 上電繼電器瞬間吸合前面提過C8051 的 IO 上電默認高阻如果驅動電路是低有效上電瞬間繼電器會抖一下?,F(xiàn)象是每次上電空壓機“啪”一聲接觸器吸合又斷開。解決是在main函數最開頭、任何外設初始化之前先把繼電器口置高同時硬件上加 10K 下拉電阻到地。代碼順序不能反先配P1MDOUT再置高否則推挽沒開置高也沒驅動能力。4.3 Flash 寫故障記錄導致看門狗復位C8051 擦寫 Flash 的時候 CPU 會停頓如果看門狗沒處理直接復位。現(xiàn)象是每次存故障記錄就重啟故障碼還存不進去。解決是在Flash_Write前后加WDT_Feed()并且把看門狗超時設到最長。更穩(wěn)妥的做法是存故障前先關看門狗存完再開但這樣萬一寫 Flash 卡死就沒救了我一般還是喂狗。4.4 RS485 通信在電機啟動時丟包現(xiàn)象是空壓機一啟動上位機就報通信中斷。原因是 RS485 收發(fā)器跟電機共地地電位跳變導致差分信號超范圍。解決是給 RS485 加隔離模塊或者至少把 A/B 線換成雙絞屏蔽線屏蔽層接大地。軟件上把通信超時從 1s 放寬到 3s給重傳留時間。4.5 溫度查表精度不夠有人直接抄了 10K B3950 的表結果實際用的 NTC 是 B3435溫度差出 8℃ 以上?,F(xiàn)象是排氣溫度顯示 95℃實際才 87℃保護提前動作。解決是拿恒溫槽標定從 20℃ 到 120℃ 每隔 10℃ 記 ADC 值重新生成表格。沒有恒溫槽的話至少用冰水混合物和沸水標兩個點反推 B 值修正。5. 二次開發(fā)改造從單機控制到多機聯(lián)控的擴展思路拿到這份源碼想改造成自己的東西最直接的路子是先把溫度采樣和繼電器輸出這兩個模塊吃透然后按自己的硬件改引腳和閾值。但如果你要做多臺空壓機聯(lián)控就得動架構了。我一般會這么干把單機控制邏輯封裝成一個獨立的任務函數主循環(huán)里用時間片輪詢每臺機器一個狀態(tài)機實例通過 RS485 或者 CAN 交換啟停請求和故障狀態(tài)。// 多機聯(lián)控的調度框架 #define MAX_UNITS 4 typedef struct { SystemState state; int temp; unsigned int delay_cnt; unsigned char fault_code; unsigned char addr; // 從站地址 } CompressorUnit; CompressorUnit units[MAX_UNITS]; void Main_Loop(void) { unsigned char i; static unsigned int tick 0; for(i 0; i MAX_UNITS; i) { // 每10ms調度一臺4臺輪一圈40ms if((tick % MAX_UNITS) i) { units[i].temp Get_Temperature( Filter_Adc(ADC_Read(units[i].addr))); Control_Logic_Unit(units[i]); } } tick; // 聯(lián)控邏輯根據總管壓力決定啟停臺數 if(tick % 100 0) { Cascade_Control(units, MAX_UNITS); } }這個框架的關鍵是把Control_Logic改成帶實例參數的版本所有狀態(tài)變量從全局挪到結構體里。Cascade_Control負責讀總管壓力壓力低于下限就按運行時間最短的優(yōu)先啟動高于上限就按運行時間最長的優(yōu)先停。輪詢周期 40ms 對空壓機來說綽綽有余溫度變化是秒級的。改造時驗證方法很簡單先用信號發(fā)生器模擬 NTC 分壓從 0.5V 掃到 2.0V看每臺機器的狀態(tài)切換和繼電器動作是否跟單機版一致。然后接實際傳感器用熱風槍加熱看聯(lián)控邏輯能不能正確加減載。最后跑 72 小時老化重點盯 Flash 故障記錄有沒有丟、RS485 有沒有累積錯誤。從那以后我每次改完控制邏輯都強制走一遍“模擬傳感器全量程掃描 繼電器動作記錄 故障注入”這三步少一步都不敢上機。希望幫到你。本文還有配套的精品資源點擊獲取