マイクロコントローラのカスタマイズ
コードを生成するとき,多くのパラメータが自動的に設定されるか,デフォルト値を使用するかする.これらはマイクロコントローラに指定することで変更できる.
一般的なパラメータ
| "Microcontroller" | コードを生成する対象のマイクロコントローラ |
| "OperatingVoltage" | マイクロコントローラの動作電圧 |
| "ClockFrequency" | マイクロコントローラのシステムクロックの周波数 |
| "I2CAddress" | I2Cスレーブデバイスとして動作する場合のI2Cアドレス |
| "SlaveSelect" | SPIスレーブデバイスとして動作する場合のSS(スレーブ選択)ピン |
Needs["MicrocontrollerKit`"]sys = NonlinearStateSpaceModel[{{Which[x > 0, 0, True, 1]}, {x}}, {x}, {}, {Automatic}, Automatic, SamplingPeriod -> 1];
mc[pars___] := <|"Target" -> "ArduinoUno", "Outputs" -> 13 -> "Digital", pars|>;
p = "/dev/cu.usbmodem14101";MicrocontrollerEmbedCode[sys, mc["Microcontroller" -> "ATmega328P_28PDIP"], p]MicrocontrollerEmbedCode[sys, mc["OperatingVoltage" -> 5], p]MicrocontrollerEmbedCode[sys, mc["ClockFrequency" -> 16 10^6], p]タイマパラメータ
各サンプリング時点で,マイクロコントローラは入力信号を読み取り,状態を更新し,出力を計算し,出力を送信する.サンプリング区間が終わったら,タイマはリセットされ,これらの処理が最初から繰り返される.各サンプリング区間において,マイクロコントローラは,引き起こされた割り込みに対処しなければならないとき以外は,ビジー状態のときとアイドル状態のときがある.
サンプリリング区間はシステムの性能を決める重要な因子となり得る.サンプリング区間の選択は,通常性能と電力消費の間でのトレードオフとなる.
マイクロコントローラを各サンプリング区間でサンプリングを行うように設定するための情報はデータシートに記載されている.デフォルトでは,タイマとそのパラメータは自動的に選ばれる.これらは明示的に設定することもできる.
timer = {"2", "Mode" -> "7", "Prescaler" -> 1024, "Top" -> 124};ℳ = MicrocontrollerEmbedCode[sys, mc["Timer" -> timer], p]ℳ["Timer"]["2"]["SamplingError"]ℳ = MicrocontrollerEmbedCode[sys, mc[], p]ℳ["Timer"]| "delay" | Arduinoライブラリのdelay関数を使用する |
| "delayMicroseconds" | ArduinoライブラリのdelayMicroseconds関数を使用する |
| "millis" | Arduinoライブラリのmillis関数を使用する |
| "micros" | Arduinoライブラリのmicros関数を使用する |
| None | 連続操作 |
設定"delay","delayMicroseconds","millis","micros"ではArduinoライブラリの関数が使用される.マイクロコントローラはまずすべてのタスクを完了し,τ 秒遅延させ,また最初から始める.
ℳ = MicrocontrollerEmbedCode[sys, mc["Timer" -> "delay"], p]ℳ["Timer"]lib = FileNameJoin[{$RootDirectory, "Applications", "Arduino.app", "Contents", "Java", "hardware", "arduino", "avr", "cores"}];MicrocontrollerEmbedCode[sys, mc["Timer" -> "delay"], p, <|"Libraries" -> lib|>]連続操作には設定Noneが使用できる.出力が送信されたらすぐに新しい入力一式が読み込まれる.この設定はサンプリング区間を無視しても安全な場合に使用できる.タイマはこの場合設定されない.
ℳ = MicrocontrollerEmbedCode[StateSpaceModel[{{}, {}, {}, {{1}}}, SamplingPeriod -> 1, SystemsModelLabels -> None], <|"Target" -> "ArduinoUno", "Inputs" -> "A0" -> "Analog", "Outputs" -> 3 -> "Analog", "Timer" -> None|>, p]ℳ["Timer"][None]["SamplingError"] == 1共有パラメータ
| "ADC" | A/D変換設定 |
| "Serial" | シリアル通信設定 |
| "SerialOverUSB" | Serial Over USB設定 |
| "IncludeFiles" | インクルードするファイル |
| "Definitions" | マクロの定義 |
| "Declarations" | 関数宣言 |
| "Utilities" | ユーティリティ関数と変数 |
| "Initializations" | プログラムの初期化 |
| "Loop" | 各サンプリング時点で実行する |
| "PreLoop" | "Loop"の前に実行する |
| "PostLoop" | "Loop"の後に実行する |
| "UntimedLoop" | プロセッサが解放されているときに繰り返し実行する |
場合によっては,いくつかのピン(入力チャンネルまたは出力チャンネル)は共通の機能を共有する.例えば,アナログからデジタルへの変換は複数の入力ピンの間で多重化されたり,複数の入力および出力によって同じシリアル通信ピンが使用されたりする."ADC","Serial"等のマイクロコントローラのサブオプションの設定は,これらすべてのチャンネルに適用される.
ADCの例
sys = StateSpaceModel[{{}, {}, {}, {{(1/3), (1/3), (1/3)}}}, SamplingPeriod -> 1, SystemsModelLabels -> None];adc1 = Table[a -> "Analog", {a, {"A0", "A1", "A2"}}]adcSpec = "ADC" -> "Reference" -> "AVCC";この共通基準値はマイクロコントローラのサブオプションとして指定できる.
ℳ1 = MicrocontrollerEmbedCode[sys, <|"Target" -> "ArduinoUno", "Inputs" -> adc1, "Outputs" -> 3 -> "Analog", adcSpec|>, p]チャンネルの設定を直接指定することで,個々のチャンネルの機能がカスタマイズできることもある.
adc2 = Join[Table[a -> "Analog", {a, {"A0", "A1"}}], {"A2" -> <|"Type" -> "Analog", "Reference" -> "Internal"|>}]ℳ2 = MicrocontrollerEmbedCode[sys, <|"Target" -> "ArduinoUno", "Inputs" -> adc2, "Outputs" -> 3 -> "Analog", adcSpec|>, p](ℳ1["SourceCodeByteCount"] < ℳ2["SourceCodeByteCount"]) && (ℳ1["MachineCodeByteCount"] < ℳ2["MachineCodeByteCount"])SPIの例
2つのMAX6675熱電対がデータを読み込む設定を考える.どちらも同じSPIバスを使い,交換シーケンスも同じである.しかしそれらをスレーブとして選ぶのには異なるピンが使われる.
ssPins = {"8", "9"};spi = Table[{ss -> {"SELECT", "READ", "READ", "DESELECT"}}, {ss, {"8", "9"}}]util = CFunction["double", "convert", {"uint8_t", #}& /@ {"b1", "b2"}, {CDeclare["uint16_t", CAssign["sxtnBtValue", COperator[BitOr, {COperator[BitShiftLeft, {"b1", 8}], "b2"}]]], CReturn@COperator[Times, {0.25, COperator[BitShiftRight, {"sxtnBtValue", 3}]}]}]//ToCCodeStringconversion[b1_, b2_] := CCall["convert", {b1, b2}]ic = Table["12" -> <|"Type" -> "SPI", "SlaveSelect" -> ss, "Conversion" -> conversion|>, {ss, ssPins}]oc = Table["1" -> "Serial", {2}]ユーティリティは熱電対のどちらについても同じであるので,マイクロコントローラが実行する必要のある共通のユーティリティコードスニペットとして与えることができる.
ℳ = MicrocontrollerEmbedCode[StateSpaceModel[{{}, {}, {}, {{1, 0}, {0, 1}}}, SamplingPeriod -> 1, SystemsModelLabels -> None], <|"Target" -> "ArduinoUno", "Inputs" -> ic, "Outputs" -> oc, "Utilities" -> util|>, p, <|"SPI" -> spi|>]その他のパラメータ
Arduino Yun等,マイクロコントローラのボードによっては, 新しいプログラムを自動的にボードにアップロードするのにCommunications Device Class (CDC)デバイスとして設定される必要がある.仮想シリアル通信等の場合,この機能はデバイスの動作時にも便利である."CDC"オプションを使うと,この機能を取り除き,プログラムのフットプリントを減らし,ボードを手作業でリセットして新しいプログラムをアップロードすることができる.
| "Basic", Automatic | 基本的なCDC機能を加える |
| None | CDC機能を加えない |
CDC機能を取り除くことは,ボードをロック状態にすることになるため,以下の入力を評価する前にその結果を分かっておく必要がある.不明の場合は,Arduino Yunに物理的に接続しないで評価することもできる.
sys = NonlinearStateSpaceModel[{{Which[x > 0, 0, True, 1]}, {x}}, {x}, {}, {Automatic}, Automatic, SamplingPeriod -> 1];ℳ1 = MicrocontrollerEmbedCode[sys, <|"Target" -> "ArduinoYun", "Outputs" -> "13" -> "Digital", "CDC" -> None|>, p]ℳ2 = MicrocontrollerEmbedCode[sys, <|"Target" -> "ArduinoYun", "Outputs" -> "13" -> "Digital"|>, p]{ℳ1["MachineCodeByteCount"], ℳ2["MachineCodeByteCount"]}tempDir = CreateDirectory[];MicrocontrollerEmbedCode[sys, <|"Target" -> "ArduinoYun", "Outputs" -> "13" -> "Digital"|>, p, <|"WorkingDirectory" -> tempDir, "CleanIntermediate" -> False|>];FileNameTake /@ FileNames["*.c", tempDir]DeleteDirectory[tempDir, DeleteContents -> True]