SRSniffer

调试网络通讯的好软件。SRSniffer?软件只有39Kb,真良心啊!

发表在 待分类 | SRSniffer已关闭评论

nodemcu

ESP8266真是一款牛牛的产品,用于扩展mcu的wifi就很不错了,然而本身还是一款低功耗的32位mcu,再用一款8位的单片机去控制这款芯片真是小兵指挥将军了。

对这款芯片的开发可以通过官方的IDE来开发,当然我不习惯他们这个平台,但是发现了一款nodemcu的固件,这个固件可以用lua语言来开发,当然测试这个nodemcu平台之前我也没有接触过lua,但确定的是这是一款简单好用的语言。

安信可有售nodemcu的开发板,价格也不贵,但是手上有一块ESP8266-12F的模块,外挂个CH340就简单测试吧。万用板堆了个最小电路。

1、刷固件

首先,对于0.96版本之后的固件,是不提供bin文件的,需要到https://nodemcu-build.com/来选择自己需要的模块来生成固件,只需要提供自己的邮箱,一会儿就能收到编辑好的下载链接了。

刚开始,下载的几个固件刷进去后都是不停的串口发送乱码,也不知道是怎么回事,刷入0.96版本的固件是可以直接用的。

解决这个问题真是费了挺大的劲,找了很久终于看到有人说刷0.96版本以上的需要再刷一个固件才可以,这个固件在哪里却没有说,最后终于在https://www.plotcup.com/2016/11/26/nodemcu-1/里的文章提到了解决的方法,其实看过才知道http://nodemcu.readthedocs.io/en/master/en/flash/这个官方文档都提到了怎么办,只是e文不好又没仔细看才至于不知道怎么解决。

其实就是在nodemcu-flasher-master的Resources里有esp_init_data_default.bin文件,刷了下载的固件后再刷这个文件就可以,对于4MB的flash,刷写地址是0x3fc000,高级界面都是默认的设置就可以,如果不稳定,可以降低波特率。

对于高一点的版本,默认的串口波特率是115200,不再是9600,刷完固件,正常启动的第一次一排乱码输出后有Formatting file system. Please wait…的提示,需要等待一下,然后就进系统了,
NodeMCU custom build by frightanic.com
branch: 1.5.4.1-final
commit: 1885a30bd99aec338479aaed77c992dfd97fa8e2
SSL: false
modules: file,gpio,net,node,ow,tmr,wifi
build built on: 2017-05-30 03:49
powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)

刷机完成!OK!

下载工具的地址:https://github.com/nodemcu/nodemcu-flasher

2,编程。
ESPlorer是目前最好用的编程环境,只是需要java环境,这点稍有不爽。

左侧编辑窗口写好的lua代码保存就可以发送到mcu执行,lua为代码解释执行,还可以把代码读回来再修改,这点非常方便。瞬间感觉高达上。牛!

下载地址:https://esp8266.ru/esplorer/

 

发表在 待分类 | nodemcu已关闭评论

php记录日志的一种方式

要调试post数据,但是post过去的数据又不能直接返回到客户端,所以就用下边的方式来将获取的post数据保存到文本。这样,所有的数据就保存下来了。

