前回は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);
      }
  
  }
}
はーい、お疲れ様です。
このページからかんらい参考になりました。