当前位置:   article > 正文

HTML/JS/浏览器与串口通信(一)_html串口通信

html串口通信

在一些应用场景中,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.如下图操作:

ActiveX控件和插件修改选项
ActiveX控件和插件修改选项
点击确定
方点击确定,是,重启浏览器。

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

B.在IE中运行mscomm.html
允许加载阻止的内容
C.查看控件是否加载 设置——管理加载项——所有加载项
所有加载项
IE管理项加载OCX控件

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/671463
推荐阅读
相关标签
  

闽ICP备14008679号