議與調(diào)試避坑指南)
簡(jiǎn)介針對(duì)馬肯依碼士9410-9450系列噴碼機(jī)這套串口通訊實(shí)例資源提供了從協(xié)議規(guī)范到可運(yùn)行代碼的完整參考適合上位機(jī)開(kāi)發(fā)、設(shè)備集成及產(chǎn)線數(shù)據(jù)采集場(chǎng)景中的自動(dòng)化工程師和嵌入式開(kāi)發(fā)者重點(diǎn)解決串口通訊中協(xié)議幀格式不清晰、缺少立即可用代碼、聯(lián)調(diào)排錯(cuò)難等實(shí)際問(wèn)題。整個(gè)壓縮包共57個(gè)文件約1.76MB以16個(gè)C#源碼文件、sln/csproj工程方案及可直接運(yùn)行的exe為主體同時(shí)附有英文協(xié)議PDF、必讀使用說(shuō)明RTF、項(xiàng)目升級(jí)日志、README、配置文件和圖片素材等輔助材料其中的resx、settings、resources等文件保存了界面與初始化配置pdb調(diào)試符號(hào)及相關(guān)輔助文件也便于追蹤工程細(xì)節(jié)既支持直接運(yùn)行觀察通訊效果也適合在Visual Studio中繼續(xù)調(diào)試和二次開(kāi)發(fā)。該資源在CSDN已有1343人學(xué)習(xí)屬于馬肯依碼士通訊協(xié)議方向較受關(guān)注的實(shí)例之一。通過(guò)閱讀協(xié)議文檔和SerialPortConnection示例讀者可以完整掌握9410-9450機(jī)型的串口參數(shù)配置、數(shù)據(jù)幀構(gòu)造與收發(fā)流程并可將示例代碼快速遷移至自己的上位機(jī)或產(chǎn)線項(xiàng)目中包內(nèi)備份工程和升級(jí)記錄還能幫助排查連接異常、比對(duì)版本差異降低實(shí)際部署門(mén)檻尤其適合需要快速落地噴碼機(jī)串口對(duì)接的工程場(chǎng)景。1. 馬肯依碼士9410-9450通訊協(xié)議為什么串口通訊實(shí)例比面板操作更值得先搭起來(lái)噴碼機(jī)如果只靠面板操作換一次打印內(nèi)容就要跑一趟產(chǎn)線批量記錄更是全靠人肉登記而馬肯依碼士9410/9450這類小字符噴碼機(jī)大多保留了串口通訊接口用一套ASCII指令就能把“改文本、啟停打印、查狀態(tài)、讀產(chǎn)量”全部交給上位機(jī)。這篇筆記基于我拆過(guò)的“馬肯依碼士9410-9450通訊協(xié)議串口通訊實(shí)例”資源先把協(xié)議文檔和實(shí)例例程的落地順序講清楚從RS232/RS485選型、串口參數(shù)確認(rèn)到一條實(shí)際打印指令的發(fā)送與回報(bào)確認(rèn)再把接PLC、排查串口通訊異常的坑列出來(lái)。適合剛接手產(chǎn)線設(shè)備集成的工程師也適合要把噴碼機(jī)并進(jìn)MES的熟手前者能照步驟跑通后者可以直接借狀態(tài)機(jī)和排查清單復(fù)用。2. 串口協(xié)議先讀物理層RS232/RS485、幀結(jié)構(gòu)與參數(shù)選型2.1 RS232 與 RS485 怎么選先看距離、干擾和地電位噴碼機(jī)串口看起來(lái)都是DB9但電氣層面差別很大。9410/9450的通訊口通常可以選擇RS232或RS485方式工作選哪個(gè)不是憑偏好而是看產(chǎn)線布局。RS232是全雙工發(fā)送和接收各自獨(dú)立調(diào)試時(shí)最直觀但抗干擾能力一般標(biāo)準(zhǔn)距離也就15米左右。工控機(jī)就在噴碼機(jī)旁邊用RS232最省事一旦距離超過(guò)20米或者線纜要經(jīng)過(guò)變頻器、伺服驅(qū)動(dòng)器附近RS232很容易出現(xiàn)偶發(fā)亂碼。RS485是半雙工用A、B兩根差分線傳輸抗共模干擾能力強(qiáng)很多現(xiàn)場(chǎng)最遠(yuǎn)跑到一千米也沒(méi)問(wèn)題。代價(jià)是同一時(shí)刻只能一個(gè)方向發(fā)數(shù)據(jù)程序里必須處理好方向切換和延時(shí)如果上位機(jī)剛發(fā)完指令立刻讀返回可能讀到的是自己發(fā)出去的殘余信號(hào)。另一個(gè)容易忽略的是地電位RS232兩端必須共地不共地輕則亂碼、重則燒通訊芯片RS485不強(qiáng)制共地但屏蔽層要單端接地不能兩端都接否則地環(huán)路電流會(huì)造成更隱蔽的丟包。這套實(shí)例包對(duì)應(yīng)的接線方式建議按資源里的“接線圖”頁(yè)來(lái)不要只看針腳號(hào)。常見(jiàn)的DB9定義里2是RXD、3是TXD、5是GND但有些噴碼機(jī)把2、3做了交叉標(biāo)的是DTE視角拿普通的直通串口線去插返回的永遠(yuǎn)是亂碼。先做一次回環(huán)測(cè)試確認(rèn)線序再接設(shè)備能省下一個(gè)下午這個(gè)動(dòng)作我在最后一章會(huì)展開(kāi)。2.2 串口參數(shù)波特率、數(shù)據(jù)位、校驗(yàn)位、停止位怎么確認(rèn)噴碼機(jī)的串口參數(shù)不是上位機(jī)軟件里隨手填的必須和噴碼機(jī)面板上的設(shè)置一致。9410/9450默認(rèn)常見(jiàn)值是9600 8 N 1也有一些固件版本出廠是19200 8 E 1。參數(shù)不一致時(shí)不會(huì)完全沒(méi)反應(yīng)常見(jiàn)現(xiàn)象是能收到數(shù)據(jù)但每個(gè)字符都是亂的或者返回長(zhǎng)度剛好差一個(gè)字節(jié)。我從實(shí)例包里的通訊協(xié)議PDF整理了一張速查表現(xiàn)場(chǎng)調(diào)串口時(shí)按這個(gè)順序核對(duì)參數(shù)常見(jiàn)值影響波特率9600 / 19200不高不低干擾大時(shí)優(yōu)先選9600數(shù)據(jù)位8必須與噴碼機(jī)一致校驗(yàn)位N / EE時(shí)幀多一個(gè)校驗(yàn)位長(zhǎng)度會(huì)變停止位1設(shè)成2也能通但時(shí)序變差流控?zé)o很多噴碼機(jī)不支持硬件流控開(kāi)了后反而鎖死注意不要把“校驗(yàn)位N”和“無(wú)校驗(yàn)”理解成可以隨便填。如果噴碼機(jī)面板設(shè)置的是8 E 1上位機(jī)寫(xiě)成8 N 1雙方對(duì)幀邊界的判斷就不一樣最容易出現(xiàn)“讀到了半個(gè)字節(jié)”的怪問(wèn)題。改參數(shù)時(shí)噴碼機(jī)側(cè)要進(jìn)入設(shè)置界面保存并重啟通訊口如果是生產(chǎn)中途發(fā)現(xiàn)參數(shù)不對(duì)最好在換班停線時(shí)再改線上熱切參數(shù)容易把當(dāng)前打印任務(wù)弄丟。2.3 幀結(jié)構(gòu)ASCII 明文幀和十六進(jìn)制幀先找結(jié)束符協(xié)議文檔拿到手第一件事不是讀命令列表而是先找“幀結(jié)構(gòu)”和“結(jié)束符”。9410/9450這類設(shè)備常用的是ASCII明文指令人眼能直接讀例如查詢狀態(tài)就是幾個(gè)字母加回車(chē)也有一些版本支持十六進(jìn)制幀用STX/ETX包起來(lái)末尾加校驗(yàn)。兩者差別很大上位機(jī)不能混用。這套協(xié)議文檔里的幀設(shè)計(jì)屬于典型的“STX功能碼數(shù)據(jù)ETXBCC”結(jié)構(gòu)發(fā)送時(shí)在幀尾再追加CRLF作為物理結(jié)束。整理成表格段長(zhǎng)度說(shuō)明STX1字節(jié)0x02幀頭功能碼1字節(jié)區(qū)分查詢、控制、寫(xiě)入數(shù)據(jù)變長(zhǎng)ASCII字符內(nèi)容視功能碼ETX1字節(jié)0x03幀內(nèi)容結(jié)束B(niǎo)CC1字節(jié)前面所有字節(jié)按位異或CRLF2字節(jié)0x0D 0x0A串口幀邊界為什么結(jié)束符重要因?yàn)榇谑橇魇降臎](méi)有包邊界上位機(jī)必須靠結(jié)束符判斷一幀收完了。很多工程師第一次聯(lián)調(diào)發(fā)了“PRINT”就等返回結(jié)果噴碼機(jī)一直不應(yīng)答代碼本身沒(méi)問(wèn)題就是少了結(jié)尾的CRLF。反過(guò)來(lái)說(shuō)如果協(xié)議文檔里明確沒(méi)有校驗(yàn)位那幀尾一個(gè)CR或LF就夠多發(fā)的CRLF可能被當(dāng)成兩個(gè)空指令。2.4 功能碼分類查詢、控制、寫(xiě)入、文件調(diào)用先做成一頁(yè)紙速查表協(xié)議文檔里命令一多就容易亂。我把常見(jiàn)的功能分成四類配合實(shí)例工程里的頭文件整理成速查表貼在工位旁類別作用典型場(chǎng)景查詢類讀當(dāng)前狀態(tài)、計(jì)數(shù)、報(bào)警上位機(jī)定時(shí)巡檢控制類啟動(dòng)打印、停止打印、清洗噴頭產(chǎn)線啟停聯(lián)動(dòng)寫(xiě)入類修改當(dāng)前打印內(nèi)容、日期格式換產(chǎn)換文本文件類調(diào)用已存儲(chǔ)的打印任務(wù)多任務(wù)快速切換查詢類和控制類在聯(lián)調(diào)階段優(yōu)先級(jí)最高。先確認(rèn)能讀到狀態(tài)再控制啟停最后才動(dòng)文本寫(xiě)入。文本寫(xiě)入最容易出邊界問(wèn)題比如內(nèi)容里有中文字符、特殊符號(hào)有些噴碼機(jī)要求用指定的字符集編碼還有日期變量是噴碼機(jī)內(nèi)部生成的上位機(jī)如果直接發(fā)固定字符串把變量覆蓋掉第二天日期就不更新了。這個(gè)細(xì)節(jié)在協(xié)議文檔的“變量格式”章節(jié)里寫(xiě)得比較細(xì)實(shí)操時(shí)值得逐字看。3. 串口通訊實(shí)例從一條打印指令到完整收發(fā)確認(rèn)3.1 先裝環(huán)境、探測(cè)串口別讓端口號(hào)拖后腿拿到實(shí)例包后我習(xí)慣先用Python的pyserial把通訊鏈路跑通再去啃協(xié)議里的每個(gè)命令。原因是Python寫(xiě)起來(lái)快改參數(shù)不用重新編譯適合做聯(lián)調(diào)階段的“探針”。第一步是確認(rèn)當(dāng)前機(jī)器的串口設(shè)備號(hào)import serial from serial.tools import list_ports ports list_ports.comports() for p in ports: print(p.device, p.description)這段代碼會(huì)列出所有串口設(shè)備和驅(qū)動(dòng)描述。如果你插了USB轉(zhuǎn)串口線設(shè)備號(hào)通常是COM3、COM4描述里能看到芯片型號(hào)比如FT232、CH340、CP2102。邏輯說(shuō)明pyserial底層會(huì)遍歷系統(tǒng)注冊(cè)表里的串口節(jié)點(diǎn)所以我們不需要手工指定端口號(hào)參數(shù)說(shuō)明device是類似“COM3”的完整設(shè)備名description是驅(qū)動(dòng)描述字符串。產(chǎn)線上建議把USB轉(zhuǎn)串口線的COM號(hào)在設(shè)備管理器里固定住避免重啟后設(shè)備號(hào)漂移導(dǎo)致MES連錯(cuò)噴碼機(jī)。3.2 發(fā)送一條打印指令并讀取返回串口參數(shù)確認(rèn)后就可以做第一次真實(shí)收發(fā)。這里我用一個(gè)通用幀構(gòu)建函數(shù)協(xié)議里常見(jiàn)的BCC校驗(yàn)就是逐字節(jié)異或import serial import time SER_PORT COM3 SER_BAUD 9600 SER_BYTESIZE 8 SER_PARITY N SER_STOPBITS 1 def build_frame(fc: str, data: str ) - bytes: # 功能碼和數(shù)據(jù)都是ASCII拼接后整體做異或校驗(yàn) body (fc data).encode(ascii) bcc 0 for b in body: bcc ^ b return b\x02 body b\x03 bytes([bcc]) b\r\n def send_and_recv(ser: serial.Serial, frame: bytes, timeout: float 2.0): ser.reset_input_buffer() ser.write(frame) return ser.read_until(b\r\n, timeout) ser serial.Serial(portSER_PORT, baudrateSER_BAUD, bytesizeSER_BYTESIZE, paritySER_PARITY, stopbitsSER_STOPBITS, timeout1.0) resp send_and_recv(ser, build_frame(S, PRINT)) print(response:, resp) ser.close()邏輯說(shuō)明build_frame先把功能碼和數(shù)據(jù)組成內(nèi)容體逐字節(jié)異或得到BCC然后按STX、內(nèi)容、ETX、BCC、CRLF的順序拼成完整幀send_and_recv在發(fā)送前清空接收緩沖避免讀到上一次殘留數(shù)據(jù)再用read_until按CRLF判斷一幀結(jié)束。參數(shù)說(shuō)明fc是功能碼這里我用“S”表示控制類data是具體的控制參數(shù)“PRINT”timeout設(shè)為2秒如果噴碼機(jī)2秒內(nèi)沒(méi)返回就不繼續(xù)空等。你手頭的協(xié)議文檔如果功能碼編號(hào)不同只要把“S”和“PRINT”替換成對(duì)應(yīng)值即可。關(guān)鍵是要先確認(rèn)兩件事幀頭是不是0x02、結(jié)束符是不是CRLF。如果實(shí)例包里的協(xié)議是純ASCII無(wú)校驗(yàn)?zāi)莃uild_frame里的異或部分可以去掉直接返回body加CRLF。3.3 把收發(fā)邏輯封裝成線程安全的打印機(jī)類聯(lián)調(diào)沒(méi)問(wèn)題后上位機(jī)往往會(huì)有多個(gè)功能模塊同時(shí)訪問(wèn)串口MES要查狀態(tài)、PLC要啟停、操作員要改文本。如果不加鎖兩個(gè)線程同時(shí)write噴碼機(jī)收到的就是兩幀混在一起的垃圾數(shù)據(jù)。我一般會(huì)封裝一個(gè)簡(jiǎn)單的類import serial import threading import time class SerialPrinter: def __init__(self, port, baud9600, timeout2.0): self.lock threading.Lock() self.ser serial.Serial(portport, baudratebaud, bytesize8, parityN, stopbits1, timeouttimeout) self.last_response b def transact(self, fc: str, data: str ) - bytes: frame self._build_frame(fc, data) with self.lock: self.ser.reset_input_buffer() self.ser.write(frame) resp self.ser.read_until(b\r\n, self.ser.timeout) self.last_response resp return resp def _build_frame(self, fc: str, data: str) - bytes: body (fc data).encode(ascii) bcc 0 for b in body: bcc ^ b return b\x02 body b\x03 bytes([bcc]) b\r\n邏輯說(shuō)明transact方法內(nèi)部用threading.Lock保證同一時(shí)刻只有一個(gè)線程占用串口發(fā)送前reset_input_buffer清空舊數(shù)據(jù)然后write并等待應(yīng)答。參數(shù)說(shuō)明timeout既用于serial.Serial構(gòu)造也用于read_until的等待上限返回值resp是噴碼機(jī)回傳的原始字節(jié)。封裝成類之后其他模塊只要調(diào)transact就行不用關(guān)心幀怎么拼、鎖怎么加。3.4 返回碼表把協(xié)議文檔里的錯(cuò)誤碼做成上位機(jī)可讀的提示噴碼機(jī)收到指令后返回的不是人話而是一個(gè)短幀。這套實(shí)例工程里常見(jiàn)的返回碼大概是0x06表示成功0x15表示校驗(yàn)錯(cuò)誤0x21表示緩沖區(qū)滿0x31表示當(dāng)前狀態(tài)不允許該操作。不同固件版本有差異所以拿到機(jī)器第一件事是把協(xié)議文檔里的返回碼表和實(shí)測(cè)結(jié)果對(duì)一遍不要拿A版本的表去套B版本。我在上位機(jī)里的做法是維護(hù)一張字典把返回碼映射成中文提示。比如0x21不再顯示“十六進(jìn)制21”而是顯示“噴碼機(jī)通訊緩沖區(qū)已滿請(qǐng)降低發(fā)送頻率”0x31顯示“當(dāng)前噴碼機(jī)處于待機(jī)狀態(tài)無(wú)法啟動(dòng)打印”。這樣操作員不用看手冊(cè)就能判斷是重發(fā)還是先處理機(jī)器狀態(tài)。返回碼表雖然短但排查問(wèn)題的時(shí)候價(jià)值很高值得單獨(dú)做一個(gè)頁(yè)面。4. 接進(jìn) PLC 與 MES狀態(tài)機(jī)、RS485 組網(wǎng)和打印互鎖4.1 流水線串口通訊狀態(tài)機(jī)發(fā)送、等待、超時(shí)、重試噴碼機(jī)通訊不能簡(jiǎn)單做成“請(qǐng)求-響應(yīng)”一步。產(chǎn)線上一旦出現(xiàn)干擾幀可能會(huì)丟所以上位機(jī)和PLC都要有狀態(tài)機(jī)。狀態(tài)轉(zhuǎn)換的核心是空閑、發(fā)送中、等待應(yīng)答、超時(shí)重試、錯(cuò)誤處理。我常用的簡(jiǎn)化實(shí)現(xiàn)import time class PrintLink: def __init__(self, printer: SerialPrinter, max_retry3, timeout2.0): self.printer printer self.max_retry max_retry self.timeout timeout def transact_with_retry(self, fc: str, data: str ) - bytes: last_err None for attempt in range(self.max_retry): try: resp self.printer.transact(fc, data) # 這里按返回碼判斷是否成功 if resp and resp[0] 0x06: return resp last_err resp except serial.SerialTimeoutException as e: last_err e time.sleep(0.3 * (attempt 1)) raise RuntimeError(f噴碼機(jī)通訊失敗: {last_err})邏輯說(shuō)明每次發(fā)送前不做額外延時(shí)但超時(shí)重試的間隔按0.3秒、0.6秒、0.9秒遞增避免機(jī)器剛開(kāi)機(jī)處理不過(guò)來(lái)時(shí)連續(xù)重發(fā)把緩沖區(qū)塞滿。參數(shù)說(shuō)明max_retry設(shè)為3適合產(chǎn)線上輕度干擾如果現(xiàn)場(chǎng)電磁環(huán)境很差可以調(diào)到5但單次指令最多會(huì)占用5×2秒MES側(cè)的請(qǐng)求超時(shí)要留夠余量。狀態(tài)機(jī)的好處是讓排查有跡可循。我把每次transact_with_retry的開(kāi)始時(shí)間、幀內(nèi)容、返回碼、重試次數(shù)都寫(xiě)到日志里。出了串口通訊異常先看日志里是第幾次重試成功的就能判斷是偶發(fā)干擾還是持續(xù)性故障。這個(gè)習(xí)慣幫我解決過(guò)不少“時(shí)好時(shí)壞”的玄學(xué)問(wèn)題。4.2 RS485 組網(wǎng)站號(hào)、廣播幀和終端電阻一個(gè)都不能少多臺(tái)9410/9450掛在同一條RS485總線上時(shí)每臺(tái)噴碼機(jī)必須分配不同的站號(hào)。實(shí)例包里的協(xié)議會(huì)把站號(hào)放在功能碼前面比如站號(hào)01的控制指令是“01S”站號(hào)02是“02S”。上位機(jī)發(fā)帶站號(hào)的幀噴碼機(jī)根據(jù)站號(hào)決定是否應(yīng)答如果協(xié)議里沒(méi)有站號(hào)字段那RS485就只能點(diǎn)對(duì)點(diǎn)不能組網(wǎng)。廣播幀是個(gè)容易踩坑的點(diǎn)。很多協(xié)議會(huì)預(yù)留一個(gè)特殊站號(hào)255表示“所有機(jī)器同時(shí)執(zhí)行”比如同時(shí)停止所有噴碼機(jī)。問(wèn)題是廣播幀不需要返回ACK因?yàn)樗性O(shè)備會(huì)同時(shí)響應(yīng)總線立刻沖突。所以我一般只在緊急停止時(shí)用廣播幀正常啟動(dòng)和查詢一律逐臺(tái)輪詢。輪詢間隔不能太短RS485半雙工模式下上一臺(tái)的返回幀還沒(méi)結(jié)束下一臺(tái)的查詢幀就發(fā)出去總線就亂了。終端電阻也是老問(wèn)題。RS485總線兩端各接一個(gè)120歐姆電阻不是每臺(tái)設(shè)備都接。如果一臺(tái)離得遠(yuǎn)的噴碼機(jī)時(shí)通時(shí)斷先檢查總線兩端電阻而不是急著改協(xié)議。更隱蔽的是屏蔽層很多現(xiàn)場(chǎng)把屏蔽層在兩端都接地結(jié)果地環(huán)路電流比信號(hào)電流還大丟包率不降反升。正確做法是屏蔽層單端接地一般選PLC側(cè)或電柜接地排。4.3 與 PLC 通訊協(xié)議對(duì)接自由口、Modbus RTU 和協(xié)議轉(zhuǎn)換網(wǎng)關(guān)怎么選PLC與噴碼機(jī)對(duì)接要看PLC支持什么通訊協(xié)議。西門(mén)子S7-200 SMART、三菱FX系列支持自由口協(xié)議可以直接按噴碼機(jī)ASCII幀發(fā)送連轉(zhuǎn)換設(shè)備都省了。但很多中大型PLC默認(rèn)只開(kāi)放Modbus RTU而噴碼機(jī)用的是自定義ASCII協(xié)議兩者不能直接互通。常見(jiàn)做法是加一個(gè)協(xié)議轉(zhuǎn)換網(wǎng)關(guān)把Modbus寄存器映射成噴碼機(jī)的串口指令。工程上大概分三種方案方案優(yōu)點(diǎn)缺點(diǎn)PLC自由口直連成本低響應(yīng)快程序邏輯復(fù)雜換PLC要重寫(xiě)串口服務(wù)器上位機(jī)中轉(zhuǎn)靈活可同時(shí)管理多臺(tái)實(shí)時(shí)性一般依賴上位機(jī)在線Modbus網(wǎng)關(guān)透?jìng)髋cPLC品牌無(wú)關(guān)需要額外配置寄存器映射我用得最多的是Modbus網(wǎng)關(guān)方案。PLC側(cè)只讀寫(xiě)幾個(gè)保持寄存器比如40001寫(xiě)打印內(nèi)容、40002寫(xiě)啟停指令、40003讀當(dāng)前狀態(tài)。網(wǎng)關(guān)內(nèi)部把寄存器變化轉(zhuǎn)換成噴碼機(jī)指令幀再把噴碼機(jī)返回碼寫(xiě)回40004。這樣PLC工程師不需要了解噴碼機(jī)協(xié)議只要按Modbus寄存器表開(kāi)發(fā)就行。注意寄存器讀寫(xiě)有先后順序先寫(xiě)參數(shù)再寫(xiě)啟動(dòng)指令不能讓啟動(dòng)指令先到。4.4 啟停打印的互鎖時(shí)序別把“發(fā)指令”當(dāng)成“按按鈕”噴碼機(jī)的啟動(dòng)和停止比普通繼電器復(fù)雜得多。停止噴碼機(jī)不是切斷打印頭而是先停墨路、清洗噴嘴再進(jìn)入待機(jī)狀態(tài)如果直接斷掉噴碼機(jī)電源噴嘴里的墨水干涸輕則堵嘴重則換噴頭。所以上位機(jī)在控制啟停前必須做互鎖檢查。我習(xí)慣把啟動(dòng)時(shí)序拆成四步第一步讀噴碼機(jī)狀態(tài)確認(rèn)處于“就緒”而非“報(bào)警”第二步發(fā)送文本寫(xiě)入確認(rèn)返回成功第三步發(fā)送啟動(dòng)打印指令第四步再讀狀態(tài)確認(rèn)已經(jīng)進(jìn)入“打印中”。任何一步失敗都不能直接重試啟動(dòng)要先看返回碼。停止時(shí)序反過(guò)來(lái)先停打印任務(wù)再停墨路兩條指令之間至少間隔500毫秒給噴碼機(jī)內(nèi)部動(dòng)作留時(shí)間。這個(gè)互鎖邏輯對(duì)MES尤其重要。MES往往同時(shí)管理多條產(chǎn)線如果只發(fā)一次啟動(dòng)指令不確認(rèn)結(jié)果噴碼機(jī)因?yàn)槟坎蛔銢](méi)啟動(dòng)MES卻已經(jīng)記錄“生產(chǎn)開(kāi)始”后面所有產(chǎn)量統(tǒng)計(jì)全錯(cuò)。所以我把“啟動(dòng)確認(rèn)”做成了MES的強(qiáng)制校驗(yàn)項(xiàng)查不到“打印中”狀態(tài)就報(bào)錯(cuò)。5. 串口通訊異常排查避坑9410/9450 的五個(gè)高頻故障記錄5.1 能收到返回碼但噴碼機(jī)不打印現(xiàn)象上位機(jī)發(fā)出啟動(dòng)打印指令噴碼機(jī)返回ACK但機(jī)器始終不噴印。原因噴碼機(jī)處于“待機(jī)”或“維護(hù)”模式此時(shí)控制指令被接收但不會(huì)執(zhí)行也有可能是當(dāng)前打印任務(wù)被面板鎖定外部指令無(wú)權(quán)覆蓋。解決先看面板狀態(tài)確認(rèn)在“就緒/聯(lián)機(jī)”模式再用查詢類指令讀當(dāng)前任務(wù)號(hào)確認(rèn)上位機(jī)要啟動(dòng)的任務(wù)確實(shí)存在且未被鎖定最后檢查外部控制使能開(kāi)關(guān)有些機(jī)型在“外部控制”菜單里有一個(gè)總開(kāi)關(guān)默認(rèn)是關(guān)的。5.2 RS485 偶發(fā)中斷A/B 接反和終端電阻位置不對(duì)現(xiàn)象多臺(tái)噴碼機(jī)在一根RS485總線上遠(yuǎn)端那臺(tái)時(shí)通時(shí)斷近端正常用串口助手單獨(dú)測(cè)遠(yuǎn)端又一切正常。原因A/B極性接反時(shí)通訊并不完全癱瘓而是時(shí)好時(shí)壞因?yàn)椴罘中盘?hào)在臨界狀態(tài)來(lái)回跳終端電阻沒(méi)接在總線兩端而是接在某臺(tái)設(shè)備旁邊阻抗不匹配導(dǎo)致反射。解決先測(cè)空閑時(shí)A到B的電壓正常應(yīng)在1.5V到5V之間如果為負(fù)值說(shuō)明A/B反了對(duì)調(diào)即可終端電阻只保留總線兩端各一個(gè)中間設(shè)備全部拆掉。5.3 返回?cái)?shù)據(jù)亂碼或總是多一個(gè)字節(jié)現(xiàn)象上位機(jī)收到的返回文本長(zhǎng)度比預(yù)期多一個(gè)0x00或0xFF偶爾整段亂碼。原因波特率或校驗(yàn)位不匹配通訊雙方對(duì)每個(gè)字節(jié)的位邊界判斷不一致如果改用單片機(jī)做上位機(jī)常見(jiàn)原因是單片機(jī)串口波特率定時(shí)器初值算錯(cuò)實(shí)際波特率偏差超過(guò)2%短幀看著正常長(zhǎng)幀就錯(cuò)位。解決先用示波器測(cè)單字節(jié)波形數(shù)一下起始位、數(shù)據(jù)位、校驗(yàn)位、停止位是不是和設(shè)定一致把波特率降到9600再測(cè)排除高速下線路電容的影響如果還是亂碼用邏輯分析儀抓真實(shí)波形不要靠上位機(jī)顯示判斷。5.4 開(kāi)機(jī)后第一條指令必然超時(shí)后面全部正常現(xiàn)象噴碼機(jī)剛上電上位機(jī)第一次發(fā)查詢指令必然超時(shí)第二次發(fā)立刻正常。原因噴碼機(jī)串口接收緩沖區(qū)在系統(tǒng)初始化完成前沒(méi)有就緒面板可能已經(jīng)顯示主界面但通訊服務(wù)還沒(méi)起來(lái)。解決在上位機(jī)啟動(dòng)流程里加一條“喚醒幀”比如發(fā)送0x00加回車(chē)停頓200ms后再發(fā)真實(shí)指令不要在第一次超時(shí)后立即重試否則可能撞上噴碼機(jī)正在初始化內(nèi)部文件系統(tǒng)的階段。這個(gè)動(dòng)作放到MES啟動(dòng)腳本里每次開(kāi)線自動(dòng)執(zhí)行一次。5.5 用USB轉(zhuǎn)串口線調(diào)試正常換到工控機(jī)板載串口就異?,F(xiàn)象開(kāi)發(fā)階段用USB轉(zhuǎn)串口線一切正常部署到工控機(jī)自帶串口后指令發(fā)出沒(méi)響應(yīng)或返回亂碼。原因工控機(jī)BIOS把COM口設(shè)成了IrDA紅外模式或硬件流控模式也有可能是DB9針腳定義不同工控機(jī)側(cè)是DTE噴碼機(jī)側(cè)也是DTE中間需要交叉線而USB轉(zhuǎn)串口線內(nèi)部已經(jīng)做了交叉。解決進(jìn)BIOS確認(rèn)COM口模式為RS232關(guān)閉IrDA和RTS/CTS流控再做一次完整的針腳測(cè)量確定2、3、5三根線在插座端的實(shí)際電平不要默認(rèn)“DB9就是標(biāo)準(zhǔn)線序”。6. 進(jìn)階驗(yàn)證技巧回環(huán)測(cè)試與報(bào)文錄制把鏈路問(wèn)題擋在上位機(jī)之前6.1 RS232 回環(huán)測(cè)試一根短接線代替噴碼機(jī)驗(yàn)證上位機(jī)程序新接一臺(tái)噴碼機(jī)之前我會(huì)先做一次回環(huán)測(cè)試確認(rèn)串口線和上位機(jī)程序本身沒(méi)問(wèn)題。把DB9的2腳和3腳短接5腳接GND這時(shí)上位機(jī)發(fā)出去的數(shù)據(jù)會(huì)原樣回到接收端。用一個(gè)簡(jiǎn)單腳本驗(yàn)證import serial ser serial.Serial(COM3, 9600, timeout2) test bLOOPBACK_TEST\r\n ser.write(test) echo ser.read_until(b\n, 2) assert echo test, f回環(huán)異常: {echo} ser.close()邏輯說(shuō)明2腳和3腳短接后TXD和RXD是同一根線write發(fā)出的字節(jié)立刻被自身接收如果程序能讀到和發(fā)送完全一致的數(shù)據(jù)說(shuō)明串口線、驅(qū)動(dòng)、波特率整體正常。參數(shù)說(shuō)明read_until按換行符結(jié)束所以測(cè)試數(shù)據(jù)必須以\r\n結(jié)尾。這個(gè)測(cè)試5分鐘就能做完能擋住“插錯(cuò)線”“驅(qū)動(dòng)裝錯(cuò)”“參數(shù)配錯(cuò)”三類基礎(chǔ)問(wèn)題。6.2 報(bào)文錄制用監(jiān)聽(tīng)工具抓真實(shí)電平別只看噴碼機(jī)面板回環(huán)測(cè)試只能驗(yàn)證鏈路驗(yàn)證不了噴碼機(jī)側(cè)的真實(shí)收發(fā)。聯(lián)調(diào)階段我會(huì)在噴碼機(jī)串口線上并聯(lián)一個(gè)邏輯分析儀把雙方收發(fā)的每一幀都錄下來(lái)。重點(diǎn)看三個(gè)指標(biāo)幀與幀之間的間隔、返回幀的結(jié)束符是不是CRLF、BCC校驗(yàn)值是否和上位機(jī)算的一致。很多“偶發(fā)通訊異?!逼鋵?shí)主控板上已經(jīng)要求重傳只是一重傳就丟數(shù)據(jù)靠上位機(jī)日志看不到那么細(xì)。從那以后我每次新接一臺(tái)9410/9450都會(huì)強(qiáng)制走一遍回環(huán)測(cè)試、報(bào)文錄制、參數(shù)核對(duì)三步再進(jìn)產(chǎn)線聯(lián)調(diào)。這套動(dòng)作擋下了至少三次讓我頭疼的“玄學(xué)”故障——最后不是針腳氧化就是校驗(yàn)位多配了一位。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取