概略

大量のデータを保持するために保持変数メモリを拡張する方法を考えます

  1. NJシリーズであれば「CJユニット用メモリ」で足りるかをチェックします
  2. まずはCJメモリを使って保持メモリの代わりにできるか考えてみます
    それでもメモリが足りないときは、NXシリーズの場合は「変数をファイルに保存」か「ファイルをメモリ化」の方法を検討します

  3. 「変数をファイルに保存」する方法
  4. 保持したい変数を構造体にまとめて定期的かイベントで構造体をまるごとファイルに保存する方法です
    この方法はスナップショットのイメージで、電源起動時にスナップショットを復元して直近のデータに戻す動作をします

  5. 「ファイルをメモリ化」はファイルをメモリ代わりにして直接読み書きします
  6. この方法はファイルを物理メモリのように扱って値の変化を順番に書き込みます
    そのため書込み時間を考慮する必要があり、頻繁に変化する変数は保持変数メモリに割り当て、変化が少なくて保持したい変数をこの方法で行います

CJメモリを有効活用

概略

CJユニット用メモリを保持メモリとして使えますが
DMはCJユニットで使用するエリアがあるためEMエリアのみを保持メモリとして使うことにします
※ CJユニット用メモリがあるのは、NJシリーズのみです (NXシリーズでは保持メモリをCJユニット用メモリに割り付ける機種もあります)

CJユニット用メモリ(保持)

DM D0~D32767 D20000~D29599は使用不可(CJ 高機能IOユニット用)
D30000~D31599は使用不可(CJ CPU高機能ユニット用)
EM E0_0~E3_32767
EM E3_0~E18_32767 NJ501のみ使用可能 (20バンク 03HEX~18HEX)

EMは1バンクあたり32767WORDなので65536Byte=64KByteあります
NJ501では64KByte×24バンク=1.5MByteを保持メモリとして使用可能です
NJ101,301では同様に256KByteを保持メモリとして使用可能です

CJMemoryのメモリエリア

設定方法

グローバル変数またはPOUの変数設定の割付先にAT指定で%E0_0など先頭アドレスを設定することでCJユニット用メモリを使用することができます

AT指定

E0 WORD型配列32868個をE0_0~E0_32767に割付けました
ByteArray BYTE型配列65536個をE1_0~E1_32767に割付けました
DINTArray DINT型配列16384個をE2_0~E2_32767に割付けました
TestStruct sTestStruct型配列4095個をE3_0~E3_32767に割付けました(sTestStructは16byteの構造体)
WordArray1 WORD型配列1000個をE0_0~E0_999に割付けました
WordArray2 WORD型配列1000個をE0_1000~E0_1999に割付けました

メモリ使用状況
メモリ使用状況

メモリ使用状況で確認すると保持変数メモリは消費されていません

注意事項

バンクを超えた領域は設定できません
例えば、割付先に%E0_0を設定して変数のサイズが32768WORD(65536byte)を超える変数を設定することはできません

割付けが被らないように注意が必要です
例えば、割付先をE0_0とした1000byteの変数と、割付先をE0_500とした1000byteの変数を設定する事ができてしまいます
この場合E0_500~E0_999が2つの変数で被ってしまうため値が不定となってしまいます

変数をファイルに保存

大量のデータを保持したいときに、非保持変数を通常のメモリとして使用しながら、SDカードにファイルとして記憶する方法です
変数をSDカードに書き込む方法と特徴について調べます

大容量変数を丸ごとSDに書き出す

非保持変数メモリに大容量の変数を作成してFileWriteVar命令で変数を丸ごとSDに書き出します
こうすることでファイルを書き込んでから電源がOFFするまでの変数の値の変化は保持できないものの、ファイルに書き込んだ時点までを保持する事ができる変数を作ることができます
保持変数が足りなくなったら、少し巻き戻っても問題のない変数をこの方法でファイルに保持することを検討します
ファイルに書き込んだ値は電源ON時にFileReadVar命令で読出します

構造体

約524KBの構造体を宣言
構造体

グローバル変数

構造体を配列にして約4MBのグローバル変数にする
グローバル変数

メモリ使用状況

メモリ使用状況で確認
メモリ使用状況

ラダー

TriggerをONでファイル書込み
ラダー

書込み時間計測

書き込む変数(WriteVar)のSampleStructの要素数を変えて4MB,3MB,2MB,1MBのサイズで書込み時間を測てみました
定周期にファイルに書き出す時は、この書込み時間の2倍以上を目安に書込み処理を実行するタイミングを調整してください
100回計測中の最大値(かっこは平均値)

書き込み時間
書き込み時間

ファイルをメモリとして使う

大量のデータを保持したいときに、SDカードのファイルを保持メモリの代わりとして使う方法です
ファイルをメモリとして使う方法と特徴について調べます

ファイルをメモリとして使う

SDに任意のサイズのファイルを作り、そのファイルの物理的なアドレスに値を直接書き込みます
物理的なアドレスとは、ファイルの先頭からのバイト数がアドレスになります

注意が必要なのは、書込み用のバッファを使って変数をファイルに書き込むため時間がかかります
読み出しをするときには書込みが終わるのを待ってから読み出すことになります
このことから、値が頻繁に変化する変数はこの処理には不向きです

書込み用リングバッファ

書込み変数の最大サイズ : 4096byte
バッファ数 : 100

リングバッファの構造体
リングバッファの構造体

書込みファンクション

書込みデータとアドレスを指定して書込みバッファに追加します

ファンクション一覧
MemWriteSINT
MemWriteUSINT
MemWriteBYTE
MemWriteINT
MemWriteUINT
MemWriteWORD
MemWriteDINT
MemWriteUDINT
MemWriteDWORD
MemWriteLINT
MemWriteULINT
MemWriteLWORD
MemWriteREAL
MemWriteLREAL
MemWriteTIME
MemWriteDATE
MemWriteTOD
MemWriteDT
MemWriteSTRING

【例】

Func
入出力
Ringbuf
sRingBuff
書込み用リングバッファ
Data
ARRAY[*] OF ??
書込みデータ
入力
Address
DINT
書込みバイト位置

ファイル書込みFB

書込み用バッファからファイルに書込みします

FB
入出力
Ringbuf
sRingBuff
書込み用リングバッファ
入力
FileName
STRING[66]
ファイル名
出力
WriteBusy
BOOL
書込み中

ファイル読出しFB

TriggerをONで指定したアドレスから値を読出し

MemReadFB
入力
FileName
STRING[66]
ファイル名
Address
DINT
読出し開始バイト位置
入出力
ReadData
ARRAY[*] OF BYTE
読出しデータ

使い方

書込みファンクション(MemWrite???)で書き込みたい値を書込み用リングバッファに追加します

リングバッファ格納サンプルラダー
リングバッファ格納サンプルラダー

蓄えられたリングバッファのデータはファイル書込みFB(MemControl)でファイルに書き込みます
このファイル書込みFB(MemControl)はプログラムの最後で常時1つだけ実行しておくことでリングバッファのデータを順番にファイルに書き込みます

書込みサンプルラダー
書込みサンプルラダー

ダウンロード

この記事へのコメント