ecfa是什么意思

更新时间:2022-12-31 21:33:43 阅读: 评论:0


2022年12月31日发(作者:鲋鱼)

node-red教程5函数节点

发送消息

这个函数既可以使⽤“return”向流中的下⼀个节点传递消息,也可以调⽤(messages)。

它可以返回或是发送

⼀个单⼀的消息对象——传递给连接到第⼀个输出的节点

⼀组消息对象——传递给连接到相应输出的节点

如果数组的任何元素本⾝都是⼀组消息,那么多条消息就会被发送到相应的输出。

如果返回null,⽆论是单独还是作为数组的元素,都不会传递任何消息。

⽇志和错误处理

要记录任何信息或报告错误,可以使⽤以下功能:

(“Logmessage”)

(“Warning”)

(“Error”)

1

2

3

Catch节点也可以⽤来处理错误。为了调⽤Catch节点,将msg作为第⼆个参数传递给:

5.2使⽤函数控件实现多个输出

前边使⽤switch控件时我们已经实现了根据不同的条件,来实现多个输出。Switch控件是⼀种功能控件,⽽函数控件也是功能控件。

甚⾄可以说,函数控件可以通过编程实现所有功能控件的功能。接下来,我们尝试⽤函数控件实现多个输出。

5.2.1最简单的函数控件⽤法

拖⼊⼀个inject、function与debug,⽆需任何修改,直接⽤线连接三个节点。

这⾥写图⽚描述

部署,并点击inject的输⼊按钮,观察调试窗⼝。可以看到debug节点打印的调试信息。

这⾥写图⽚描述

你可能会说,什么嘛,不加这个函数节点,直接连接inject与debug节点,不也是这个效果嘛!这个函数节点有什么⽤?

它的作⽤就是,把消息原封不动输出。原封不动的输出,也是⼀种功能,最简单的功能。

我们双击函数节点,来看⼀下⾥边的内容。

这⾥写图⽚描述

只有⼀⾏代码,returnmsg,返回消息。

回过头来,看函数控件的说明信息。⽤来处理节点接收到的消息,消息作为⼀个名为msg的对象传⼊。可以使⽤“return”向下⼀个节

点传递消息。也就是说,函数控件的输⼊时msg对象,输出也是msg对象。在输出之前,可以对msg对象进⾏处理。所谓对象,意思是这

是⼀个msg实例,是具体的数据,不是抽象的,更不是msg跟异性朋友处对象。

既然可以原封不动返回msg,当然也可以不返回。只要把语句改为returnnull即可。Null的意思是空值,也可以说没有值。修改代码

为:

这⾥写图⽚描述

重新部署,⽆论现在如何点击inject节点的输⼊按钮,debug节点都不会打印出任何消息了。

5.2.2在函数节点中创建并返回多个消息

函数控件中,除了可以处理输⼊的msg对象以外,也可以⾃⼰定义⼀些msg对象。另外,说明⽂件中,有介绍说function可以返回⼀

个对象,或是⽤数组传递⼀组对象。我们先尝试⾃⾏建⽴⼀组对象并传递。

修改函数节点:取个合适的名称,添加如下代码,并把输出改为两路。

varmsg1={payload:“firstoutofoutput1”};

varmsg2={payload:“condoutofoutput1”};

varmsg3={payload:“thirdoutofoutput1”};

varmsg4={payload:“onlymessagefromoutput2”};

return[[msg1,msg2,msg3],msg4];

1

2

3

4

5

这⾥写图⽚描述

拖⼊两个debug节点,命名,并分别接到函数节点的两路输出去。然后点击inject的按钮,观察调试窗⼝的现象。

这⾥写图⽚描述

这⾥写图⽚描述

我们发现,OUT1节点⼀⼝⽓收到了3条消息,OUT2节点收到了⼀条消息,且消息的内容我们刚刚输⼊的代码有关系。跟输⼊的消息没有

任何关系,因为输⼊的是时间戳。

关注最后⼀句并对⽐分析:

returnmsg;//⼀个返回值

return[[msg1,msg2,msg3],msg4];//⼀组返回值

1

2

