Written by
developer on 2007/09/30 in
Arduino -
4 Comments按原文進(jìn)行了多次實(shí)驗都沒(méi)成為功,經(jīng)反復測試和修改,終于大功告成為,現在把需要修改的地方著(zhù)重標出
在A(yíng)rduino與Flash之間實(shí)現交互最重要的一點(diǎn)是如何為兩者建立起有效的通信途徑。出于安全性上的考慮,Flash本身不能直接操作硬件,但它能夠通過(guò)XMLSocket,并按照一定的約定同與外界實(shí)現通信:
通過(guò)全雙工的TCP/IP流套按字(Socket)發(fā)送XML消息
只能連接到端口號大于等于1024的TCP端口
每個(gè)XML消息都是一個(gè)以零(0)結束的XML文檔
發(fā)送和接收XML消息的數量沒(méi)有限制
雖然有如此多的限制,但它畢竟提供了一條與外界通信的途徑,這也是我們能在Flash和Arduino之間實(shí)現交互的基石。具體的做法是運行一個(gè)串口代理(Serial Proxy)程序,這個(gè)程序一方面直接對串口硬件進(jìn)行操作,另一方面又和Flash通過(guò)Socket進(jìn)行通信。在
Arduino網(wǎng)站上我們可以找到這一串口代理的
Windows版本和
Mac版本。
在運行串口代理之前我們需要對它進(jìn)行相應的配置,也就是編輯serproxy.cfg文件:
newlines_to_nils=truecomm_ports=1comm_baud=19200comm_databits=8comm_stopbits=1comm_parity=nonetimeout=300net_port1=5331按照上面的配置,我使用的是Windows下的COM1,波特率為19200bps,并且是在TCP端口5331上接受來(lái)自Flash的XMLSocket連接。
以上serproxy.cfg文件和我的不大一樣,需要修改一個(gè)重要的地方:以下是我的serproxy.cfg的內容
# Config file for serproxy
# See serproxy's README file for documentation
# Transform newlines coming from the serial port into nils
# true (e.g. if using Flash) or false
newlines_to_nils=true
# Comm ports used
comm_ports=1,2,3,4,5,6
# Default settings
comm_baud=9600 //一定樣認真核對波特率,要與下位程序arduino里的一致,否則會(huì )出現亂碼,自然無(wú)法通訊
comm_databits=8
comm_stopbits=1
comm_parity=none
# Idle time out in seconds
timeout=300
# Port 1 settings (ttyS0)
net_port1=5331
# Port 2 settings (ttyS1)
net_port2=5332
# Port 3 settings (ttyS2)
net_port3=5333
# Port 4 settings (ttyS3)
net_port4=5334
# Port 5 settings (ttyS4)
net_port5=5335
# Port 6 settings (ttyS5)
net_port6=5336
我使用的是Windows下的COM4,波特率為9600bps,并且是在TCP端口5331上接受來(lái)自Flash的XMLSocket連接
有了串口代理的幫助,對于A(yíng)rduino來(lái)講就是通過(guò)串口接受來(lái)自Flash的命令,然后執行相應的操作,或者通過(guò)串口向Flash發(fā)送命令。下面的Arduino工程一方面通過(guò)數字I/O端口13號管腳讀取按鍵的狀態(tài),并在狀態(tài)改變時(shí)通過(guò)串口向Flash發(fā)送按下(switchOn)或者是松開(kāi)(switchOff)的狀態(tài)信息;另一方面則接受Flash通過(guò)串口代理發(fā)送過(guò)來(lái)的命令,并相應點(diǎn)亮連接在數字I/O端口2、3、4或者5號引腳上的發(fā)光二極管。原理圖如下所示:
相應的Arduino工程代碼為:
int activeLED ;int switchState = 0;int lastSwitchState = 0;int switchPin = 13;void setup(){ Serial.begin(9600);//一定要與CFG文件里的設置一樣,要不然不能進(jìn)行通訊,實(shí)際上在出現亂碼時(shí)就是應想到是這個(gè)問(wèn)題 pinMode(switchPin, INPUT); for (int i = 2; i <= 9; i++) { pinMode(i, OUTPUT); }}void loop (){ switchState = digitalRead(switchPin); if (switchState != lastSwitchState) { if (switchState == 1){ sendStringToFlash("switchOn");// 想改為“swith on"中間加一個(gè)空格,可以收到字符,但控制不了按鈕,不知道什么原因,待查 } else if (switchState == 0){ sendStringToFlash("switchOff"); } } lastSwitchState = switchState; // 保證松開(kāi)按鍵后按鈕處于OFF狀態(tài) if(Serial.available() > 0) { activeLED = Serial.read(); //activeLED值在50-53之間 } if(activeLED >= 50 && activeLED <= 57) { int outputPort = activeLED - 48; //保證端口在2-9之間 Serial.print("LED port "); Serial.println(outputPort); if(outputPort >= 2 && outputPort <= 9) { for (int i = 2; i <= 10; i++) { digitalWrite(i,LOW); //把幾個(gè)端口的LED熄滅 } digitalWrite(outputPort, HIGH); } activeLED = 0; } else if (activeLED) { Serial.print("Invalid LED port "); Serial.println(activeLED,BYTE);// 改寫(xiě)為Serial.println(activeLED); } delay(50);}void sendStringToFlash (char *s){ while (*s) { printByte(*s ++); //改寫(xiě)為Serial.write(*s ++);用print是不能發(fā)送字符的 } printByte(0);//改寫(xiě)為 Serial.write((byte)0);}函數sendStringToFlash()被Arduino用來(lái)向Flash發(fā)送數據,其最后一個(gè)字節必須是0,這是由XMLSocket協(xié)議所決定的。arduino 1.0改動(dòng)非常大。。。按照官方文檔介紹,以前最常用的Serial.print(val,BYTE)變?yōu)榱薙erial.write(val)。但是使用中發(fā)現一個(gè)問(wèn)題。。就是Serial.write(val)中。。val你是用3,4,5等都沒(méi)問(wèn)題,就是不能輸入0。。。。。暈了暈了。
那怎么發(fā)送0呢,其實(shí)還是需要把0定義為BYTE才行,但是格式。。和以前不一樣。命令要這樣子寫(xiě):
Serial.write((byte)0);再來(lái)看一下對應的Flash代碼,你可以從這里
下載相應的Flash工程。該工程中包含的Arduino.as提供了對XMLSocket的封裝,而FlashLED.fla正是通過(guò)調用其相應功能,來(lái)實(shí)現同Arduino的通信。
import Arduino;var port:Number = 5331;//改為相應端口,本例中改成5534,即用端口4var a:Arduino = new Arduino(port);以下是本例的ARduino.as文件內容:
mport mx.events.EventDispatcher;
class Arduino extends XMLSocket {
private var _connected :Boolean = false; // is connected?
private var _host :String = "127.0.0.1"; // Host name or IP address
private var _port :Number = 5334//read the config file of the socket server for this one
//EVENT DISPATCH MIXIN
function addEventListener(){}
function removeEventListener(){}
function dispatchEvent(){}
function dispatchQueue(){}
//constructor - provide a port number and a host ip adress
//read the documentation of the SerialProxy to better understandwhat this means
function Arduino(port, host) {
//initialize
super();
mx.events.EventDispatcher.initialize(this);
//trace("** Arduino ** initilizing constructor");
//check if the selected port is correct or set default
if(port == undefined) {
trace("** Arduino ** default port:"+_port+" initialized! to change it use new Arduino(onPortNumber)")
} else if ((_port < 1024) || (_port > 65535)) {
trace("** Arduino ** Port must be from 1024 to 65535 ! read the Flash Documentation and the serProxy config file to better understand")
} else {
_port = port;
}
//check for host or set default
if(host != undefined) {
_host = host;
}
//register and override responder functions
this.onConnect = onConnectToSocket;
this.onClose = onDisconnectSocket;
this.onData = onDataReceived;
//autoconnect
connect();
}
//---------------------------------------
// CONNECT and DISCONNECT + responders
//---------------------------------------
//connect to the XMLsocket
public function connect () {
trace("** Arduino ** Connecting to "+_host+":"+_port+" . . .");
super.connect(_host,_port);
}
//disconnects from the xmlsocket (not Arduino itself)
public function disconnect () {
if (_connected) {
trace("** Arduino ** disconnecting");
this.close()
_connected = false;
}
}
//XMLsocket responders
private function onConnectToSocket (success) {
//trace("** Arduino ** onConnectToSocket");
if (success) {
_connected = true;
//launch event
trace ("** Arduino ** Connection established.")
e_connectToSocket();
} else {
trace ("** Arduino ** Connection failed! you must launch the serialProxy first");|
e_connectToSocketError();
}
}
//XMLsocket responders
private function onDisconnectSocket (success) {
_connected = false;
//trace ("** Arduino ** onDisconnectSocket ** Connection closed by remote host.");
//launch event
e_disconnectSocket()
}
//---------------------------------------
// SEND and receive data from server
//---------------------------------------
//sends data to arduino
public function send(dataStr:String) {
//trace("** Arduino ** send:" + dataStr)
if (_connected) {
if (dataStr.length) {
//trace("** Arduino ** Sending \""+dataStr+"\"");
super.send(dataStr);
}
}
}
//overrides XMLSocket.onData in order to have pure string and not the full XML object
private function onDataReceived (str:String) {
//trace("** Arduino ** onDataReceived str:"+str);
//launch event
e_onReceiveData(str)
}
//---------------------------------------
// EVENTS
//---------------------------------------
private function e_connectToSocket(){
var evt = {target:this, type:"onConnect"};
dispatchEvent(evt);
}
private function e_connectToSocketError(){
var evt = {target:this, type:"onConnectError"};
dispatchEvent(evt);
}
private function e_disconnectSocket(){
var evt = {target:this, type:"onDisconnect"};
dispatchEvent(evt);
}
private function e_onReceiveData (str:String){
var evt = {target:this, type:"onReceiveData"};
evt.data = str;
dispatchEvent(evt);
}
}
上述的代碼創(chuàng )建了相應的Arduino對象,并將其連接端口設置成了5334,這是與串口代理配置文件serproxy.cfg相一致的。
現在我們可以試著(zhù)運行整個(gè)工程了。首先將Arduino工程下載到Arduino模塊中并運行起來(lái),然后啟動(dòng)串口代理serproxy.exe,最后再運行Flash動(dòng)畫(huà)。如果一切正常,在Flash中選中某個(gè)綠色圓形之后,Arduino會(huì )將相應的發(fā)光二極管點(diǎn)亮,此外按鈕按下或者松開(kāi)的狀態(tài)也會(huì )在Flash動(dòng)畫(huà)中立即得到體現。