在一些應用場景中,Web應用程序需要獲取訪問者電腦上連接的硬件設備,即瀏覽器和串口通信。通常的做法是爲這些硬件設備開發ActiveX控件,並將其嵌入到HTML網頁中供InternetExplorer瀏覽器訪問這些設備信息。而採用ActiveX控件要求瀏覽器必須爲InternetExplorer,不兼容Chrome等其他瀏覽器。下面是結合廣大網友資料的總結,順便記錄下實現的過程和碰到的問題。
一、使用mscomm32.ocx使用串口資源
該方法是使用微軟的ActiveX控件MSCOMM32.ocx的串口控件對串口進行控制,但是ActiveX控件目前只針對IE瀏覽器支持較好,要想兼容其他瀏覽器可以去找下自定義ActiveX控件相關資料
二、用C#之類的自己寫一個dll,然後使用
使用C#語言的控件對串口進行控制,然後使用JS+AJAX與C#進行交互獲得串口數據,缺點就是數據同步方面可能相對稍有延遲,畢竟AJAX是一個異步傳輸的標準
三、用Node.js 的serial模塊實現
暫無實際項目開發經驗。附上別人家的代碼一份供參考
http://www.qihuawu.com/serial-data-obtained-using-nodejs.html
四、使用Google的Chrome.serial實現
開發這位大神總結的很nice:https://www.jianshu.com/p/873b5403bf05
下面我詳細說一下用微軟的ActiveX控件實現串口通信的過程
1.註冊MSCOMM32.ocx控件
A.下載控件https://github.com/davidanger/MSCOMM32
B.複製MSCOMM32.OCX 到 C:\WINDOWS\SysWOW64(
注意:如果是32位系統就是C:\WINDOWS\SysWOW32)
C.在C:\WINDOWS\SysWOW64(C:\WINDOWS\SysWOW32)搜索cmd.exe,以管理員身份運行,執行命令: regsvr32 mscomm32.ocx,彈出註冊成功
2.設置註冊表
A. 複製下面的內容,文件命名爲mscomm.bat
copy mscomm*.* %windir%\system32\ /y
Regsvr32 %windir%\system32\mscomm32.ocx /s
Regsvr32 %windir%\system32\actxprxy.dll /s
Regsvr32 %windir%\system32\shdocvw.dll /s
Reg add"HKEY_CLASSES_ROOT\Licenses\4250E830-6AC2-11cf-8ADB-00AA00C00905" /v “” /d “kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun” /f
pause
B.將文件複製到C:\Windows\SysWOW64 目錄下
C.右擊mscomm.bat 文件選擇以管理員身份運行
D.出現如圖:即操作成功,完成後即可關閉命令窗口
3.設置IE對ActiveX的安全控制
A.打開IE瀏覽器 — 設置 — Internet 選項 — 安全模塊 — 自定義級別
B.自定義級別——安全——ActiveX控件和插件
C.如下圖操作:
方點擊確定,是,重啓瀏覽器。
4.IE 管理項加載
A.新建文檔,複製下面的內容,文件爲mscomm.html
<html>
<head>
<title></title>
</head>
<body>
<OBJECT id=MSComm1 CLASSID="clsid:648A5600-2C6E-101B-82B6-000000000014" codebase="MSCOMM32.OCX" type="application/x-oleobject" style="LEFT:54px;TOP:14px">
<PARAM NAME="CommPort" VALUE="3"/>
<PARAM NAME="DataBits" VALUE="8"/>
<PARAM NAME="StopBits" VALUE="1"/>
<PARAM NAME="BaudRate" VALUE="9600"/>
<PARAM NAME="Settings" VALUE="9600,N,8,1"/>
<PARAM NAME="RTSEnable" VALUE="1"/>
<PARAM NAME="DTREnable" VALUE="1"/>
<PARAM NAME="Handshaking" VALUE="0"/>
<PARAM NAME="NullDiscard" VALUE="0"/>
<PARAM NAME="ParityReplace" VALUE="?"/>
<PARAM NAME="EOFEnable" VALUE="0"/>
<PARAM NAME="InputMode" VALUE="0"/>
<PARAM NAME="InBufferSize" VALUE="1024"/>
<PARAM NAME="InputLen" VALUE="0"/>
<PARAM NAME="OutBufferSize" VALUE="512"/>
<PARAM NAME="SThreshold" VALUE="0"/>
<PARAM NAME="RThreshold" VALUE="1"/>
</OBJECT>
</body>
</html>
B.在IE中運行mscomm.html
C.查看控件是否加載 設置——管理加載項——所有加載項
3.附上代碼
<!DOCTYPE html>
<html>
<head>
<title>JavaScript串口測試</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script ID=clientEventHandlersJS LANGUAGE=javascript>
function MSComm1_OnComm() {
switch(MSComm1.CommEvent) {
case 1:
{
window.alert("Send OK!");
break;
} //發送事件
case 2:
{
Receive();
break;
} //接收事件
default:
alert("Event Raised!" + MSComm1.CommEvent);;
}
}
</script>
<script LANGUAGE=javascript FOR=MSComm1 EVENT=OnComm>
// MSComm1控件每遇到 OnComm 事件就調用 MSComm1_OnComm()函數
MSComm1_OnComm()
</script>
<script language="JavaScript" type="text/JavaScript">
String.prototype.Blength = function(){
var arr = this.match(/[^\x00-\xff]/ig);
return arr == null ? this.length : this.length + arr.length;
}
function OperatePort() {
if(MSComm1.PortOpen == true) {
try {
MSComm1.PortOpen = false;
document.getElementById("OperateButton").value = "打開串口";
} catch(ex) {
alert(ex.message);
}
} else {
try {
MSComm1.PortOpen = true;
document.getElementById("OperateButton").value = "關閉串口";
} catch(ex) {
alert(ex.message);
}
}
}
function ConfigPort() {
alert("串口狀態:" + MSComm1.PortOpen);
if(MSComm1.PortOpen == false) {
try {
MSComm1.CommPort = document.getElementById("ComName").value;
alert(MSComm1.CommPort)
MSComm1.Settings = document.getElementById("BaudRate").value.toString() + "," +
document.getElementById("CheckBit").value.toString() + "," +
document.getElementById("DataBits").value.toString() + "," +
document.getElementById("StopBits").value.toString();
MSComm1.OutBufferCount = 0; //清空發送緩衝區
MSComm1.InBufferCount = 0; //滑空接收緩衝區
alert("已配置串口COM" + MSComm1.CommPort + "\n 參數:" + MSComm1.Settings);
} catch(ex) {
alert(ex.message);
}
} else {
alert("請先關閉串口後再設置!");
}
}
function Send() {
//alert(document.getElementById("txtSend").value);
var orgstr = document.getElementById("txtSend").value;
var newstr = "";
var hexflag = document.getElementById("isSendHex").checked;
if(hexflag && orgstr != "") {
if(orgstr.substr(0, 2) == "0x" || orgstr.substr(0, 2) == "0X") orgstr = orgstr.substring(2, orgstr.length);
if(orgstr.length % 2 != 0) orgstr = "0" + orgstr;
//alert(str2hex(orgstr));
if((newstr = str2hex(orgstr)) == "") {
alert("錯誤的16進制數");
return false;
}
}
try {
MSComm1.Output = hexflag ? newstr : orgstr;
//alert(MSComm1.Output)
} catch(ex) {
alert(ex.message);
}
}
function Receive() {
//alert("InBufferCount::" + MSComm1.InBufferCount); // 緩衝區接收的字節
document.getElementById("txtReceive").value += MSComm1.Input; //alert("InBufferCount::"+MSComm1.InBufferCount);
}
function ClearReceived() {
document.getElementById("txtReceive").innerText = "";
}
function str2hex(s) {
var a, b, d;
var hexStr = '';
for(var i = 0; i <
s.length; i++) {
d = s.charCodeAt(i);
a = d % 16;
b = (d - a) / 16;
hexStr += '%' + "0123456789ABCDEF".charAt(b) + "0123456789ABCDEF".charAt(a);
}
//alert(hexStr);
return hexStr;
}
function charCode(v) {
return String.fromCharCode(v);
}
</script>
</head>
<body>
<form name="form1">
<fieldset style="width:200px;height:250px;text-align:center;">
<legend>配置串口</legend>
<div style="float:left;width:200px">
<br/>
<span>串口號:</span>
<select name="ComName" id="ComName" style="width:75px">
<option value="1">COM1</option>
<option value="2">COM2</option>
<option value="7" selected>COM7</option>
<option value="4">COM4</option>
<option value="5">COM5</option>
<option value="9">COM9</option>
</select>
<br/>
<span>波特率:</span>
<select name="BaudRate" id="BaudRate" style="width:75px">
<option value="9600">9600</option>
<option value="57600">57600</option>
<option value="115200" selected>115200</option>
</select>
<br/>
<span>校驗位:</span>
<select name="CheckBit" id="CheckBit" style="width:75px">
<option value="N" selected>無NONE</option>
<option value="O">奇ODD</option>
<option value="E">偶EVEN</option>
</select>
<br/>
<span>數據位:</span>
<input type=text id="DataBits" name="DataBits" value=8 style="width:75px;height:20px">
<br/>
<span>停止位:</span>
<input type=text id="StopBits" name="StopBits" value=1 style="width:75px;height:20px">
<br/>
<br/>
<input type="button" id="ConfigButton" style="width:80px;height:30px;font-size:13px" name="ConfigButton" value="配置串口" onClick="ConfigPort()">
<input type="button" id="OperateButton" style="width:80px;height:30px;font-size:13px" name="OperateButton" value="打開串口" onClick="OperatePort()">
</div>
</fieldset>
<fieldset style="width:200px;height:250px;text-align:center;">
<legend>發送區域</legend>
<div style="float:left;">
<textarea id="txtSend" name="txtSend" style="width:200px;height:160px"></textarea>
<br/>
<span><input id="isSendHex" name="isSendHex" type="checkbox" />16進制</span>
<input type="button" id="SendButton" style="width:100px;height:30px" name="SendButton" value="發送" onClick="Send()">
</div>
</fieldset>
<fieldset style="width:200px;height:250px;text-align:center;">
<legend>接收區域</legend>
<div style="float:left;">
<textarea id="txtReceive" READONLY=TRUE name="txtReceive" style="width:200px;height:160px"></textarea>
<br/>
<span><input id="isReceiveHex" name="isReceiveHex" type="checkbox" />16進制</span>
<input type="button" id="ClearButton" style="width:100px;height:30px" name="ClearButton" value="清空" onClick="ClearReceived()">
</div>
</fieldset>
</form>
<OBJECT id=MSComm1 CLASSID="clsid:648A5600-2C6E-101B-82B6-000000000014" codebase="MSCOMM32.OCX" type="application/x-oleobject" style="LEFT:54px;TOP:14px">
<PARAM NAME="CommPort" VALUE="3"/>
<PARAM NAME="DataBits" VALUE="8"/>
<PARAM NAME="StopBits" VALUE="1"/>
<PARAM NAME="BaudRate" VALUE="9600"/>
<PARAM NAME="Settings" VALUE="9600,N,8,1"/>
<PARAM NAME="RTSEnable" VALUE="1"/>
<PARAM NAME="DTREnable" VALUE="1"/>
<PARAM NAME="Handshaking" VALUE="0"/>
<PARAM NAME="NullDiscard" VALUE="0"/>
<PARAM NAME="ParityReplace" VALUE="?"/>
<PARAM NAME="EOFEnable" VALUE="0"/>
<PARAM NAME="InputMode" VALUE="0"/>
<PARAM NAME="InBufferSize" VALUE="1024"/>
<PARAM NAME="InputLen" VALUE="0"/>
<PARAM NAME="OutBufferSize" VALUE="512"/>
<PARAM NAME="SThreshold" VALUE="0"/>
<PARAM NAME="RThreshold" VALUE="1"/>
</OBJECT>
</body>
</html>
4.代碼調試
沒有實際的USb串口的話,即爲模擬環境,注意模擬環境要安裝虛擬串口
1)下載調試工具
Configure Virtural Serial Port 創建虛擬串口的 試用期 14天
串口調試精靈 調試串口的
2)虛擬調試方法
在Configure Virtural Serial Port 裏添加端口,添加的端口都爲一對
3)實際串口調試方法
待更新…
5.問題彙總
安裝虛擬端口
https://www.cnblogs.com/javatiandi/p/11180765.html
設置虛擬端口
https://jingyan.baidu.com/article/4ae03de31828973eff9e6b8e.html
調試方法
https://blog.csdn.net/u013769695/article/details/80408139
串口調試助手怎麼知道串口打開是否成功
https://zhidao.baidu.com/question/2053929245831631307.html
解決IE的Automation 服務器不能創建對象的問題
http://xinzhi.wenda.so.com/a/1539093807203701
http://www.qiuyexitong.com/article/1024.html
模塊"scrrun.dll"已加載,但對DllRegisterServer的調用失敗,錯誤代碼爲0x80004005
https://zhidao.baidu.com/question/537433274.html
算是個最完整的實例:
https://www.cnblogs.com/x-j-p/p/7819724.html
控件參數詳解
https://blog.csdn.net/dongyue786/article/details/8177047
通信常見問題
https://www.iteye.com/blog/linuxgao-1925099