可以得出结论,如果想得到多个返回值,需要把返回值放到英⽂的中括号⾥。在3.1.3⼩节⾥,恰好在inject的内容⾥,输⼊数组时,也

是放在中括号⾥。这说明,多个返回值需要放到⼀个数组中,数组⽤中括号括起来,⽤逗号间隔开。⽽数组元素的顺序,也就是输出对象的

顺序,⽐如刚刚的OUT1收到的是msg1,msg2与msg3,⽽OUT2收到的msg4。

另外,虽然名为数组(array),但是其边的元素并不是数字,⽽是msg对象,所以,更贴切的叫法应该是:对象组。

这⾥写图⽚描述

这个例⼦代码如下:

[{“id”:“09a8”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“两路输出”,“func”:“var

msg1={payload:“firstoutofoutput1”};nvarmsg2={payload:“condoutofoutput1”};nvarmsg3={

payload:“thirdoutofoutput1”};nvarmsg4={payload:“onlymessagefromoutput2”};nreturn[[msg1,msg2,

msg3],msg4];”,“outputs”:2,“noerr”:0,“x”:360,“y”:180,“wires”:[[“6144cc3f.854e34”],

[“146c”]]},

{“id”:“e49b03a7.395d1”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:"",“payload”:"",“payloa

dType”:“date”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:200,“y”:180,“wires”:

[[“09a8”]]},

{“id”:“6144cc3f.854e34”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT1”,“active”:true,“tosideb

ar”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:510,“y”:160,“wires”:[]},

{“id”:“146c”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT2”,“active”:true,“tosideb

ar”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:510,“y”:220,“wires”:[]}]

1

5.2.3通过判断语句进⾏数据分类

Switch控件可以进⾏数据的分流,它属于功能控件。函数控件是功能控件⾥,功能最强的,它可以实现switch控件的功能。

第3章4节讲解switch控件时,使⽤过判断数字的例⼦,这⾥⽤函数控件来实现它。

输⼊与输出不变,把函数节点替换掉switch节点,并修改代码如下:

这⾥写图⽚描述

分别点击3个inject节点的输⼊按钮。可以再调试窗⼝观察到以下现象。

这⾥写图⽚描述

可以看出,所有数据都根据判断条件正确输出,说明我们的任务完成了。代码如下:

[{“id”:“50a42dcc.f47e44”,“type”:“inject”,“z”:“899b4619.356a88”,“name”:"",“topic”:"",“payload”:“100”,

“payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:330,“y”:160,“wires”:

[[“d616421c.69733”]]},

{“id”:“ea00b43e.c61ba8”,“type”:“inject”,“z”:“899b4619.356a88”,“name”:"",“topic”:"",“payload”:“10”,“

payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:330,“y”:220,“wires”:

[[“d616421c.69733”]]},

{“id”:“370ac143.d7c11e”,“type”:“inject”,“z”:“899b4619.356a88”,“name”:"",“topic”:"",“payload”:“1”,“p

ayloadType”:“num”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:330,“y”:280,“wires”:

[[“d616421c.69733”]]},

{“id”:“3e98”,“type”:“debug”,“z”:“899b4619.356a88”,“name”:“OUT1”,“active”:true,“toside

bar”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:750,“y”:160,“wires”:[]},

{“id”:“22fba15b.22857e”,“type”:“debug”,“z”:“899b4619.356a88”,“name”:“OUT2”,“active”:true,“toside

bar”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:750,“y”:220,“wires”:[]},

{“id”:“82f1829b.b1b8a”,“type”:“debug”,“z”:“899b4619.356a88”,“name”:“OUT3”,“active”:true,“tosideb

ar”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:750,“y”:280,“wires”:[]},

{“id”:“d616421c.69733”,“type”:“function”,“z”:“899b4619.356a88”,“name”:“判断数字”,“func”:“if

(d>10){nreturn[msg,null,null];n}elif(d===10){nreturn[null,msg,null];n}el{nreturn

[null,null,msg];n}”,“outputs”:3,“noerr”:0,“x”:540,“y”:220,“wires”:[[“3e98”],

[“22fba15b.22857e”],[“82f1829b.b1b8a”]]}]

1