$dat = file_get_contents(“php://input”); //接收POST数据

file_put_contents(“data.txt”,$dat,FILE_APPEND);

这样每次的数据会在data.txt后边添加,不会替换到之前的数据。

//$soap=file_get_contents(“A.xml”);

这个代码就是读取的代码了,将文件赋值到文本里。使用也很方便。

发表在 待分类 | php记录日志的一种方式已关闭评论

php解析webservice服务

webservice服务我认为不是个非常通用的接口,虽然这是个标准的接口,但是跨语言处理问题还是非常多的,比如我用PHP来处理java提供的webservice就是一个非常麻烦的事情。

PHP自带soap扩展,本来以为用来解析java的soap服务很容易,但发现问题很多,php间通讯是没有问题的,但格式与java的不一样,就通讯不上了。

感慨:json是真心不错的。

好在PHP无比强大,模拟数据也实现了数据通讯。

首先,因为php的soap扩展提供给服务器的数据,服务器端不匹配,所以就不用soap扩展了,改用curl模拟。

完整代码:


<?php
$soap='<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<AisQuery xmlns="http://www.kingdee.com/Public"/>
</soap:Body>
</soap:Envelope>';
//$soap=file_get_contents("A.xml");//从文件获取字符串的方式
//echo $soap;
$ch=curl_init();
//curl_setopt($ch,CURLOPT_URL,"http://192.16.1.12/soap.php");
curl_setopt($ch,CURLOPT_URL,"http://192.168.100.108/KDWEBSERVICE/Public.asmx");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml; charset=utf-8"));
curl_setopt($ch,CURLOPT_POSTFIELDS,$soap);
$data=curl_exec($ch);
curl_close($ch);
//echo $data;//得到返回数据

$dom = new DOMDocument();
$dom->loadXML($data);
// 获取所有的AisInfo标签
$AisInfo = $dom ->getElementsByTagName("AisInfo" );
// 循环遍历AisInfo标签
foreach ($AisInfo as $post ){
// 获取AisInfo标签
$AisName = $post ->getElementsByTagName("AisName" );
$AisID = $post ->getElementsByTagName("AisID" );
$Number = $post ->getElementsByTagName("Number" );
/**
* 要获取标签的属性要分两部走
* < title id ="1" > PHP XML处理</ title >
* 1. 获取标签中所有属性的列表也就是$*->item(0)->attributes
* 2. 获取标签中第一个属性,因为其在第一位所以用item(0)
* 3. $title ->item(0)->attributes->item(0)->nodeValue
*
* 小提示:
* 若取属性的值可以用item(*)->nodeValue
* 若取属性的标签可以用item(*)->nodeName
* 若取属性的类型可以用item(*)->nodeType
*/
echo $AisName ->item(0)->nodeName .': '. $AisName ->item(0)->nodeValue . "<br />" ;
echo "AisID: " . $AisID ->item(0)->nodeValue . "<br />" ;
echo "Number: " . $Number->item(0)->nodeValue . "<br />" ;
echo "Version: " . $post ->getElementsByTagName("Version") ->item(0)->nodeValue . "<br /><br />" ;
}
?>

php直接post了服务器需要的xml数据,返回的数据是xml符合soap规范。

这个xml的处理也需要一点特殊,首先,xml_parse_into_struct,这个方式可以获取数据,但是得到的数组的格式我看了,不是很容易处理。再有能直接处理的就是这个DOMDocument了。这个获取到的是dom对象,按照上文的代码可以解析,还有另一种方法是解析成数组再处理。

function getArray($node) {
$array = false;

if ($node->hasAttributes()) {
foreach ($node->attributes as $attr) {
$array[$attr->nodeName] = $attr->nodeValue;
}
}

if ($node->hasChildNodes()) {
if ($node->childNodes->length == 1) {
$array[$node->firstChild->nodeName] = getArray($node->firstChild);
} else {
foreach ($node->childNodes as $childNode) {
if ($childNode->nodeType != XML_TEXT_NODE) {
$array[$childNode->nodeName][] = getArray($childNode);
}
}
}
} else {
return $node->nodeValue;
}
return $array;
}

$doc=new DOMDocument();
$doc->loadXML($data);
$root=$doc->documentElement;
//var_dump($root);
//print_r($root);
//print_r(getArray($root->firstChild));
//print_r(getArray($root->firstChild->firstChild->firstChild->firstChild));
//$items=getArray($root->firstChild->firstChild->firstChild->firstChild);
$items=getArray($root->firstChild);
//print_r($items);
$num=count($items['AisQueryResponse']['AisQueryResult'][0]['AisInfo']);
for($i=0;$i<$num;$i++){
echo 'AisID:'.$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['AisID'][0]['#text'].'</br>';
echo 'AisName:',$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['AisName'][0]['#text'],'</br>';
echo 'Number:',$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['Number'][0]['#text'],'</br>';
echo 'Version:',$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['Version'][0]['#text'],'</br>';
}

用getArray函数获取到数组对象,然后处理数组就可以。但是发现1条数据的时候和两条数据的情况数组的深度发生了变化,还没有细研究。

2017-6-1更新:

本来以为上边的代码可以用了,但测试k3v14.2没有问题,测试我们公司正在用的k3v10.3却不能通过。说明他们的服务器本身就不是一样的。侦听了下源码,发现10.3版本的k3需要传递的头是不一样的。改改就可以适配了。主要是curl部分的不同。需要一个SOAPAction。另外再说下一个小工具,SRSniffer,这个软件真不错,其它的软件如Fiddler2等需要做代理啊,或者需要.net环境啊,或者需要只能调试浏览器的通讯什么的,这个真是简单好用。


$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,"http://192.168.100.108/KDWEBSERVICE/Public.asmx");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POST,1);
//curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml"));//k3v14.2 testpass
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml","SOAPAction:\"http://www.kingdee.com/Public/AisQuery\""));//k3v10.3 testpass
curl_setopt($ch,CURLOPT_POSTFIELDS,$soap);
$data=curl_exec($ch);
curl_close($ch);

