现场总线第讲NeuronC语言与IO对象.ppt
现场总线控制系统,第3讲 Neuron C 语言与I/O对象,信息学院自动化系 凌志浩,内容简介1 Neuron C 简介2 Neuron C 编程及技巧3 节点间通信3.1 网络变量3.2 显示报文4 输入输出对象,1 Neuron C 简介,Neuron芯片的应用程序是用Neuron C编写的。Neuron C是建立在ANSI C的基础上的,与之相比有如下三方面扩展功能:(1)一种新的语句类型when,引入事件并定义任务事件的执行顺序。(2)新增加了37种数据类型,34种输入/输出对象,2个定时器/计数器对象,大大简化了设备控制器的用法。(3)网络变量的内部消息传送机制和其他消息处理机制。它是将程序样例建立在事件上的。也即应用程序是被发生在网络当中或指定设备上的事件所触发的。因此网络自己是被事件驱动的。,1.1 对ANSI C 的扩展包括,(1)一个内部多任务调度程序,它允许程序员以自然的方式描述事件驱动的任务,同时控制这些任务的优先级的执行。(2)将I/O对象直接映射到处理器的I/O能力。(3)网络变量对象定义:提供一种简单的实现节点之间数据共享的方法。(4)when语句:引入事件并定义这些事件所对应的任务。(5)显式消息传递(explicit message):用于直接对LonTalk协议的底层进行访问。(6)秒及毫秒级软件定时器对象。(7)函数库:当调用时,可以执行事件检查、管理输入/输出、网上发送或接收消息以及控制Neuron芯片的各种功能。(8)Neuron C中有三个ANSI包含文件:、。,1.2 Neuron C 支持的变量的类型,(1)整型(整型常数或整型变量)int、short int、long int、unsinged int、signed(可省略)int(2)字符型(字符型常数或字符型变量)unsigned char(8位)、signed char(8位)(3)typedef enum FALSE、TRUE boolean(4)其他,1.3 Neuron C 变量定义,(1)Neuron C和ANSI C支持的变量定义如下简单的数据类型 int a,b,c;char a;数据类型 typedef unsigned long ULONG;枚举 enum hueRED,GREEN,BLUE 指针 char*p;函数 int f(int a,int b)数组 int a4 结构和共用体 struct char name10;int age;char addr10;,(2)Neuron C中附加定义的对象,I/O对象:IO_0 output bit alarm 定时器:mtimer led_on_timer 网络变量:network input int net_is_car 消息标签:msg_tag command,1.4 编译指令,NEURON C允许通过#pragma编译指令进行编译器扩充。#pragma可用来设置一个Neuron 芯片的系统资源以及节点参数,诸如缓存器数及其大小,接收事务数等。也可用于对特定的Neuron芯片参数进行控制,这些指令可在源文件的任何位置出现。例:#pragma enable_io_pull_ups 可使IO4-IO7的上拉使能,2 Neuron C 编程及技巧,2.1 调度程序 Neuron 芯片的任务调度是由事件驱动的:当一个给定的条件判断为“真”时,与该事件有关的代码被执行(称为任务被执行)。调度程序允许定义任务,该任务作为特定事件的结果而被运行,如:输入管脚的改变、接收一个网络变量的新值、或定时器溢出等。也可以指定某些任务是具有优先级的任务,以便能得到优先服务。,(1)when语句,事件由when语句来定义,when语句包含一个表达式,当表达式为真时,表达式后面的代码段被执行。例:when(timer_expires(led_timer)/当定时器溢出时执行下列任务 io_out(io_led,OFF);在任务执行后,时间溢出事件被清除。当led_timer再次溢出,when子句判断为真,任务又将执行;否则,任务被忽略。,A.多个when子句可与一个任务发生关联,when(reset)when(io_change(io_switch)when(!timer_expires)when(x=3).,B.when子句不能嵌套,如下为错误:when(io_changes(io_switch)when(x=3).,()when子句语法,priority prompt_safe when(event)taskpriority(优先级):可选择项 prompt_safe:可选项,如使用即便应用程序处于占先模式,仍然允许调度程序执行相关的when任务。event:可是预定的事件也可是有效的 Neuron C 表达式。task:是Neuron 的复合语句,任务同void函数体等同,也即它不能返回一个值.,()when语句中的事件类型,分为两种:预定义事件和用户定义事件预定义事件:使用编译器内部固有的关键字,包括输入引脚状态变化、网络变量修改、定时器溢出以及消息的接收等。用户定义事件:可以是任何有效的Neuron C表达式。例:when(msg_arrives)/正确 when(online)/正确when(msg_arrives&flag=TURE)/正确,()when语句的调度,调度程序对一组when子句的判断过程是一个循环往复的过程,每一个when语句都由调度程序检测,如果为真,则与其相关联的任务就被执行。如果when语句为假(FALSE),调度程序将继续检查后面的when语句,在检查完最后一个when语句后,调度程序返回顶部重复执行上述过程。例如:(其中只有为真)when()A when()B when()C when()D,()优先级when子句,如when子句选用priority关键字,相比无优先级的when子句,调度程序对具有优先级的when子句的判断次数要频繁的多。优先级when语句在每次调度程序运行时以指定的顺序被检查。如果任何优先级when语句被检测为真,则与它相对应的任务就被执行,然后调度程序又重新回到优先级 when语句队列头,从头开始检测优先级when语句。使用优先级when语句必须仔细考虑。因为优先级when语句太多的话,将使无优先级的when语句根本没机会执行。如果一个优先级when语句在大部分时间里都为真,则它将独占处理器时间。,()预定义事件关键字,flush_completes、offline、online、wink、io_changes、io_in_ready、io_out_ready、reset、timer_expires、io_update_occurs、msg_arrives、msg_completes、nv_update_fails、nv_update_succeeds等等。预定义事件还可以作为子表达式放置在if、while、for语句的控制表达式中,这种方法称为直接事件处理。例:mtimer t;when(event)if(timer_expires(t)io_out(io_led,OFF);,2.2 定时器,Neuron 可以使用两种类型的软件定时器对象:毫秒定时器和秒定时器。毫秒定时器提供一个计时范围为164000毫秒的定时器。秒定时器提供一个计时范围为 165535秒的定时器。它们和Neuron芯片上两个硬件定时器计时器无关,由网络处理器实现(15个)。,()定时器的定义,mtimer repeating timer-name=initial-value 毫秒定时器 stimer repeating timer-name=initial-value 秒定时器repeating:为可选项,如果定时器溢出,定时器将自动开始重新计时。使用该选项,即使应用不能立即响应该终止事件,精确的时间间隔也能够被保留。timer-name:为定时器指定的名字init-value:为可选项,指定当加电或者复位时赋给定时器的值。如果不提供该初始值,定时器的值被置为0。,例,stimer led_timer;/定义秒定时器led_timer when(reset)led_timer=5;when(t=50)led_timer=0;/关闭秒定时器,(2)时间溢出事件,语法:timer_expires(定时器名)定时器名:是可选项,由它来指定所要检查的具体的定时器。如没有该选项,该事件是一个未加限定的timer_expires事件。它与其它预定义事件不同的是,其它的某个挂起事件只为真一次,而对未加限定的timer_expires事件,只要任何一个定时器已经终止,未加限定的timer_expires将一直保持为真。该事件只有当检测到特定的定时器终止事件时才能被清除stimer led_timer;when(timer_expires(led_timer)io_out(io_led,OFF);,如果程序中有多个定时器,对每个具体的定时器都要作检查,以便这个终止事件被清除。例如:mtimer x;mtimer y;mtimer z;when(timer_expires(x)when(timer_expires(y)when(timer_expires(z),另外也可采用如下的方法:when(timer_expires)if(timer_expires(x)else if(timer_expires(y)else if(timer_expires(z).,2.3 输入输出,对未定义的I/O引脚也就是不用的引脚,默认为无效状态,即高阻状态。如果引脚不用,应设计上拉电阻,对IO4IO7可使用enable_io_pullups编译指令,加上软件实现的上拉电阻。为避免使用上拉电阻,可将不用的管脚定义为输出管脚。为实现I/O,可使用内嵌的I/O函数:io_out()、io_in()、io_select()、io_select_dirction()、io_change_init()、io_set_clock()等。,(1)I/O对象的定义,说明一个I/O对象,完成了两件事:1在哪个或哪几个管脚上将实现什么类型的I/O操作。2 将I/O对象的名字和硬件连在一起。语法:pin type option io-object-name;pin:IO0IO10中的一个,同一个引脚可以出现在多个 I/O对象定义中 type:I/O对象类型 option:是可选的I/O参数,不同I/O对象有不同的选项,(2)定义I/O对象的指导原则,(1)最多定义16个I/O对象(2)Neurowire、I2C、磁卡、磁迹1以及串行I/O对象是互斥的。在一个程序中可以说明一个或多个该组中的某一种I/O对象。(3)定时器/计数器对象定义了的引脚不能再定义 为移位I/O对象。(4)定时器/计数器1可以有多到4个的输入对象供选择(多路复用输入对象)。(5)并行和muxbus I/O对象要求使用所有的I/O管脚,任何一个这种类型的I/O对象被说明后,就不能再说明其它I/O对象类型。,(3)I/O对象的重叠使用,可能同一引脚要定义为多种I/O对象例:IO_4 input nibble io_all_points;IO_4 input bit io_point_1;IO_5 input bit io_point_2;IO_6 input bit io_point_3;IO_7 input bit io_point_4;允许一个程序在同一个操作中读相邻的4个引脚或分别读每个引脚(比特I/O)。,(4)I/O函数及事件,输入对象的访问可以采用两种方法:1显式的调用io_in()函数。2.判断与该对象有关的事件 输出对象的访问方法:调用io_out()函数,内嵌的I/O函数,io_in()return-value=io_in(io-object-name,args)/从I/O对象读取数据 io_out()当信号要发送到某个设备时,使用io_out(io-object-name,output-value,agrs)/向一个I/O对象写数据,与I/O有关的事件,代替显式调用io_in()函数的方法 使用预定义事件:io_changes()io_update_occurs()仅用于输入对象,在检测时,io_update_occurs和io_changes事件都隐含的执行io_in()函数,该函数包括对象的输入值。任务可以通过使用关键字input_value访问这个输入值。,1)io_changes事件,语法:io_changes(io-object-name)by|to expr 当从I/O对象读到的值改变时,该事件判断为真。值的改变有三种类型:改变为某指定的值(to)至少改变一指定的量(by 绝对值)任意改变(无限制)参考值是上次事件判断为真时读取的值,对于无限制的io_changes事件,如果当前值与引用值不同时就意味着发生了一个状态的改变.对于定时器/计数器输入设备有一个新的值并且该值与以前的值不同时,io_changes事件才发生。,IO_0 input bit push_button;when(io_changes(push_button)to 0)IO_7 input pulsecount total_ticks;when(io_changes(total_ticks)by 100),例,对于定时器/计数器对象,io_changes事件发生于:双斜率输入:转换完成时事件发生定期及周期输入:如果测量时间与上次测量时间相比已发生改变时事件发生。脉冲计数输入:如果脉冲计数的值与上次计数相比已发生改变,则事件发生。,2)io_update_occurs事件,语法:io_update_occurs(io-object-name)当输入对象(io-object-name)读取的值发生改变时,io_update_occurs事件为真。该事件只能用在某些定时器/计数器的输入对象中。对事件的定时依赖于输入对象的类型。,例如,双斜率输入:转换完成且值发生变化时,该事件发生 定期及周期输入:事件发生在定时度量结束时脉冲计数输入:每0.839秒事件发生一次,即当一个新的脉冲计数值有效时。,3)input_value变量,long int类型,内嵌变量,可象任何其他的C变量一样使用.例:when(io_changes(io_switch_in)nv_switch_state=(input_value=SWITCH_ON)?ST_ON:ST_OFF;例中可以根据 input_value的值设置网络变量nv_switch_state的值。input_value 只有在io_changes和io_update_occurs事件发生后才有效。有两种方法可以帮助你确定输入值是否为新值。,3 节点间通信,3.1 网络变量概述(1)可定义为输入或输出(2)基于Neuron节点定义62个,基于非Neuron节点可定义4096个(3)实现节点间通信、数据共享(4)由LonTalk协议实现,被称为隐式消息(5)类型相同的网络变量才能建立I/O连接(6)不用考虑消息的打包、发送及接收,简化编程,缩短开发周期。,3.1.1 网络变量的说明,network input|output type identifier=initial-value;network input|output type identifier array-bound=initializer-list,input、output:输出/输入网络变量 identifier:用户定义的网络变量名 初值:(initial-value)指定一个初值,说明,Type:网络变量的数据类型,(1)signedlong int(2)unsigned long int(3)signedshort int(4)unsigned short int(5)signed char(6)unsinged char(7)枚举(9)标准网络变量(SNVT)(8)以上类型构成的结构体、数组(最多62个元素)SNVT:是一组与数据的单位(如摄氏、伏、米等)相关联的预定义网络变量类型,同时SNVT 还定义了网络变量值的范围以及类型标识号ID。目前,已定义了的标准网络变量有255种。,例,network input SNVT_temp temp_set_point;network output SNVT_lev_disc primary_heater;network output int current_temp;network output boolean bind_info(priority)fire_aalarm;network output boolean bind_info priority(nonconfig)fire_aalarm;,3.1.2 网络变量的连接,网络变量的连接是独立于节点上的Neuron C 应用的。网络变量的连接由网络管理工具中称为连接器(Binder)的部分来建立。Binder是LonBuilder网络管理程序、LonMaker安装工具或其它网络管理工具的一部分。连接器首先找共享共同网络变量的所有节点。然后对每个网络变量,连接器给所有相应的节点分配地址,以保证信息从正确的地方来,到正确的地方去。is_bound()函数用来确定网络变量是否连接到其它任何的网络变量。,3.1.3 网络变量事件,有4个和网络变量相关的预定义的事件:nv_update_completes(network-var)nv_update_fails(network-var)nv_update_occurs(network-var)只用于输入网络变量 nv_update_succeeds(network-var)其它三个事件,当输出网络变量被更新时,用于输出网络变量,当输入网络变量被轮循时,应用于输入网络变量。network-var:可用网络变量名、网络变量数组名或网络变量数组元素来限定例如:network_varindex,如事件被一个数组名限定,事件将对每个数组元素发生一次。,nv_update_occurs(network-var)事件,network-var:如果省略,事件对任何网络变量更新都为真。当输入网络变量收到一个新值,nv_update_occurs事件为真。例 network input SNVT_temp tempSetPoint;when(nv_update_occurs(tempSetPoint)primaryHeader=(curTemptempSetPoint)?ST_ON:ST_OFF;,nv_update_completes(network-var)事件,network-var:可是网络变量名、网络变量数组名或网络变量数组元素,也可没有。用于:(1)输出网络变量更新完成(2)被轮循的输入网络变量操作完成 无论成功还是失败,只要完成该事件都判断为真。例:network output int humidity;humidity=32;when(nv_update_completes(humidity),nv_update_fails和nv_update_succeeds,nv_update_fails(network-var)当一个网络变量更新或轮循失败后,nv_update_fails事件为真。如果没有为该事件指定相应的网络变量,那么该节点上任何网络变量的更新或轮循失败该事件都检测为真。如果多个网络变量被指定,则每一个网络变量更新或轮循失败都使该事件为真。nv_update_succeeds(network-var)同样当输出网络变量更新已被成功地发送或来自所有写出节点的轮循都已被接收到,nv_update_succeeds事件为真。,三个节点网络示意图,开关节点,nv_switch_state,nv_lamp_state,电灯节点,电灯节点,nv_lamp_state,一个输出网络变量控制两个输入网络变量,开关节点,#pragma enable_io_pullups;#include network output SNVT_lev_disc nv_switch_state=ST_OFF;#define BUTTON_DOWN 1#define BUTTON_UP 0IO_4 input bit ioButton=BUTTON_UP;/I/O任务When(io_changes(ioButton)to BUTTON_DOWN)nv_switch_state=(nv_switch_state!=ST_OFF)?ST_OFF:ST_ON;,电灯节点,network input SNVT_lev_disc nv_lamp_state=ST_OFF;#define LED_ON 1#define LED_OFF 0IO_0 output bit ioLED=LED_OFF;/修改任务-修改电灯的状态,用网络变量的值作为电灯的新状态when(nv_update_occurs(nv_lamp_state)io_out(ioLED,(nv_lamp_state!=ST_OFF)?LED_ON:LED_OFF);,3.2 显式报文 3.2.1 显式报文与网络变量的比较,(1)显式报文有一个可变大小的数据域,一个给定的网络变量数据域的大小是一个常数。(2)显式报文提供了请求/响应机制,使得在一个节点上的应用可以引起另一个节点的应用来响应它.(3)显式报文使用的E2PROM表空间比网络变量少,用的代码空间比网络变量要多.(4)显式报文是从一个节点向另一个节点传送信息的更复杂的方法。程序员必须显示地构造、发送和接收显示报文。而报文的属性例如服务类型、认证和优先级是在编译时定义的,在节点安装后是不能通过网络管理工具配置的。,3.2.2 显式报文,操作步骤 Neuron C 功能(1)构造一个报文 msg_out对象(2)发送一个报文 msg_send()函数 msg_cancel()函数(3)接收一个报文 msg_arrives 事件 msg_receive函数 msg_in 对象(4)发送报文后的确认服务 msg_completes 事件 msg_succeeds 事件 msg_fails 事件,3.2.3 构造一个报文,报文对象名字:msg_out 发送:使用msg_send()函数注意:在同一时间,只有一个输出报文(或响应)和一个输入报文(或响应)是可用的。程序不能同时建造两个报文,也不能同时发送它们。并且两个输入报文不能同时被分析。,(1)msg_out 对象定义,structboolean priority_on;/优先级消息TRUE,缺省为FALSEmsg_tag tag;/报文标签该域是必须的int code;/消息代码,为数字报文码,该域必须的int dataMAXDATA;/报文包含的数据(缺省没有),/该域是可选的 建议MAXDATA228boolean authenticated;/报文是证实的为TRUE,缺省为FALSE service_type service;/服务类型(缺省为确认服务)msg_out_addr dest_addr;msg_out;,typedef enumACKD=0,UNACKD_RPT=1,UNACKD=2,REQUSET=3service_type;service:为下列服务之一(1)ACKD(缺省值)-确认服务(2)UNACKD-非确认服务(3)UNACKD_RPT-非确认重发(报文发送多次)(4)REQUEST-请求/响应服务。当报文使用该服务被发送,则接收节点返回一个响应给发送节点,发送节点处理这个响应。dest_addr:在msg_out对象中是一个可选域,如果用显示地址发送报文,则应用程序给该域赋值。,(2)发送报文,void msg_send(void);/其用msg_out对象发送报文例如:msg_tag motor;#define MOTOR_ON 0#define ON_FULL 100when(io_changes(switch1)to ON)/给电动机发送一个报文 msg_out.tag=motor;msg_out.code=MOTOR_ON;/消息代码是0 msg_out.data0=ON_FULL;msg_send();,void msg_cancel(void)该函数取消为msg_out对象构造的报文并释放分配给它的缓冲区,允许构造另外的报文,它无参数、无返回值。如果构造了报文还没有发送出去,在任务退出前报文被自动取消。这个函数用来取消优先级和非优先级报文。(3)接收一个报文 程序通常通过预定义事件when(msg_arrives)接收一个报文。msg_receive()函数也可用来接收一个消息。收到的消息可在msg_in对象中得到。,取消发送,例,If(offline()/被请求脱机 msg_cancel();else msg_send();,struct intcode;/报文码intlen;/报文数据的长度int dataMAXDATA;/报文数据booleanauthenticated;/如认证通过为真 service_typeservice;msg_in_addraddr;booleanduplicate;/接收消息是一个重发的请求消息 unsigned rcvtx;/接收事务 ID,在节点的事务数据库中使用它。msg_in;,msg_arrives 事件,msg_arrives(message-code)事件message-code:是一个可选的整数报文代码。如果省略这个参数,收到任何报文,事件都为真。当报文到达时,msg_arrives事件为真。这个事件可以由报文的发送者指定一个限定的报文码。这时只有当包含指定码的报文到达时,事件才为真。当既使用非限定的msg_arrives事件又使用限定的msg_arrives事件时,则必须指定#pragma scheduler_reset编译指令,以便在所有的限定事件when语句之后处理非限定事件when语句。,例:#pragma scheduler_reset when(msg_arrives(1)io_out(sprinkler,ON);when(msg_arrives(2)io_out(sprinkler,OFF);when(msg_arrives)/处理意料之外的消息/什么也不做,只是仍掉它 注意:使用msg_arrives事件接收消息的程序,应该考虑到接收意料之外的消息。例如某个节点的服务引脚向所有节点发送,但只有网络管理工具对该消息有兴趣并处理该消息。否则未处理的消息永远停留在队列前面,造成阻塞。,boolean msg_receive(void)函数,msg_receive()函数接收一个消息到msg_in对象,如果收到一个新的报文,函数返回真,否则返回假。(1)如果在报文队列中没有报文,该函数并不等待。(2)如果在一个任务中收到多个报文,正如在旁路模式,它可能需要使用这个函数。(3)如果收到的是已接收的消息,先接收的消息将被删掉以释放它所占的缓存空间。(4)该函数不能用在一个when子句表达式中。例:if(msg_receive().msg_free();,开关、灯节点,开关程序,#define LAMP_ON 1#define LAMP_OFF 2#define OFF 0#define ON 1IO_4 input bit io_switch_in;msg_tag TAG_OUT;/声明消息标签when(reset)io_change_init(io_switch_in);when(io_changes(io_switch_in)msg_out.code=(input_value=ON)?LAMP_ON:LAMP_OFF;msg_out.tag=TAG_OUT;msg_send();,灯程序,#define LAMP_ON 1#define LAMP_OFF 2#define OFF 0#define ON 1IO_0 output bit io_lamp_control;when(msg_arrives)switch(msg_in.code)case LAMP_ON:io_out(io_lamp_control,ON);break;case LAMP_OFF:io_out(io_lamp_control,OFF);break;,4.Neuron 芯片应用I/O对象,4.1 Neuron芯片I/O对象类型 I/O对象简单的讲就是一个定义的输入或输出波形,也可看成是存放在ROM 中供用户程序访问的已编写好的固件例程,如同Windows编程中的各种控件,可直接使用。用户可通过io_out()和io_in()系统调用来访问这些I/O对象,并在程序执行期间完成输入/输出操作。,Neuron芯片通过11只引脚(IO0-IO10)与应用指定的外部硬件相连,称这11只引脚为应用I/O。这些引脚可以以最少的外接电路实现多种灵活的输入输出功能。其中IO4-IO7可通过编程使用芯片内部的上拉电阻、IO0-IO3有高电流吸收能力、IO0IO7具有低电平检测锁存器。IO0-IO10有TTL电平输入。可以定义一个或多个引脚作为I/O对象。Neuron芯片共有34种不同的I/O对象,分为以下四类:,应用I/O,(1)直接I/O对象:基于I/O管脚的逻辑电平,(2)并行双向I/O对象,并行I/O对象用于高速双向输入、输出数据,当定义并行I/O对象时,必须定义用全部的I/O对象引脚。,(3)串行I/O对象 用来实现在一个管脚上串行的数据传输,(4)定时器/计数器 I/O 对象,4.2 I/O对象介绍 4.2.1 直接I/O对象,(1)比特I/O对象(bit)这种I/O对象类型用于读或控制单个管脚的逻辑状态,IO0IO10都可分别配置成单个的比特输入或输出端口,0相当于低电平而1相当于高电平。输入信号电平是TTL电平,比特输入可从外接的逻辑电路例如触点式表决器以及类似的电路中读取与TTL电平兼容的逻辑信号。比特输出信号电平是CMOS 电平,可驱动外接的与CMOS电平兼容的逻辑电路。如开关晶体管、灯等。也可驱动较高电流的外部设备如步进电机等。程序可动态的改变端口的输入、输出方向。IO0-IO3 具有较高的高电流(20mA)吸收能力,使得它们能直接驱动多个I/O设备。IO4IO7具有可编程上拉电阻。,比特对象定义,pin input bit o_object_name;pin output bit o_object_name(=initial_output_level);initial_output_level:初始状态,缺省为0IO_1 input bit io_switch_1;unsigned int switch_on_off;.when(io_changes(io_swtich_1)switch_on_off=input_value;,IO_2 output bit io_led;unsigned int led_on_off;.when()Io_out(io_led,led_on_off);,(2)电平检测输入对象(leveldetect),IO0IO7可分别配置为电平检测输入端口,用于检测某一输入端输入的逻辑为“0”的电平。它能锁存输入引脚的负跳变,即使该负脉冲很窄,对于10Mhz的输入时钟每200ns输入状态在硬件上被锁存一次(时间间隔与输入时钟速度成比例),可捕获任何电平输入。该事件由值代表,当读取时被清为零。只要输入管脚电平停留在逻辑,每个io_in()调用将返回值.用于俘获短持续时间的事件。,对象定义,pininput leveldetect io-name;例:IO_5 input leveldetect io_edge_trigger;when(io_changes(io_edge_trigger)to 1)./任务将在每次引脚IO_5变为电平时执行,4.2.2 串行I/O对象(1)同步串行I/O对象(Neurowire),Neurowire可实现与外部器件的同步全双工串行数据格式的传送,它可作为主控收发器(提供同步时钟)或被控收发器(接收同步时钟)。只要遵循SPI或National Semiconductors Microwire TM的接口器件,都可以作为Neurowire的外接器件。例如A/D、D/A以及显示驱动器等。,1)引脚配置如下:,主控方式 被控方式,语法:,IO_8 neurowire masterslaveselect(pin)timeout(pin)kbaud(const-expr)clockedge(+/-)io-name;(1)IO_8:必须指定IO_8,片选IO0-IO7。(2)master:由IO8提供时钟;slave:IO8为输入管脚,最大输入时钟为18kbps,占空比为50/50,此时Neuron输入时钟为10MHz。速度与输入时钟成正比。(3)select:为 master指定片选管脚(IO0IO7)。数据输出前,片选为低电平,数据输出后为高电平。(4)timeout:为 slave 指定一个超时管脚(IO0IO7)每当Neuron芯片等待时钟的上升沿或下降沿时,将检查该管脚的逻辑电平。如果检测到逻辑电平1,则传输被终止。这样就允许使用外部超时信号或内部生成的超时信号来限制传输的持续时间。(5)kbaud为master指定比特率,const-expr的结果可以为1,10,或20。对于10Mhz的Neuron芯片输入时钟缺省为20kbps。不能用于 Slave。(6)clockedge(+/-):时钟信号的极性,缺省为上升沿。,(2)RS232半双工异步串行I/O对象(Serial),用于异步串行数据格式数据传输,实现半双工的EIA-232(RS232)通信,传输格式为:1位始位,8位数据位,1位停止位。输入串行I/O对象将等待被接收的数据帧的真正的开始,直到已经等待了接收20个字符所需要的时间结束,如果在这段时间内没有输入发生则返回0。当已收到全部的字节数或已超过接收20个字符所需要的时间但仍未接收到数据时,输入终止。输入串行I/O对象将在无效停止位或奇偶校验位时停止接收数据。在波特率为2400bps,输入超时为83ms。,串行输入:必须为IO8 串行输出:必须为IO10,串行输入模式只提供1位缓存和4800bps的最大速率,一次最多可传送255个字节的数据。当输入时钟为10Mhz时,两引脚的输入输出比特速率(baud)可分别指定为600、1200、2400、4800b/s,数据速率与输入时钟的值成比例。主要用于挂接终端、Modem以及计算机的串行接口等,实现Neuron 芯片与这类设备器件之间的半双工异步串行通信(RS232标准)。unsigned int coutn,input_buffercount;io_in(io-name,input_buffer,count);io_out(io-name,output_buffer,count);,例:异步串行I/O对象的使用,(1)串行输入 IO_8 input serial io_keyboard;/定义异步串行输入对象 char in_buffer20;/输入数据的存放缓冲区 unsigned int num_chars;when()num_chars=io_in(io_keyboard,in_buffer,20);/接收20个字符存放在in_buffer中,IO_10 output serial io_crt_screen;/定义异步串行输出对象 char out_buffer20;/输出数据存放缓冲区 when(.)io_out(io_crt_screen,out_buffer,20);/将out_buff