php串口通信编程问题
最近做个小项目,要远程控制一个水泵, 编程 只会一点儿php,正好方便远程控制。 开发环境 win7 ,一个usb转 串口 的转换器,淘宝上买的 串口 4路继电器板。 想最终整个atom的小板子加个u盘做系统,定制一个小linuxapachephp系统来做,硬件体积小,功耗低,应
最近做个小项目,要远程控制一个水泵,编程只会一点儿php,正好方便远程控制。
开发环境 win7 ,一个usb转串口的转换器,淘宝上买的串口4路继电器板。
想最终整个atom的小板子加个u盘做系统,定制一个小linux+apache+php系统来做,硬件体积小,功耗低,应该可靠性比较高。
google了一下,看到大多都是用的php dio模块,我也用吧。
原来开发开发环境用的是 wamp server 2.1, 发现没有pecl dio模块,又google,发现 pecl4win.php.net当机了,郁闷。
又找,在http://snaps.php.net/win32/找到了php5.2-win32-200808060430.zip和pecl5.2-win32-200808060430.zip这个是配套的。
要下班了,回家继续写!
继续,继续google,找到了个coreAMP,试试看,下载安装,包含2个php版本,5.2.17,和5.3.5,都没有扩展库,下载的php版本是 5.2.7,php版本不一样,
覆盖看看行不行,解压php5.2-win32-200808060430.zip覆盖coreamp的php5.2.17目录,解压
pecl5.2-win32-200808060430.zip到php5.2.17的ext目录,修改php.ini,改extension_dir = "C:\CoreAMP\server\php-5.2.17\ext"添加php_dio.dll扩展。开发环境配置完毕。
测试了一下,没问题。
程序开始,惨了,家里机器上没有代码啊。
回单位了,上代码:
- /**************************************************************
- *rs232.php 控制4路串口继电器演示程序 *
- * 作者 tiger92665@gmail.com 2011.04 *
- **************************************************************
- 采用232协议通信,波特率9600,8个数据位,一个停止位,无校验位。
- MODE COM1 9600, n, 8, 1
- 计算机到继电器板的数据帧说明:
- 数据头: 0x55 (作为标识)
- 地址:0x01(一个继电器板默认为1)
- 操作类型: 0x00(查询当前各继电器状态)0x01(写入新值)
- 数据(四个字节) 每个字节代表一个继电器,共四个;
- 数据值1:继电器断开;数据值2:继电器吸合;数据值0:继电器无动作。
- 校验 一字节和校验 0x56
- 继电器板到计算机的数据帧说明:
- 数据头: 0x22 (作为标识)
- 地址:0x01(单个继电器默认为1)
- 操作类型: 与计算机发来的操作类型一致
- 数据(四个字节) 每个字节代表一个继电器,共四个;
- 数据值1:继电器断开,数据值2:继电器吸合。
- 校验 一字节和校验(用来防止数据出错)
- 计算机发送指令表(部分):
- "55 01 01 02 00 00 00 59"; // 吸合第1路继电器
- "55 01 01 00 02 00 00 59"; // 吸合第2路继电器
- "55 01 01 00 00 02 00 59"; // 吸合第3路继电器
- "55 01 01 00 00 00 02 59"; // 吸合第4路继电器
- "55 01 01 01 00 00 00 58"; // 断开第1路继电器
- "55 01 01 00 01 00 00 58"; // 断开第2路继电器
- "55 01 01 00 00 01 00 58"; // 断开第3路继电器
- "55 01 01 00 00 00 01 58"; // 断开第4路继电器
- 55 01 01 02 02 02 02 5F 吸合所有继电器
- 55 01 01 01 01 01 01 5B 断开所有继电器
- "55 01 01 00 00 00 00 57"; 查询当前继电器板的状态 */
- //定义被操作的窜口
- $com="com4";
- //定义串口数据
- // k1 k2 k3 k4 校验位
- $k1on="\x55\x01\x01\x02\x00\x00\x00\x59";
- $k2on="\x55\x01\x01\x00\x02\x00\x00\x59";
- $k3on="\x55\x01\x01\x00\x00\x02\x00\x59";
- $k4on="\x55\x01\x01\x00\x00\x00\x02\x59";
- $k1off="\x55\x01\x01\x01\x00\x00\x00\x58";
- $k2off="\x55\x01\x01\x00\x01\x00\x00\x58";
- $k3off="\x55\x01\x01\x00\x00\x01\x00\x58";
- $k4off="\x55\x01\x01\x00\x00\x00\x01\x58";
- $kon="\x55\x01\x01\x02\x02\x02\x02\x5f";
- $koff="\x55\x01\x01\x01\x01\x01\x01\x5b";
- $kstatus="\x55\x01\x00\x00\x00\x00\x00\x56";
- //定义接受的get 命令
- $ops = array("k1on", "k2on", "k3on", "k4on",
- "k1off","k2off","k3off","k4off","kon","koff","kstatus");
- //串口操作开始
- if ( isset($_GET['op']) and in_array($_GET['op'],$ops ) )
- {
- $data=${$_GET['op']};
- set_time_limit(3);
- //echo 'windows下设置窜口参数
';
- exec("mode ".$com."BAUD=9600 PARITY=n DATA=8 STOP=1 odsr=off");
-
- //echo "打开端口$com
";
- $f = dio_open ($com, O_RDWR | O_NOCTTY | O_NONBLOCK);
- if(!$f)
- {
- die("Error when open $com");
- }
- //echo "向串口发送数据
".$data.'
';
- dio_write ($f, $data);
- //echo "接收数据
";
- $str="";
- for ($i = 0; $i
- {
- $str.=bin2hex(dio_read( $f,1));
- }
- //echo $str;
- $k1=$str[7];
- $k2=$str[9];
- $k3=$str[11];
- $k4=$str[13];
-
- //echo "关闭端口
";
- dio_close($f);
- //串口操作结束
-
- //输出开始
- //简单控制界面
- $output='串口继电器控制演示程序 2011年4月
- k1开
- k1关
- k2开
- k2关
- k3开
- k3关
- k4开
- k4关
- 全开
- 全关
- 查询
- XML格式查询
-
- 开关状态 1关 2开
-
k1:'.$k1.'
-
k2:'.$k2.'
-
k2:'.$k3.'
-
k2:'.$k4.'
';
-
- echo $output;
- }
- ?>
我的问题在哪里呢?
必须要用串口控制程序初始化一下窜口,我的php程序才能正常工作。不明白,google了N次,也google不出来。
自己分析是用win自己的mode命令设置的参数还不完整,可是要怎么设置呢?自己cmd下用mode测试,结果居然蓝屏死机了。
哪位大侠能给个解决方法?
================================================================================================================================
再研究,google,发现不用php 的dio 也成。别人的代码如下
- // HOW TO USE PHP TO WRITE TO YOUR SERIAL PORT: TWO METHODS
- $serproxy=true;
- if ($serproxy) {
- // Use this code in conjunction with SERPROXY.EXE
- // (http://www.lspace.nildram.co.uk/freeware.html)
- // which converts a Serial stream to a TCP/IP stream
- $fp = fsockopen ("localhost", 5331, $errno, $errstr, 30);
- if (!$fp) {
- echo "$errstr ($errno)";
- } else {
- $e = chr(27);
- $string = $e . "A" . $e . "H300";
- $string .= $e . "V100" . $e . "XL1SATO";
- $string .= $e . "Q1" . $e . "Z";
- echo $string;
- fputs ($fp, $string );
- fclose ($fp);
- }
- } elseif ($com1) {
- // Use this code to write directly to the COM1 serial port
- // First, you want to set the mode of the port. You need to set
- // it only once; it will remain the same until you reboot.
- // Note: the backticks on the following line will execute the
- // DOS 'mode' command from within PHP
- `mode com1: BAUD=9600 PARITY=N data=8 stop=1 xon=off`;
- $fp = fopen ("COM1:", "w+");
- if (!$fp) {
- echo "Uh-oh. Port not opened.";
- } else {
- $e = chr(27);
- $string = $e . "A" . $e . "H300";
- $string .= $e . "V100" . $e . "XL1SATO";
- $string .= $e . "Q1" . $e . "Z";
- echo $string;
- fputs ($fp, $string );
- fclose ($fp);
- }
- }
- ?>
这样也成?不用dio的话,配置服务器就方便多了。改吧!
- /**************************************************************
- *rs232new.php 控制4路串口继电器程序 *
- * 作者 tiger92665@gmail.com 2011.04 *
- **************************************************************/
- /* 采用232协议通信,波特率9600,8个数据位,一个停止位,无校验位。
- MODE COM1 9600, n, 8, 1
- 计算机到继电器板的数据帧说明:
- 数据头: 0x55 (作为标识)
- 地址:0x01(一个继电器板默认为1)
- 操作类型: 0x00(查询当前各继电器状态)0x01(写入新值)
- 数据(四个字节) 每个字节代表一个继电器,共四个;
- 数据值1:继电器断开;数据值2:继电器吸合;数据值0:继电器无动作。
- 校验 一字节和校验 0x56
- 继电器板到计算机的数据帧说明:
- 数据头: 0x22 (作为标识)
- 地址:0x01(单个继电器默认为1)
- 操作类型: 与计算机发来的操作类型一致
- 数据(四个字节) 每个字节代表一个继电器,共四个;
- 数据值1:继电器断开,数据值2:继电器吸合。
- 校验 一字节和校验(用来防止数据出错)
- 计算机发送指令表(部分):
- // k1 k2 k3 k4 校验位
- "55 01 01 02 00 00 00 59"; // 吸合第1路继电器
- "55 01 01 00 02 00 00 59"; // 吸合第2路继电器
- "55 01 01 00 00 02 00 59"; // 吸合第3路继电器
- "55 01 01 00 00 00 02 59"; // 吸合第4路继电器
- "55 01 01 01 00 00 00 58"; // 断开第1路继电器
- "55 01 01 00 01 00 00 58"; // 断开第2路继电器
- "55 01 01 00 00 01 00 58"; // 断开第3路继电器
- "55 01 01 00 00 00 01 58"; // 断开第4路继电器
- 55 01 01 02 02 02 02 5F 吸合所有继电器
- 55 01 01 01 01 01 01 5B 断开所有继电器
- "55 01 01 00 00 00 00 57"; 查询当前继电器板的状态 */
- //定义被操作的窜口
- $com="com4";
- //定义串口数据
- $k1on="\x55\x01\x01\x02\x00\x00\x00\x59";
- $k2on="\x55\x01\x01\x00\x02\x00\x00\x59";
- $k3on="\x55\x01\x01\x00\x00\x02\x00\x59";
- $k4on="\x55\x01\x01\x00\x00\x00\x02\x59";
- $k1off="\x55\x01\x01\x01\x00\x00\x00\x58";
- $k2off="\x55\x01\x01\x00\x01\x00\x00\x58";
- $k3off="\x55\x01\x01\x00\x00\x01\x00\x58";
- $k4off="\x55\x01\x01\x00\x00\x00\x01\x58";
- $kon="\x55\x01\x01\x02\x02\x02\x02\x5f";
- $koff="\x55\x01\x01\x01\x01\x01\x01\x5b";
- $kstatus="\x55\x01\x00\x00\x00\x00\x00\x56";
- //定义接受的get 命令
- $op = array("k1on", "k2on", "k3on", "k4on",
- "k1off","k2off","k3off","k4off","kon","koff","kstatus");
- //串口操作开始
- if ( isset($_GET['op']) and in_array($_GET['op'],$op ) )
- {
- $data=${$_GET['op']};
- set_time_limit(3);
- //echo 'windows下设置窜口参数
';
- exec("mode ".$com."BAUD=9600 PARITY=n DATA=8 STOP=1 odsr=off");
-
- //echo "打开端口$com
";
- $f = fopen ($com, 'w+');
- if(!$f)
- {
- die("Error when open $com");
- }
- //echo "向串口发送数据
".$data.'
';
- fwrite ($f, $data);
- //echo "接收数据
";
- $str="";
- for ($i = 0; $i
- {
- $str.=bin2hex(fread( $f,1));
- }
- //echo $str;
- $k1=$str[7];
- $k2=$str[9];
- $k3=$str[11];
- $k4=$str[13];
-
- //echo "关闭端口
";
- fclose($f);
- //串口操作结束
-
- //输出开始
- if ( isset($_GET['out']) and ($_GET['out']=="xml" ) )
- {
- //xml输出
- $output =
- '
-
'.$k1.'
-
'.$k2.'
-
'.$k3.'
-
'.$k4.' ';
- }
- else
- {
- //简单控制界面
- $output='串口继电器控制演示程序 2011年4月
- k1开
- k1关
- k2开
- k2关
- k3开
- k3关
- k4开
- k4关
- 全开
- 全关
- 查询
- XML格式查询
-
- 开关状态 1关 2开
-
k1:'.$k1.'
-
k2:'.$k2.'
-
k2:'.$k3.'
-
k2:'.$k4.'
';
- }
- echo $output;
- }
- ?>
测试也成功了,可以控制继电器动作!不过还是那个问题,要用串口程序初始化串口!
=======================================================================================================
你买的买的串口4路继电器板有DEMO程序给你吗?
如果有建议将DEMO改成PHP可调用交互的exe文件,通过exec 执行这类DELPHI或VB等写的程序和串口通信,相对PHP直接通讯要稳定的多。
我原先的一些PHP读写串口的应用都是通过购买的相应硬件厂方提供的DEMO改写的程序作通讯中介的。
-------------------------
有的,是vb做的,是调用 一个mscomm32.ocx控件实现的,不过好像与win7不兼容,它的程序跑不起来。
程序最终要到linux下运行,所以就不能用你的方法啦。
-----------------------------
NB啊,也有过类似的经历,找了一些PHP的串口资料,后面也没有搞到,倒是用了网络转COM口代替了.NPORT类产品.