然后看⼀看通过主题来判断的例⼦。跟判断数字没有多⼤的不同,只需要把被判断的条件改为d就可以。

这⾥写图⽚描述

这段代码出现了⼀个indexOf()函数,它的作⽤就是检查⼀下调⽤它的字符串,有没有包含括号⾥的字符(或字符串)。如果包含的

话,返回字符在字符串中⾸次出现的位置。如果没有包含的话,返回-1。所以,if(f(“e”)!=-1)在包含的情况下成

⽴。如图配置并部署。

这⾥写图⽚描述

分别输⼊3个inject节点,结果如下:

这⾥写图⽚描述

这是跟3.4.4⼩节中,在选择“接受第⼀条匹配消息后停⽌”的情况下,结果⼀样。

代码如下:

[{“id”:“e98b2a01.0b6228”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“判断主题”,“func”:“if

(===“apple”){nreturn[msg,null,null];n}nif(===“banana”){nreturn[null,msg,

null];n}nif(f(“e”)!=-1){nreturn[null,null,msg

];n}n”,“outputs”:3,“noerr”:0,“x”:340,“y”:160,“wires”:[[“7cfcaea9.f501f”],[“6997f0e2.7d67d”],

[“95d3ab47.6f79f8”]]},

{“id”:“77880a51.e8f324”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“apple”,“payload”:“

apple”,“payloadType”:“str”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:130,“y”:100,“wires”:

[[“e98b2a01.0b6228”]]},

{“id”:“98875d47.089c5”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“banana”,“payload”:

“banana”,“payloadType”:“str”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:140,“y”:160,“wire

s”:[[“e98b2a01.0b6228”]]},

{“id”:“a5a2ecfd.7f28f”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“orange”,“payload”:“o

range”,“payloadType”:“str”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:140,“y”:220,“wires”:

[[“e98b2a01.0b6228”]]},

{“id”:“7cfcaea9.f501f”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT1”,“active”:true,“tosidebar

”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:530,“y”:100,“wires”:[]},

{“id”:“6997f0e2.7d67d”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT2”,“active”:true,“tosideba

r”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:530,“y”:160,“wires”:[]},

{“id”:“95d3ab47.6f79f8”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:“OUT3”,“active”:true,“tosideb

ar”:true,“console”:fal,“tostatus”:fal,“complete”:“payload”,“x”:530,“y”:220,“wires”:[]}]

1

思考⼀下,apple显然是包括了字符“e”的,但是点击apple时,为什么OUT3没有收到apple的数据?

这是因为,编程的函数有⼀个特点:见到return以后函数就结束了,即便return之后还有没执⾏的代码。if(===

“apple”)成⽴以后就执⾏了return,当然不会管有没有包含“e”的判断条件了。

如果你想实现apple既要输出给OUT1,⼜要输出给OUT3的话,可以使⽤⼀个数组,在满⾜if(===“apple”)时,元素1

储存apple;在满⾜if(f(“e”)!=-1)时,元素3存储apple,只使⽤⼀次return,来返回数组就可以了。你可以尝试⾃

⼰实现它。

后边也会⽤到函数的nd⽅法。

5.3使⽤函数控件处理数据

上⼀⼩节使⽤函数控件进⾏判断与多个输出的情况下,函数控件可能还没有switch好⽤。但是在这⼀节,函数控件的优势就能完全体现

出来。接下来使⽤函数控件可以进⾏数据的处理。

5.3.1单个数字的计算

接下来尝试⽤函数节点对数字进⾏计算。拖⼊inject节点,并把输⼊的内容改为数字;拖⼊debug节点⽤来观察现象,拖⼊函数节点并

做如下修改:

这⾥写图⽚描述

其中,varnewMsg={payload:d*2}语句的意思是,新建⼀个对象,名为newMsg,它有payload属性,并且payload

的值为d的两倍。最后返回的是newMsg,也就是新建的这个对象。

这⾥写图⽚描述

部署并运⾏,可以看到现象是,调试窗⼝显⽰的数值是输⼊的两倍。说明函数节点的功能实现了。

这⾥写图⽚描述

我们知道,消息是通过msg对象传过来的,可不可以不新建⼀个对象,直接修改d呢?当然是可以的。