发表在 待分类 | php解析webservice服务已关闭评论

Php Xml解析之DOMDocument使用方法

http://blog.csdn.net/leonzhang2008/article/details/5107945

发表在 待分类 | Php Xml解析之DOMDocument使用方法已关闭评论

51duino

基于STC单片机的51duino平台。

优势在于有了图形化编程的51平台,其源代码的编程方式也可以借鉴。结构和我编程很相似,都是基于STC库文件的方式来做。51duino_SDKV2.0全功能源代码+舵机记忆+8路舵机+红外避障+超声波避障+循迹+跟随+大灯_Publish

XR Block V1.0

对于初学单片机还是有一定帮助的。

发表在 待分类 | 51duino已关闭评论

ESP8266 Doit固件

Doit的这款固件是可以通过wifi来配置的透传固件,非常好用。

ESP8266Flasher

ESP8266_Doit串口透传固件使用方法-图文说明(V2.4.1)

发表在 待分类 | ESP8266 Doit固件已关闭评论

arduino 小车


//定义变量程序段
//把小车左轮电机编码器码盘的OUTA信号连接到Arduino控制器的数字端口2,
//数字端口2是Arduino的外部中断0的端口。
#define PinA_left 2 //外部中断0
#define PinB_left 8 //小车左车轮电机编码器码盘的OUTB信号连接到数字端口8
//把小车右车轮电机编码器码盘的OUTA信号连接到Arduino控制器的数字端口3,
//数字端口3是Arduino的外部中断1的端口。
#define PinA_right 3 //外部中断1
#define PinB_right 9 //小车右车轮电机编码器码盘的OUTB信号连接到数字端口9
int E_left =5; //L298P直流电机驱动板的左轮电机使能端口连接到数字接口5
int M_left =4; //L298P直流电机驱动板的左轮电机转向端口连接到数字接口4
int E_right =6; //连接小车右轮电机的使能端口到数字接口6
int M_right =7; //连接小车右轮电机的转向端口到数字接口7
int val_right; //小车右轮电机的PWM功率值
int val_start;//上位机控制字节,用于控制电机是否启动;
int val_FB; //上位机控制字节,用于控制电机是正转还是反转;
int val_left;//上位机控制字节,用于提供给左轮电机PWM功率值。
int count1 = 0; //左轮编码器码盘脉冲计数值
int count2= 0; //右轮编码器码盘脉冲计数值
int rpm1 = 0; //左轮电机每分钟(min)转速(r/min)
int rpm2 = 0; //右轮电机每分钟(min)转速(r/min)
int flag;//设置小车行车状态,是前进、后退还是停止
unsigned long timenew = 0, old_time = 0; // 时间标记
unsigned long time1 = 0, time2 = 0; // 时间标记

