Codesy#PI3とArduino をシリアル通信する

前回は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ですね。

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
xExecuteBoolTrue=Function実行
usiListLengthUSINTパラメータリストのサイズ
pParameterListCAA.PVOID
udiParameterIdパラメータID、先表示したCAA SerialCom>Global Variables
udiValueその設定値
Output
xDoneBoolTrue=Function実行成功
xBusyBoolTrue=Function実行中
xErrorBoolTrue=Functionにエラーがある
eErrorERRORエラーID
hComCAA.HANDLE開いてたその”COM”

COMRead

次はこのBlockを使ってシリアルPortからデータを読みます。

Input
xExecuteBoolTrue=Function実行
xAbortBoolTrue=実行停止
udtTimeOutUDINTまぁ、Timeoutですね。
hComCAA.HANDLEいまシリアル通信で開いてるCOM
pBufferCAA.PVOIDRead Bufferのアドレス
szBufferCAA.SIZE書き込まれるバイト数
Output
xDoneBoolTrue=Function実行成功
xBusyBoolTrue=Function実行中
xErrorBoolTrue=Functionにエラーがある
xAbortedBoolTrue=Functionは中止された
eErrorERRORエラーID
szSizeCAA.SIZEいま読まられたのバイト数

ComWrite

そしてこれはシリアル通信の書き込むFunction Blockです。

Input
xExecuteBoolTrue=Function実行
xAbortBoolTrue=実行停止
udtTimeOutUDINTまぁ、Timeoutですね。
hComCAA.HANDLEいまシリアル通信で開いてるCOM
pBufferCAA.PVOIDWrite Bufferのアドレス
szBufferCAA.SIZE書き込むのバイト数
Output
xDoneBoolTrue=Function実行成功
xBusyBoolTrue=Function実行中
xErrorBoolTrue=Functionにエラーがある
xAbortedBoolTrue=Functionは中止された
eErrorERRORエラーID

ComClose

最後はComを閉じるのFunction Blockです。

Input
xExecuteBoolTrue=Function実行
hComCAA.HANDLEいまシリアル通信で開いてるCOM
Output
xDoneBoolTrue=Function実行成功
xBusyBoolTrue=Function実行中
xErrorBoolTrue=Functionにエラーがある
eErrorERRORエラーID

MEMMove

BlockmoveのようなFunction Blockですね。MemoryエリアAからMemoryエリアBにX Byte分のデータを転送する。

Input
pSourcePointer to Byte移動元
pDestinationPointer to Byte移動先
uinumberofbytesUINTなんByte分のデータを移動する
Output
MemMoveBool結果

MEMFill

FillBlockのような機能のFunction Blockですね。MemoryエリアBからなんByte分にデータをByte データに入れる。

Input
pMemoryBlockPointer to Byte移動元
uiLengthUINT移動先
byFillValueByteなんByte分のデータを移動する
Output
MemMoveBool結果

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);
      }

  
  }
}

はーい、お疲れ様です。

このページからかんらい参考になりました。

https://github.com/Pi4IoT/CODESYS_Serial

Footer_Basic

Please Support some devices for my blog

Amazon Gift List

Find ME

Twitter:@3threes2
Email:soup01threes*gmail.com (* to @)
YoutubeChannel:https://www.youtube.com/channel/UCQ3CHGAIXZAbeOC_9mjQiWQ

シェアする

  • このエントリーをはてなブックマークに追加

フォローする