将函数节点内的代码修改为

d=d*2;

returnmsg;

1

2

部署,可以发现结果⼀样正确。由于这个代码实际的处理顺序是从右向左,也就是d先乘以2,再赋值给d。出

于⽅便理解的⾓度,我们总是⽤⼀个变量来暂时储存⼀下d计算过的值。代码修改为:

vartemp=d*2;

d=temp;

returnmsg;

1

2

3

这段程序保存如下:

[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:"",“payload”:“2333”

,“payloadType”:“num”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:140,“y”:180,“wires”:

[[“ecfadc58.b48d4”]]},{“id”:“ecfadc58.b48d4”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“乘以

⼆”,“func”:“vartemp=d*2;d=temp;nreturn

msg;”,“outputs”:1,“noerr”:0,“x”:310,“y”:180,“wires”:[[“65b”]]},

{“id”:“65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,

“console”:fal,“tostatus”:fal,“complete”:“fal”,“x”:520,“y”:180,“wires”:[]}]

1

你可以⾃⼰来试⼀下除法该怎么应⽤,将计算的代码分别修改并观察结果。

vartemp=d%100;

vartemp=d/100;

1

2

5.3.2使⽤数组进⾏数据的截取与组装

通常,在实际通信的时候不会只传递⼀个数组,信息的传递依赖于数组,数组中不同位置的数字也会有不同的含义,例如,第⼀个数字

表⽰ID,第⼆个数字表⽰数组长度,第三个数字表⽰温度等等,⼀般会有⼀个通信协议来规定。所以,如何取出有⽤的数据,或者按要求把

数据进⾏组装很重要。

现在,假如收到了⼀串数据,数据共16位,我们只⽤到后8位,前边的8位都不要了,如何来操作?

这⾥写图⽚描述

通过分析可以得知:

ARR2[0]=ARR1[8];

ARR2[1]=ARR1[9];

……

ARR2[7]=ARR1[15];

1

2

3

4

但是写代码的时候⼀般不会这么复制粘贴。这是循环操作,⽤for语句可以增加效率。

vartemp=newBuffer([0,0,0,0,0,0,0,0]);

for(vari=0;i<8;i++)

temp[i]=d[i+8];

d=temp;

returnmsg;

1

2

3

4

5

我们新建⼀个temp数组,有8个元素并初始化为0;

通过for循环,把d[i+8]的值赋给temp[i],i可以是0到7。

然后板temp作为msg的payload返回。

接下来添加inject与debug节点搭⼀个测试环境。Inject节点内容为数组。

这⾥写图⽚描述

函数节点内容

这⾥写图⽚描述

整个流程如下

这⾥写图⽚描述

[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“数组输

⼊”,“payload”:"

[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]",“payloadType”:“bin”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0

.1,“x”:140,“y”:180,“wires”:[[“37f18063.f0bdd”]]},

{“id”:“65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,

“console”:fal,“tostatus”:fal,“complete”:“fal”,“x”:490,“y”:180,“wires”:[]},

{“id”:“37f18063.f0bdd”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“数据截断”,“func”:“vartemp

=newBuffer([0,0,0,0,0,0,0,0]);nfor(vari=0;i<8;i++)ntemp[i]=d[i+8];d=temp;nreturn

msg;n”,“outputs”:1,“noerr”:0,“x”:300,“y”:180,“wires”:[[“65b”]]}]

1

部署并观察调试窗⼝如下

这⾥写图⽚描述

说明经过函数节点以后,我们成功截取了数组的后8位。

接下来进⾏数据的组装。需求是,我们的原始数据是8位的,通信协议要求的数据是16位的,我们要把原始数据放在通信数据的后8

位。逻辑跟刚刚的组装正好相反。

这⾥写图⽚描述

以下是函数节点的代码

vartemp=newBuffer([170,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0]);

for(vari=0;i<8;i++)

temp[8+i]=d[i];

d=temp;

returnmsg;

1

2

3

4

5

Inject节点的设置与现象,就请你⾃⾏导⼊流来观察吧。

[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“数组输

⼊”,“payload”:"

[0,1,2,3,4,5,6,7]",“payloadType”:“bin”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:140,“y”:180,

“wires”:[[“37f18063.f0bdd”]]},