//初始化程序段
void setup()
{
Serial.begin(9600); // 启动串口通信,波特率为9600b/s
pinMode(M_left, OUTPUT); //L298P直流电机驱动板的控制端口设置为输出模式
pinMode(E_left, OUTPUT);
pinMode(M_right, OUTPUT);
pinMode(E_right, OUTPUT);
pinMode(PinA_left,INPUT); //伺服电机编码器的OUTA和OUTB信号端设置为输入模式
pinMode(PinB_left,INPUT);
pinMode(PinA_right,INPUT);
pinMode(PinB_right,INPUT);
//定义外部中断0和1的中断子程序Code(),中断触发为下跳沿触发
//当编码器码盘的OUTA脉冲信号发生下跳沿中断时,
//将自动调用执行中断子程序Code()。
attachInterrupt(0, Code1, FALLING);//小车左车轮电机的编码器脉冲中断函数
attachInterrupt(1, Code2, FALLING);//小车右车轮电机的编码器脉冲中断函数
}

//子程序程序段
void advance()//小车前进
{
digitalWrite(M_left,HIGH);
analogWrite(E_left,val_left);
digitalWrite(M_right,LOW);
analogWrite(E_right,val_right);
}
void back()//小车后退
{
digitalWrite(M_left,LOW);
analogWrite(E_left,val_left);
digitalWrite(M_right,HIGH);
analogWrite(E_right,val_right);
}
void Stop()//小车停止
{
digitalWrite(E_right, LOW);
digitalWrite(E_left, LOW);
}

//主程序段
void loop()
{
if (Serial.available()>0) //如果Arduino控制器读缓冲区中存在上位机下达的字节
{
val_start= Serial.read(); //从读缓冲区中读取上位机的三个控制字节
delay(5);
val_FB = Serial.read();
delay(5);
val_left= Serial.read();
delay(5);
if(val_start==0x11) //如果读出的第一个字节为小车启动标志字节0x11
{
if(val_FB ==0xAA) //如果读出的第二个字节为小车前进标志字节0xAA
{
//读出的第三个字节为小车左车轮电机的PWM功率值,把它赋值给右车轮电机功率变量
val_right=val_left;
advance(); //小车前进
flag='a'; //设置小车前进标志字符
count1 = 0; //恢复到编码器测速的初始状态
count2 = 0;
old_time= millis();
}
else if(val_FB ==0xBB) //如果读出的第二个字节为小车后退标志字节0xBB
{
val_right=val_left;
back(); //小车后退
flag='b'; //设置小车后退标志字符
count1 = 0; //恢复到编码器测速的初始状态
count2 = 0;
old_time= millis();
}
}
else if(val_start==0x22) //如果读出的第一个字节为小车停止标志字节0x22
{
Stop(); //小车停止
flag='s'; //设置小车停止标志字符
}
}
timenew = millis();//以毫秒为单位,计算当前时间
//计算出每一秒钟编码器码盘计得的脉冲数,
if(abs(timenew - old_time) >= 1000) // 如果计时时间已达1秒
{
detachInterrupt(0); // 关闭外部中断0
detachInterrupt(1); // 关闭外部中断1
//把每一秒钟编码器码盘计得的脉冲数,换算为当前转速值
//转速单位是每分钟多少转,即r/min。这个编码器码盘为12个齿。
rpm1 =(float)count1*60/12;//小车左车轮电机转速
rpm2 =(float)count2*60/12; //小车右车轮电机转速

//根据左右车轮转速差rpm1-rpm2,乘以比例因子0.4,获得比例调节后的右车轮电机PWM功率值
val_right=(float)val_right+(rpm1-rpm2)*0.4;
Serial.print(rpm1);//向上位计算机上传左车轮电机当前转速
Serial.print(rpm2);
Serial.print(val_right);// 向上位计算机上传PID调节后的右轮电机PWM功率值
if(flag=='a') //根据刚刚调节后的小车电机PWM功率值,及时修正小车前进或者后退状态
advance();
if(flag=='b')
back();
//恢复到编码器测速的初始状态
count1 = 0; //把脉冲计数值清零,以便计算下一秒的脉冲计数
count2 = 0;
old_time= millis(); // 记录每秒测速时的时间节点
attachInterrupt(0, Code1,FALLING); // 重新开放外部中断0
attachInterrupt(1, Code2,FALLING); // 重新开放外部中断1
}
}

