前回はArduino unoとPi3をどうやってシリアル通信するかついて書きました。今回はRaspberryの中はPythonを使うではなく、Codesysを使って実現しようと思います。
これは今回の構成です:
流れとしてはこんな感じです:
PI3の構成File修正
まずPI3の中にあるFileをいくつ追加・確認する必要があります。
/etc/codesys.cfg
Terminalを開いて、
sudo nano /etc/CODESYSControl.cfg
sudo nano /etc/CODESYSControl.cfg
[SysCom]
Linux.Devicefile=/dev/ttyACM
portnum := COM.SysCom.SYS_COMPORT1
そして保存しCodesysを再起動します。
sudo /etc/init.d/codesyscontrol restart
/boot/config.txt
自分の場合はそれ大丈夫だったですが、以下のPOSTでそのようなことを書いています:
Also, it seems that sometimes the UART is disabled in Kernel
To enable it, edit /boot/config.txt and set enable_uart=1
https://forge.codesys.com/forge/talk/Runtime/thread/87506d2b8e/?limit=25&page=3#7f0d
なのでTerminalを開いて:
sudo nano /boot/config.txt
その構成が入ってるかどうかを確認します:
enable_uart=1
プログラム
これからはプログラムについて説明します。シリアル通信の流れどこのメーカーでも大体同じでCom設定>Com開く>Comからデータ読む>Comからデータ書く>Comを閉じる。
LibraryをImport
必要なのはこの3つのLibraryですね。
- CAA Memory:データ転送のときに使う
https://help.codesys.com/webapp/idx-CAA_Memory-lib;product=CAA_Memory;version=3.5.12.0 - CAA SerialCom:シリアル通信ライブラリ
https://help.codesys.com/webapp/FYUV8d1vA7RWe-7Be7kSnwQQdrM%2Ffld-CAA-SerialCom;product=CAA_SerialCom;version=3.5.9.0 - CAA Types Extern:CAA SerialComを使うときに使用するデータタイプ
https://help.codesys.com/webapp/idx-CAA_Types_Extern-lib;product=CAA_Types_Extern;version=3.5.13.0
COM構成
シリアル通信やったことがある方ならわかりますが、この通信を成立するには最低限以下の6つが必要になります。
- Baud Rate
- Parity
- Stop Bits
- Byte Size
- Binary
- Port
そしてLibrary>CAA SerialCom>Global Variablesを開いていただいて設定のパラメータ番号が書いています。
例えばudiPortは16#1、udiParityは16#3など…でもこれだけでは話になりませんよね。次はどうやってこれらのパラメータを設定するのかを説明します。
ComOpen
こちらはシリアル通信するためにCOMを開くに使うFunction Blockです。
Input | ||
xExecute | Bool | True=Function実行 |
usiListLength | USINT | パラメータリストのサイズ |
pParameterList | CAA.PVOID | udiParameterIdパラメータID、先表示したCAA SerialCom>Global Variables udiValueその設定値 |
Output | ||
xDone | Bool | True=Function実行成功 |
xBusy | Bool | True=Function実行中 |
xError | Bool | True=Functionにエラーがある |
eError | ERROR | エラーID |
hCom | CAA.HANDLE | 開いてたその”COM” |
COMRead
次はこのBlockを使ってシリアルPortからデータを読みます。
Input | ||
xExecute | Bool | True=Function実行 |
xAbort | Bool | True=実行停止 |
udtTimeOut | UDINT | まぁ、Timeoutですね。 |
hCom | CAA.HANDLE | いまシリアル通信で開いてるCOM |
pBuffer | CAA.PVOID | Read Bufferのアドレス |
szBuffer | CAA.SIZE | 書き込まれるバイト数 |
Output | ||
xDone | Bool | True=Function実行成功 |
xBusy | Bool | True=Function実行中 |
xError | Bool | True=Functionにエラーがある |
xAborted | Bool | True=Functionは中止された |
eError | ERROR | エラーID |
szSize | CAA.SIZE | いま読まられたのバイト数 |
ComWrite
そしてこれはシリアル通信の書き込むFunction Blockです。
Input | ||
xExecute | Bool | True=Function実行 |
xAbort | Bool | True=実行停止 |
udtTimeOut | UDINT | まぁ、Timeoutですね。 |
hCom | CAA.HANDLE | いまシリアル通信で開いてるCOM |
pBuffer | CAA.PVOID | Write Bufferのアドレス |
szBuffer | CAA.SIZE | 書き込むのバイト数 |
Output | ||
xDone | Bool | True=Function実行成功 |
xBusy | Bool | True=Function実行中 |
xError | Bool | True=Functionにエラーがある |
xAborted | Bool | True=Functionは中止された |
eError | ERROR | エラーID |
ComClose
最後はComを閉じるのFunction Blockです。
Input | ||
xExecute | Bool | True=Function実行 |
hCom | CAA.HANDLE | いまシリアル通信で開いてるCOM |
Output | ||
xDone | Bool | True=Function実行成功 |
xBusy | Bool | True=Function実行中 |
xError | Bool | True=Functionにエラーがある |
eError | ERROR | エラーID |
MEMMove
BlockmoveのようなFunction Blockですね。MemoryエリアAからMemoryエリアBにX Byte分のデータを転送する。
Input | ||
pSource | Pointer to Byte | 移動元 |
pDestination | Pointer to Byte | 移動先 |
uinumberofbytes | UINT | なんByte分のデータを移動する |
Output | ||
MemMove | Bool | 結果 |
MEMFill
FillBlockのような機能のFunction Blockですね。MemoryエリアBからなんByte分にデータをByte データに入れる。
Input | ||
pMemoryBlock | Pointer to Byte | 移動元 |
uiLength | UINT | 移動先 |
byFillValue | Byte | なんByte分のデータを移動する |
Output | ||
MemMove | Bool | 結果 |
Portの構成設定方法
Function Blockを紹介終わったら、まず実際どうやってPort構成を設定するのかを書きます。
定数定義
aCom1Params : ARRAY [1..7] OF COM.PARAMETER;
設定プログラム
パラメータは相手によって減ったり増やしたりする場合もあると思いますが、その場合配列のaCom1Paramsに長さを調整し、必要なパラメータIDとその値をいれればよいだと思います。だからComOpenのときパラメータのサイズのが必要でしょう?
//Port Number
aCom1Params[1].udiParameterId:=COM.CAA_Parameter_Constants.udiPort;
aCom1Params[1].udiValue:=1;
//BaundRate
aCom1Params[2].udiParameterId:=COM.CAA_Parameter_Constants.udiBaudrate;
aCom1Params[2].udiValue:=9600;
//Parity
aCom1Params[3].udiParameterId:=COM.CAA_Parameter_Constants.udiParity;
aCom1Params[3].udiValue:=INT_TO_UINT(COM.PARITY.NONE);
//StopBits
aCom1Params[4].udiParameterId:=COM.CAA_Parameter_Constants.udiStopBits;
aCom1Params[4].udiValue:=INT_TO_UINT(COM.STOPBIT.ONESTOPBIT);
//TimeOut
aCom1Params[5].udiParameterId:=COM.CAA_Parameter_Constants.udiTimeout;
aCom1Params[5].udiValue:=0;
//ByteSize
aCom1Params[6].udiParameterId:=COM.CAA_Parameter_Constants.udiByteSize;
aCom1Params[6].udiValue:=8;
//Binary Mode
aCom1Params[7].udiParameterId:=COM.CAA_Parameter_Constants.udiBinary;
aCom1Params[7].udiValue:=1;
実装-PI側
Interface
PROGRAM PLC_PRG
VAR
xCom1ReadError :BOOL;
xCom1WriteError :BOOL;
xCom1OpenError :BOOL;
xClearAll :BOOL;
iStep :INT;
aCom1Params : ARRAY [1..7] OF COM.PARAMETER;
hCom :CAA.HANDLE; (* handle of the port*)
comOpen :COM.Open;
comClose :COM.Close;
comWrite :COM.Write;
comRead :COM.Read;
iError :INT;
iState :INT;
bReadBuffer :ARRAY [1..255] OF BYTE; (*Used to read data from the serial port*)
bWriteBuffer :ARRAY [1..255] OF BYTE; (*Used to write data to the serial port*)
szWrite :CAA.SIZE;
sReadText :STRING;
szRead :CAA.SIZE;
uiRead :UINT;
Received :STRING(255);
intReceived :INT;
xReadSuccess :BOOL;
xWriteSuccess :BOOL;
errWrite :INT;
errRead :INT;
sSend :STRING(255); // send message
sStatus :STRING(25); // status message
tTimer :TON;
END_VAR
VAR CONSTANT
iStepInit :INT:=0;
iStepComOpen :INT:=5;
iStepComRead :INT:=10;
iStepComReadOK :INT:=15;
iStepComWrite :INT:=20;
iStepComDelay :INT:=25;
iStepError :INT:=1000;
END_VAR
PROGRAM
Program
IF NOT GVL.init THEN
iStep:=iStepInit;
GVL.init:=TRUE;
END_IF
CASE iStep OF
iStepInit:
xCom1ReadError:=FALSE;
xCom1OpenError:=FALSE;
xCom1WriteError:=FALSE;
iStep:=iStepComOpen;
iStepComOpen:
//Port Number
aCom1Params[1].udiParameterId:=COM.CAA_Parameter_Constants.udiPort;
aCom1Params[1].udiValue:=1;
//BaundRate
aCom1Params[2].udiParameterId:=COM.CAA_Parameter_Constants.udiBaudrate;
aCom1Params[2].udiValue:=9600;
//Parity
aCom1Params[3].udiParameterId:=COM.CAA_Parameter_Constants.udiParity;
aCom1Params[3].udiValue:=INT_TO_UINT(COM.PARITY.NONE);
//StopBits
aCom1Params[4].udiParameterId:=COM.CAA_Parameter_Constants.udiStopBits;
aCom1Params[4].udiValue:=INT_TO_UINT(COM.STOPBIT.ONESTOPBIT);
//TimeOut
aCom1Params[5].udiParameterId:=COM.CAA_Parameter_Constants.udiTimeout;
aCom1Params[5].udiValue:=0;
//ByteSize
aCom1Params[6].udiParameterId:=COM.CAA_Parameter_Constants.udiByteSize;
aCom1Params[6].udiValue:=8;
//Binary Mode
aCom1Params[7].udiParameterId:=COM.CAA_Parameter_Constants.udiBinary;
aCom1Params[7].udiValue:=1;
//Blocks
comOpen(
xExecute:=TRUE
,usiListLength:=UINT_TO_USINT(SIZEOF(aCom1Params)/SIZEOF(COM.PARAMETER))
,pParameterList:=ADR(aCom1Params)
,hCom=>hCom);
//Result
IF comOpen.xDone THEN
comOpen(xExecute:=FALSE);
iStep:=iStepComRead;
ELSIF comOpen.xError THEN
iError:=comOpen.eError;
xCom1OpenError:=TRUE;
iStep:=iStepError;
END_IF;
iStepComRead:
IF xClearAll THEN
xCom1OpenError:=FALSE;
xCom1ReadError:=FALSE;
xCom1WriteError:=FALSE;
END_IF
comRead(xExecute:=TRUE
,hCom:=hCom
,udiTimeOut:=10
,pBuffer:=ADR(bReadBuffer)
,szBuffer:=SIZEOF(bReadBuffer)
);
IF comRead.xDone THEN
szRead:=comRead.szSize;
uiRead:=ANY_TO_UINT(comRead.szSize);
IF uiRead >0 THEN
MEM.MemMove(ADR(bReadBuffer),ADR(sReadText),uiRead);
MEM.MemFill(ADR(sReadText)+uiRead,1,0);
IF sReadText <> '' AND sReadText <> 'Uncompressing Li' THEN
Received:=sReadText;
intReceived:=STRING_TO_INT(Received);
sReadText:='';
END_IF
xReadSuccess:=TRUE;
END_IF
comRead(xExecute:=FALSE);
iStep:=iStepComReadOK;
ELSIF comRead.xError THEN
xCom1ReadError:=TRUE;
errRead:=comRead.eError;
iError:=comRead.eError;
comRead(xExecute:=FALSE);
iStep:=iStepError;
END_IF
iStepComReadOK:
IF iStep=15 THEN
xReadSuccess:=TRUE;
iStep:=iStepComWrite;
END_IF
iStepComWrite:
IF NOT comWrite.xExecute THEN
sSend:='g';
szWrite:=INT_TO_UDINT(LEN(sSend));
MEM.MemMove(ADR(sSend),ADR(bWriteBuffer),ANY_TO_UINT(szWrite));
END_IF;
comWrite(xExecute:=TRUE
,hCom:=hCom
,pBuffer:=ADR(bWriteBuffer)
,szSize:=szWrite);
//Done
IF comWrite.xDone THEN
comWrite(xExecute:=FALSE);
xWriteSuccess:=TRUE;
iStep:=iStepComDelay;
ELSIF comWrite.xError THEN
xCom1WriteError:=TRUE;
iError:=comWrite.eError;
errWrite:=comWrite.eError;
comWrite(xExecute:=FALSE);
iState:=iStepError;
END_IF
iStepComDelay:
tTimer(IN:=TRUE
,PT:=T#1S)
;
IF tTimer.Q THEN
tTimer(IN:=FALSE);
xWriteSuccess:=FALSE;
iStep:=10;
END_IF
iStepError:
tTimer(IN:=TRUE
,PT:=T#1S)
;
IF tTimer.Q THEN
tTimer(IN:=FALSE);
iStep:=iStepInit;
END_IF;
END_CASE;
実装-Arduino側
Program
#define LED_1_PIN 9
int Temp;
char inChar;
void setup()
{
Serial.begin(9600);
pinMode(LED_1_PIN,OUTPUT);
}
void loop()
{
if (Serial.available() > 0) {
inChar = Serial.read();
if (inChar =='g'){
Serial.println("HELLO");
digitalWrite(LED_1_PIN,HIGH);
}
}
}
はーい、お疲れ様です。
このページからかんらい参考になりました。