最近要做一个电子秤数据读取功能,php有扩展php_dio.dll可以实现。
在网上参考相关代码之后遇到了各种问题,一一排除后最终可以读取电子称的数据,但是总是不顺利,最后调试代码发现dio_read方法读取数据时消耗了6-8秒,因为我的电子称连接的是收银台,这个时间是不能接受的,网上也没查到dio_read读取时间长的文章,而且相关文章少之又少,最后只能自己一步一步分析代码,断点调试,最后发现定位倒dio_read函数时间太长。
使用日志逐行调试,最终定位在dio_read函数上。
网上查阅各种文章均无收获,最后查阅dio_read官方文档,粗略阅读,未发现解决办法,无奈之下只得沉下心来在代码中查看dio_read函数的具体代码,代码包含了两个参数,其中第2个参数是$len,表示读取字节长度,默认1k,猜测改变该参数可能会发生变化。
修改参数$len为512之后,查看调试日志,并无明显变化,dio_read还是在6秒,随后修改为128,发现了变化,日志中$shuju变量数据变少了,随后再次修改为32,变化非常明显,从dio_read函数读出的重量数据是被拼接了2次的数据,至此我猜测,默认$len参数是1kb,那么dio_read要把数据读取并凑够1024b才返回,出现6秒的时间则是重复读取并拼接的原因。随后再把数字改为16b,则日志显示数据简洁,从电子称读取的数据很干净,并无多次拼接现象。
最大化提升效率,则把$len参数值修改为16,不能再小了,会截断数据出现乱码。
getTrace(),$e->getTraceAsString());
}
//window系统开机执行此文件
//循环读取到数据之后实时上传至云端
//云端界面读取数据显示
function cron(){
inlog(date('Y-m-d H:i:s'),'a');
//读取串口数据前,确保串口不被占用,如果出现权限拒绝,多半是被其它应用占用了
//处理方案:
//找到占用com串口的应用,找到应用服务商,关闭串口占用服务,运行代码读取串口数据
$shuju = null;
// 定义com口为com3(可以修改),波特率为115200(可修改)
exec('mode COM2: baud=9600 data=8 stop=1 parity=n xon=on');
// 打开串口
$ck = dio_open('COM2:', O_RDWR);
inlog(date('Y-m-d H:i:s'),'b');
// 如果打开串口失败,停止脚本,并输出“打开串口COM3失败”;
if(!$ck){
inlog('打开串口COM2失败');
return '打开串口COM2失败';
}
//正常来说这里可以顺利读取数据,但也可能出现一直读取不到数据并且一直循环,
//而外部还是每N秒访问一次该文件,这样就会逐渐增加系统资源消耗,直到系统卡死
$shuju = null;
while(true)
{
inlog(date('Y-m-d H:i:s'),'c');
//读取串口并将读取到的数据赋值给变量‘$shuju’;
$shuju = dio_read($ck,256);
inlog(date('Y-m-d H:i:s'),'d');
//向串口发送数据(本人猜测这里只是为了让php_read凑够$len参数的字节数,因为不凑够则会一直执行)
//if($shuju != null){
// //如果接收到了数据,就向串口写回去
// dio_write ($ck, $shuju);
//}
inlog('上报重量开始',$shuju);
$url = 'http://xbcstore.playone.cn/index/checkstand/cominfo';
curl_post($url,[
'com_data'=>isset($shuju)?$shuju:'no_data'
]);
//ob_flush();
//flush();
sleep(1);
//ob_end_flush();
}
//反向字符串
//echo strrev($shuju);
//关闭串口
//dio_close($ck);
//return '重量数据实时读取中,请勿关闭本界面!!!';
}
function curl_post( $url, $postdata) {
$timeout = 5;
$connect_timeout = 4;
$set_time_limit = 10;
//if($timeout + $connect_timeout < $set_time_limit) throw new \Exception('脚本超时值必须大于等于连接超时与请求处理超时之和');
//set_time_limit($set_time_limit);
$header = array(
'Accept: application/json',
);
//初始化
$curl = curl_init();
//设置抓取的url
curl_setopt($curl, CURLOPT_URL, $url);
//设置头文件的信息作为数据流输出
curl_setopt($curl, CURLOPT_HEADER, 0);
//设置获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
// 超时设置
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
//发起连接前等待的时间,如果设置为0,则无限等待。
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
// 超时设置,以毫秒为单位
// curl_setopt($curl, CURLOPT_TIMEOUT_MS, 500);
// 设置请求头
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE );
//设置post方式提交
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
//执行命令
$data = curl_exec($curl);
//上报结果
inlog(json_encode($data,JSON_UNESCAPED_UNICODE));
// 显示错误信息
if (curl_error($curl)) {
//inlog('code:'.curl_errno($curl).'. msg:'.curl_error($curl));
//返回错误码
//return ['code'=>curl_errno($curl), 'msg'=>curl_error($curl)];
} else {
//关闭句柄
curl_close($curl);
// 返回的内容
//inlog('code:200'.'. msg:ok');
}
}
function inlog($txt,$data=''){
$date = date('Y-m-d_H');
$filepath = "./log/";
if(!file_exists($filepath)){
mkdir($filepath,0777,true);
}
$file_name = "log_{$date}.txt";
file_put_contents($filepath.$file_name, "\n".date('Ymd H:i:s').' '.$txt.' | '.$data, FILE_APPEND);
}
dio_read读取时间长短取决于$len参数,同时每个电子称的数据量不一样,需要读取一次打印在日志里,根据数据量多少来定$len的大小,我的数据量在16b的样子最合适,而不是函数默认的1kb。
此代码复制可用,但最终效果需要自己测试并修改。
作为一个急躁的业余码农,很难潜心研究一样东西,不知道什么时候才能不这样。
END