// 左侧车轮电机的编码器码盘计数中断子程序
void Code1()
{
//为了不计入噪音干扰脉冲,
//当2次中断之间的时间大于5ms时,计一次有效计数
if((millis()-time1)>5)
//当编码器码盘的OUTA脉冲信号下跳沿每中断一次,
count1 += 1; // 编码器码盘计数加一
time1==millis();
}
// 右侧车轮电机的编码器码盘计数中断子程序
void Code2()
{
if((millis()-time2)>5)
//当编码器码盘的OUTA脉冲信号下跳沿每中断一次,
count2 += 1; // 编码器码盘计数加一
time2==millis();
}

发表在 待分类 | arduino 小车已关闭评论

USBISP下载arduino bootloaders

手上一块arduino不工作了,怀疑芯片故障了,新买来328P后只是块avr单片机,并不能直接用来做arduino,需要刷入arduino的 bootloaders后就是一样的arduino了。

买来usb ISP,才发现arduino的IDE里只支持的编程器名称有USBtinyISP和USBasp,虽然我不知道这几种与USBISP有什么区别,但显然跟我手上这个还有点差别。

USBISP就是烧录avr和51的烧录器,肯定是支持我来烧录bootloaders的。

首先,编程器带的线是10PIN的,arduino上的编程口是6PIN的,需要一个转换。

网上有专门卖转换插头,显然我没有买,根据引脚定义,直接用杜邦线连接起来就可以了。

以下引用了别人的图片:

烧写mega328p的bootloader: 如下图,插好设备板上的”ON”指示灯会点亮。

打开软件progisp,步骤如下

1、修改芯片为328P
2、点击RD,下边应提示读出ID成功。
3、熔丝位设置。
在hardware\arduino\avr\boards.txt文件里有这样代码:


##############################################################

uno.name=Arduino/Genuino Uno

uno.vid.0=0x2341
uno.pid.0=0x0043
uno.vid.1=0x2341
uno.pid.1=0x0001
uno.vid.2=0x2A03
uno.pid.2=0x0043
uno.vid.3=0x2341
uno.pid.3=0x0243

uno.upload.tool=avrdude
uno.upload.protocol=arduino
uno.upload.maximum_size=32256
uno.upload.maximum_data_size=2048
uno.upload.speed=115200

uno.bootloader.tool=avrdude
uno.bootloader.low_fuses=0xFF
uno.bootloader.high_fuses=0xDE
uno.bootloader.extended_fuses=0x05
uno.bootloader.unlock_bits=0x3F
uno.bootloader.lock_bits=0x0F
uno.bootloader.file=optiboot/optiboot_atmega328.hex

uno.build.mcu=atmega328p
uno.build.f_cpu=16000000L
uno.build.board=AVR_UNO
uno.build.core=arduino
uno.build.variant=standard

##############################################################

uno.bootloader.low_fuses=0xFF
uno.bootloader.high_fuses=0xDE
uno.bootloader.extended_fuses=0x05

就是说熔断位应设置为低位FF,高位DE,扩展位05

设置好后要写入,检验熔丝位有没有正确写入,可以在点写入之后再点读出,看是否与写入相同!

4、调用flash文件,文件在hardware\arduino\avr\bootloaders\optiboot\optiboot_atmega328.hex

5、点自动,稍等一下就可以测试arduino了。

ISP下载软件

扩展:原版arduino uno R3 的串口是Mega16u2,烧录串口的方式是熔丝位:低位FF,高位D9,扩展位f4.固件在\hardware\arduino\avr\firmwares\atmegaxxu2\Arduino-COMBINED-dfu-usbserial-atmega16u2-Uno-Rev3.hex

 

发表在 待分类 | USBISP下载arduino bootloaders已关闭评论

舵机控制

舵机的原理可以应用到很多控制场合,比如阀门的控制。购买的9g舵机用来做实验,发现需要的控制信号为PWM,但是这个PWM是有限制的,PWM的频率只是50HZ,脉冲宽度要是只是0.5ms到2.5ms之间。

抽空把这个改造下,改成个电动蝶阀的控制。

发表在 待分类 | 舵机控制已关闭评论