{“id”:“65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,

“console”:fal,“tostatus”:fal,“complete”:“fal”,“x”:490,“y”:180,“wires”:[]},

{“id”:“37f18063.f0bdd”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“数据截断”,“func”:“vartemp

=newBuffer([170,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0]);nfor(vari=0;i<8;i++)ntemp[8+i]=d[i];d=

temp;nreturnmsg;n”,“outputs”:1,“noerr”:0,“x”:300,“y”:180,“wires”:[[“65b”]]}]

1

5.3.3模拟温度数值的计算

由于通信⽅式的限制,数据在发送时,常常要转换为8位的字符来发送。在数字电路⾥,只有⾼电平和低电平两种情况,所以数据在发

送时,就只能使⽤1和0个数字。这个1或0,称之为1位。通常,8位可以传输⼀个字符。2的8次⽅是256,所以⼩于256的数字,可以⽤

8位来传输。⽽⼤于或等于256的数字,就要分成2个8位传输了。另外,8位的数据可以⽤两个⼗六进制的数来表⽰,⽐如01011010可

以表⽰为0x5a,所以通常会⽤⼗六进制来表⽰通信协议中的数。

例如,我们现在想传输⼗进制的数字14859,⼤于256,所以要分包传送。⼗进制转化为⼆进制是1011,在通

过硬件发送数据时,如果不考虑校验或者起始位以及⾼位还是地位在前,就只考虑数字的发送,那么总线上的电平可能是低低⾼⾼,⾼低⾼

低,低低低低,⾼低⾼⾼。把这个数字写成⼗六进制,是0x3a与0x0b,或0x3a0b,0x⽤来表⽰这是个⼗六进制的数字。0x3049可以通

过这种⽅式换算成10进制:数字拆成单个字符来分析,a到f的数对应10到15,在第⼏位上,就乘以⼏个16。0x3a0b=

3×16×16×16+10×16×16+11=14859。或者直接使⽤16进制进⾏计算,0x3a0b=0x3a×256+0x0b

当然,通信协议是可以进⾏特殊的规定,例如表⽰4位的温度,34.56°C,要通过⼗六进制的数字进⾏分包发送,就是

0Xd80/100。我们现在规定,⼗六进制的温度⾼位×256+低位=温度×100。接下来尝试解析温度的数据。

我们使⽤inject节点输⼊数组[0xd,0x80],由于inject节点⾥不⽀持直接输⼊⼗六进制的数字,所以输⼊[13,128]。这两个数组的值是

⼀样的。

这⾥写图⽚描述

函数节点进⾏如下修改

这⾥写图⽚描述

连线并部署,然后点击inject节点的输⼊按钮,可以看到调试窗⼝输出的正是我们期望的结果:34.56。

这⾥写图⽚描述

代码如下:

[{“id”:“d5052172.91827”,“type”:“inject”,“z”:“a1f259d6.8791a8”,“name”:"",“topic”:“数组输

⼊”,“payload”:"

[13,128]",“payloadType”:“bin”,“repeat”:"",“crontab”:"",“once”:fal,“onceDelay”:0.1,“x”:140,“y”:180,“wires

”:[[“37f18063.f0bdd”]]},

{“id”:“65b”,“type”:“debug”,“z”:“a1f259d6.8791a8”,“name”:"",“active”:true,“tosidebar”:true,

“console”:fal,“tostatus”:fal,“complete”:“fal”,“x”:490,“y”:180,“wires”:[]},

{“id”:“37f18063.f0bdd”,“type”:“function”,“z”:“a1f259d6.8791a8”,“name”:“温度计算”,“func”:“vartemp

=(d[0]*256+d[1])/100;d=temp;nreturn

msg;n”,“outputs”:1,“noerr”:0,“x”:300,“y”:180,“wires”:[[“65b”]]}]

1

可以再添加⼀个节点,把数字34.56转为字符34.56摄⽒度。

这⾥写图⽚描述

这⾥写图⽚描述

本文发布于:2022-12-31 21:33:43,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/67956.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:稻叶浩志
下一篇:the trax
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图