はじめに
電子工作界隈の皆様、あなたのメインマイコンは何でしょうか?
最近では入門者はArduinoが主で、わざわざPICを始める人はそんなに多くないと思います。
PICマイコンは少ピンデバイスでも多機能ですから小さい回路を作るにはとても便利なマイコンです。
PICマイコンを使用する上での壁はやはりレジスタを操作することに尽きるのではないかと考えます。
クロックを設定するにもデータシートとにらめっこする必要がありますしね。
しかし、最近のMPLAB X(PICの開発環境)にはPICマイコンの煩雑な設定をGUIで行うことのできるMCC(Microchip Code configurator)というプラグインがインストールされています。このMCCはクロックやペリフェラルの初期設定をGUIで行える他、設定したペリフェラルを制御するための関数も生成してくれますので、Arduinoほどではないにせよデータシートとにらめっこする時間は大幅に減らすことができます。
で、ここからが本題で、ちょっと前からこのMCCが"MCC Melody"として新しくなりました。今までのMCCは"MCC Classic"として区別されています。まだ秋月でも取り扱っていないような最新デバイスではMCC "Melody"のみ対応なのですが、執筆時点で日本語文献がほぼ皆無のためこれから新しいデバイスで開発を行う人にはハードルが高いのではないかと思います。僕も決して使いこなしているわけではないですが、誰かが使い方を書かないことには誰も使わないだろうと言うことで筆をとることにしました。
なお、この記事で使用するデバイスは秋月で取り扱われているもので、MCC "Melody"でも"Classic"でも開発可能です。この記事の説明が解りづらいと感じた方は是非MCC "Classic"に逃げてください。Classicのほうは文献がいっぱい転がっています。
おことわり
本記事はこれからPICマイコンに触れる方から対象としており、一部厳密さに欠ける説明の箇所があります。文中、平易な言葉で更に良い説明ができる箇所がありましたらコメントいただけると助かります
使用するもの・開発環境
MPLAB X v6.10以降 (執筆時の環境はv6.10) …Microchip社製マイコンの統合開発環境
XC8 v2.41以降 (執筆時の環境はv2.41) …PIC16等の8bitマイコンのCコンパイラ
PIC16F18313 (8ピン) …マイコン
PICKIT4 …プログラマ(デバッガ) PICKIT5でもおそらく可能。MPLAB Snapでも可能だが電源が別に必要
その他:LED(何色でも可)、抵抗(1kΩ程度) 1本 + 10kΩ 1本、ブレッドボードおよびジャンパ線、3.3~5Vを供給できる電源・電池(MPLAB Snapを使用する方のみ)
テスト用回路
以下の回路をブレッドボードなり基板なりに組んでください。
PICKIT使用の方は今回は電源をPICKITより供給しますので回路点線内の部分は必要ありません。
MPLAB SNAPの方は電源供給が別に必要です。ちなみに単3電池3本でちょうどいいくらいの電圧になります。アルカリ乾電池でもニッケル水素充電池でも問題ありません。
開発環境とCコンパイラのインストール
まず、以下のダウンロードページより開発環境のMPLAB XおよびC言語コンパイラのXCコンパイラをダウンロードしてください。
なお、今回使用する8bitマイコン用コンパイラは"XC8"ですのでお間違いなく。
ダウンロード後、両方をインストールしてください。
MPLAB X(記事公開時点での最新版:v6.15)
https://www.microchip.com/en-us/tools-resources/develop/mplab-x-ide
XC8コンパイラ(記事公開時点での最新版:v2.41)
https://www.microchip.com/en-us/tools-resources/develop/mplab-xc-compilers
プロジェクト作成~MCCの使用方法
プロジェクト作成
まず、MPLAB Xを起動しますと以下のような画面になります。左上にダンボールのようなアイコンがありますのでここをクリックし、プロジェクトを作成します。[File]→[New Project...]でも可能です。
出てきたウインドウで"Standalone Project"を選択し"Next >"を押します。
次の画面では使用するマイコンを選択します。中央の"Device"のところに"PIC16F18313"と入力し選択します。
更にその次の画面では使用するコンパイラを選択します。"XC8 (インストールしたバージョン)"を選択します。
最後の画面でプロジェクトネームを入力(アルファベットで好きにつけてください。このデモでは"melody18313")、下のほうの"Encoding"はUTF-8を選択してください。デフォルトだと日本語コメントが文字化けします。
最後に"Finish"を押すとプロジェクトの作成が完了します。
なお、上記手順を以下の画像にまとめましたが、elchikaの都合上幅広画像は見切れてしまっています。画像をクリックしていただくと全て表示されるようですので適宜クリックして全表示させてください。
MCC Melodyの使用方法
プロジェクト作成が完了したら、次に上部中央の水色のMCCアイコンをクリックします。すると、以下の画面が表示されますので、ここでMCC Melodyを選択します。
次の画面でContent Manager Wizardの画面となりますが、ここにあるライブラリは今回使いませんのでそのままFinishを押します。
この画面から各種機能の設定をします。
あくまで僕の場合ですが、設定は以下の流れで行っています。
①コンフィグレーションビッツの設定→②クロック設定→③各種ペリフェラル設定→④GPIOピン配置設定
①はマイコンのクロック源やメモリ保護機能など、簡単に言えば動作の根幹となる部分の設定です。画面左上の"Configuration Bits"から設定できますが、今回はここはデフォルトのままでOKです。クロック源は②の設定を行うと設定したとおりに自動でコンフィグレーションビッツを変更してくれます。
②のクロック設定では、マイコンをどのくらいの速さで動かすか、クロック源をどれにするか等の設定をします。
今回は以下の設定とします
・マイコンの内部にあるオシレータを使用
・8MHzで動作
下の画面の通り設定してください。
ちなみに、動作クロックを今回8MHzとしますが、このマイコンは32MHzまでクロックの周波数を上げることが可能です。
ただし、PCのCPUと同じで周波数を上げると消費電力が増えますので必要十分な周波数に留めておいたほうがいいのではないかと思います。特に電池駆動する場合は。
また、PIC16の場合は1動作に対し4クロック必要です。MCCを使用する場合気にすることはあまりありませんが記憶の片隅に入れておくと作りたいアプリケーションに対してどのくらいのクロック周波数が必要か目星つけることができます。
③の各種ペリフェラル設定ですが、これはCPUやメモリ以外にマイコンが内部に持っている機能を使用するための設定です。
例えるならばペリフェラルは道具で、それを人間(CPUやメモリ)が手に取り使っているイメージです。
同じPIC16F1xxxxシリーズでも、型番が変わるとペリフェラルの種類や数が変わることが多いです。というよりこのペリフェラルの違いで色々な型番のPICがあると言ったほうがいいでしょうか(ピン数やメモリ違いもあるけども)
これを使いこなせないことにはマイコンは使えないと言っても過言ではないです。
画面左中央の"Device Resources"内の"Hardware Peripherals"に使用できるペリフェラル一覧があります。
このペリフェラルの使い方の詳細は例3で説明します。
まずはGPIOの制御のみでLチカしますので、④GPIOの設定のみを行います。
GPIOとは日本語で汎用入出力と言い、簡単に言えば電源ピンやMCLRピンなどマイコンの動作に必要なピン以外の、ユーザーでプログラムできるピンのことを指します。このあと行うプログラムでピンの状態を変化させたり、ピンの状態を読み込んだりできます。
今回はRA0にLEDを繋ぎ(=出力・output)、RA2にタクトスイッチを繋ぎます(=入力・input)
以下の図のように設定してください。例によって画像が見切れていますので、クリックして全表示させてください。
これで設定は終了です。画面左上"Project Resources"右の"Generate"ボタンをクリックします。
このボタンを押すことによりMCCでの設定に合わせてプログラムの雛形を生成してくれます。
あとは生成された"main.c"に実際の動作をプログラムしていきます。
main.cは下図の通り、左上画面のProjectsタブ > Source Fileフォルダ > main.c にありますので開いてください。
まずはおなじみのLチカからプログラムを書いていきます。
例1:Lチカ
今回は0.5秒ごとにRA0に繋がったLEDを点滅させます。
このLチカについてはいくつか書き方があります。
まず下記の例"Lチカ MCCバージョン"はGPIOをMCCで生成する際に決めた名前で制御する方法です。
今回はGPIO設定の際、RA0のCustom Nameを"IO_RA0"という名前にしていました。
ピンのHIGH・LOWを変化させる場合はCustom Nameの末尾に"_LAT"をつけ、HIGHにしたいときは"1"を代入、LOWにしたいときは"0"を代入します。
例1の回路ではHIGHにするとLEDが点灯し、LOWにすると消灯します。
ひとつ注意として、設定した時間なにもせず待機するdelay関数というものを使用しますが、この関数は先頭にアンダーバーを2個付ける必要があります。1個ですとエラーとなります。
__delay_ms(500); //500ms待機 先頭はアンダーバー"_"が2個
補足:HIGHレベルにすると該当のIOピンとVDDがつながるイメージ、LOWレベルにすると該当のIOピンとVSSがつながるイメージです。今回はIOピンRA0にLEDのアノードが抵抗を介して繋がり、カソードはGND(=本回路ではVSSと同じ電圧レベル)に繋がっています。したがってHIGHレベルの際はVDD→RA0ピン→抵抗→LED→GNDと電流の流れる経路ができるためLEDは光ります。一方、LOWレベルの際はGND(VSS)→RA0ピン→抵抗→LED→GNDとLEDと抵抗の両端が同じ電位となるため光りません。
/*Lチカ MCCバージョン*/
//main.cのint main(void)関数内のwhile(1)にプログラム
while(1)
{
/*以下、記載するプログラム*/
IO_RA0_LAT = 1; //IO_RA0_LATピン(RA0)をHIGHレベルにする
__delay_ms(500); //500ms待機
IO_RA0_LAT = 0; //IO_RA0_LATピン(RA0)をLOWレベルにする
__delay_ms(500); //500ms待機
}
マイコンへの書込はこの項の最後に記載します。
上記の例ではMCCでの設定時に決めたCustom Nameで制御しましたが、他にもGPIOの状態を制御するレジスタに値を代入し制御する方法があります。というかこちらが一般的です。
レジスタとはマイコンの制御をするため、もしくは現在の状態を読み込むために読み書きするメモリです。
マイコンにある動作をさせる際には該当のレジスタに決められた値を代入し、逆にマイコンの現在の状態を読み込みたい場合は該当のレジスタに書き込まれた値を読めばわかります。
では、どのような値をどのレジスタに書き込めばいいのかはどこに書いてあるのでしょうか?
→データシートに記載があります
例えばGPIOピンの"HIGH""LOW"の制御を行うレジスタはPIC16F18313のデータシート(40001799)の132ページに記載の"LATA"レジスタです。
下の方に、"bit2-0 LATA[2:0]: RA[2:0]Output Latch Value bits"と書いてありますが、無理やり意訳するとLATA2~LATA0のビットに"1"もしくは"0"を入れるとRA2~RA0に同じ値を入れ保持しますよ的なことです。
では、そのRA2~RA0はどのようなレジスタなのでしょうか。答えはデータシートの131ページにあります"PORTA"レジスタの項を見ます。
PORTAレジスタは"bit 5-0 RA[5:0]: PORTA I/O Value bits"つまりPORTAのIOの値(レベル)を設定するレジスタです。
ここに"1"を代入すると該当のピンは V_IH以上(つまりHIGH)となり、"0"を代入するとV_IL以下(つまりLOW)となります。
逆に、このレジスタの値を読みだした際"1"であれば該当のピンにかかっている電圧はHIGHであり、"0"であればLOWです。これはあとでタクトスイッチを使用する際に出てきますので覚えておいてください。
つまり、たとえばLATA0に"1"を入れると対応するRA0も"1"となり、出力はHIGHになるということです。
勘の良いガキ皆様は気づいたと思われますがRA0にそのまま"1"を代入しても出力はHIGHになります。なぜLATレジスタを使用するかという話については詳細は省きますが、容量性負荷(コンデンサ)がピンに繋がっている状態でRAxレジスタのビットを高速で制御すると不具合が起こります。そこで正確にoutputの制御を行うためにできたのがLATレジスタです。
PIC16Fのレジスタは8bitでひとまとまりとなっており、各レジスタには名前がついています。また、その中の各ビットにも名前がついており、この名前のメモリに値を代入することによって設定をしていきます。
例えばRA0ピンの出力をHIGHにしたい場合は、PORTAというレジスタのRA0というビットに"1"を代入することになりますが、先程の話より対応するLATAレジスタのLATA0ビットに"1"を代入します。
このLATA0だけを制御したいのであれば以下のような書き方になります。
LATAbits.LATA0 = 1; //レジスタ名+bits.+ビット名
一方、LATA0~LATA5を一気に制御したい場合は以下のような書き方になります。
上記データシートの"LATA"の項を見ながら読んでみてください。
LATA = 0b00110101; //RA5,4,2,0はHIGH,RA1はLOW, 8bitの値で制御する
※LATAレジスタのbit7,6,3は未実装でどんな値を代入しても何も起こりません。読み出すと"0"となります
/*Lチカ レジスタ操作バージョン*/
while(1)
{
/*以下、記載するプログラム*/
LATAbits.LATA0 = 1; //RA0(IO_RA0_LATピン)をHIGHレベルにする
__delay_ms(500); //500ms待機
LATAbits.LATA0 = 0; //RA0(IO_RA0_LATピン)をLOWレベルにする
__delay_ms(500); //500ms待機
}
本来、マイコンのプログラムを書くということはレジスタをひたすらに読み書きする作業です。が、慣れないとデータシートを追うだけでも大変な作業となってしまうため面倒なところはMCCで自動で生成してもらったほうが作業効率は上がります。
ただし、僕を含めいまでもレジスタをいじるほうが主流の書き方ですので使用するペリフェラルのレジスタはどのようなものがあるかデータシートを眺めたほうが他人のソースコードを読む際にもきっと役に立ちます。
この項目以降に記載するプログラムについてはできる限りMCCで生成したライブラリを使用しますが、一部レジスタが混じることがあります。
マイコンへの書き込み方法
まずPICKIT4やSNAP等のプログラマをPCに繋げます。このとき環境によってはPICKITを認識しない場合がありますがいろんなUSBポートに挿し込んでみてください。どこかしら当たりがあるはずです。
次に右下にあるタブのデフォルトで一番左側のタブを選択し、そのタブの下くらいにあるスパナのアイコンをクリックします。
ポップアップされたウインドウの"Conf [default]"をクリックすると"Connected Hardware tool"がありますので、ここで使用するプログラマを選択してください。ここにない場合は認識できていません。
MPLAB SNAPを使用している方はここで画面下のOKを押して終了です。次のPICKIT電源供給の項は飛ばしてください。
一方、PICKIT4を使用している方でかつ電源供給をPICKITから行う場合(電池や電源を使わない場合)は電源供給の設定が必要ですのでここでは"OK"ではなく"apply"を押してください。
"Conf [default]"下の"PICkit4"をクリックすると設定画面が出ます。その中の"Option categories"で"Power"を選択します。
すると"Power Target circuit from PICkit 4"という項目が出てきますのでチェックを入れてください。
その下のVoltage Levelは出力電圧設定ですが、今回は5.0(V)で問題ありません。使用するデバイスや回路によって適宜3.3Vに変える等調整してください。
以上で設定完了ですので"OK"を押してください。
ここから実際に書き込みに移ります。
まず、画面上部のアイコン郡の中から緑の下向き矢印がICに向いているアイコンをクリックします。このボタンはコンパイルと書き込みを同時にやってくれるボタンです。
プログラムの記述に間違いがなければ画面下に「一瞬」緑字で"BUILD SUCCESSFUL"と表示されマイコンへの書き込みに移ります。
その後注意ウインドウが出てきますが、これはそのままOKを押してください。
意訳すると"プログラマに繋がっているマイコンはプロジェクトで指定したものと同じですか?","5V動作のデバイスが指定されているときに3.3V上限のデバイスが繋がっているとデバイスID確認時に壊れることがありますよ"とのことです。
今回使用するPIC16"F"18313は5Vデバイスなので問題ありませんが、PIC16"LF"18313のようにLFのデバイスは3.6V MAXなので注意してください。
書き込みが終了すると最後に"Programming/Verify complete"と表示されます。
ここで書き込みが出来ていなかった場合は配線や電源供給を見直して下さい。
正常に完了していればLチカしているはずです。
例2:スイッチが押された際にLEDを点灯させる
MCCでRA2ピンをinput(入力)に設定しました。inputに設定するとそのピンの状態(電圧レベル)を読み出すことができます。具体的にはRA2ピンにかかる電圧が"HIGH"の場合はPORTAレジスタのRA2ビットを読み出すと"1"となり"LOW"の場合は読み出すと"0"となります。
回路図を見るとタクトスイッチはRA2ピンからGNDに繋がっています。また、MCCでの設定時にこのRA2はマイコン内部でプルアップするよう設定しました。したがってスイッチが押されていない場合はRA2ピンは"HIGH"レベルとなっており、逆にボタンが押されると"LOW"レベルとなります。
例としてタクトスイッチを押している際にLEDを光らせるコードを記載します。
今回もMCCで生成されたもののみで記載したバージョンとレジスタを直接読み出すバージョンの2種類記載します。
/*スイッチ入力 MCCバージョン*/
while(1)
{
/*以下、記載するプログラム*/
//RA2のSWが押されている間RA0のLEDを点灯させる
if(IO_RA2_PORT == 0){
IO_RA0_LAT = 1;
}
else{
IO_RA0_LAT = 0;
}
}
/*スイッチ入力 レジスタ操作バージョン*/
while(1)
{
/*以下、記載するプログラム*/
//RA2のSWが押されている間RA0のLEDを点灯させる
if(RA2 == 0){
LATAbits.LATA0 = 1;
}
else{
LATAbits.LATA0 = 0;
}
}
例3:LEDを調光する(PWM)
LEDの調光について
例1ではLEDの点灯・消灯の制御を行いましたが、それだけでなくLEDの明るさを制御したい場面もあります。LEDの明るさ(光束)はほぼ電流に比例しますので、マイコンで電流を変化させてあげればいいのですが単純に電流を制御することはできません。
例1で説明した通りoutputモードのGPIOピンは"HIGH"状態ではVDDに繋がり、"LOW"状態ではVSSに繋がるため、中間のような状態はないわけです。
ではどうやって明るさを制御するのかというとPWM(パルス幅変調)を使います。
"PWM LED 電子工作"とでもgoogle検索すればいくらでも情報が出てくるので詳細はそちらに任せますが、要は目には感じ取れない速さで"HIGH",""LOW"を繰り返し、LEDを高速に点滅させます。このときHIGHとLOWの時間の割合を変化させると平均電力が変化しますのでLEDの明るさが変化して見えます。
このとき、HIGH状態とLOW状態の比をDuty比と言います。
PIC16F18313にはこのPWM波形を生成できるペリフェラルがありますのでこれを使います。
また、下図の通りPWMは一定の時間ごとにHIGH,LOWを切り替えるため時間を測ってくれるタイマーが必要になります。このマイコンではTimer2というタイマーを使用します。
今回はパルスの周波数を1kHz(=1周期 1ms)とします。
何もスイッチを押していないときはDuty比75%の明るさで点灯し、スイッチを押している間Duty比25%となるようにします。
まず、再度MCCの画面を開きます。
すでにMCCが起動されている場合は左上のペインのタブに"Resource..."があるはずですのでそのタブを選択します。
この"Resource..."タブがない場合はMCCが起動していないと思われますので再度水色のMCCアイコンをクリックしMCCを起動させます。
次に左中央の"Device Resource"の中から、Timer > TMR2を表示させ、TMR2左側の緑+のアイコンをクリックします。するとProject Resources内にTMR2が移動し、TMR2の設定が画面右側に出ていると思います。
以下の画面の通り、Hardware Settings内のPrescalerを1:16に設定、その後、下にあるTimer Period(sec)にPWMの1周期の時間を入力します。1ms = 0.001secですから0.001と入力します。すると下に1000.000 usと表示されているはずで、1000us = 1msですから正しく設定されたことになります。これでTimer2の設定は終わりです。
※us = μsのこと。推測ですが英語圏のキーボードではマイクロの文字が簡単に出せないため形が似ている"u"を用いているか、もしくは"μ"が2バイト文字でエンコードに依存するためにuで代用していると思われます。ちなみにdelay関数でマイクロ秒を扱いたい場合は__delay_us()と記載します。
次にPWMの設定です。
実はPWMの波形を生成できるペリフェラルは2種類あり、単に"PWM"と呼ばれるモジュールと"CCP(Captcha/Compare/PWM)"がありますが、今回は単なる"PWM"モジュールを使用します。
左中央の"Device Resource"の中から、PWM > PWM5を表示させ、左側の緑+のアイコンをクリックし設定を開きます。
以下の画面、Hardware Settingsの"Duty Cycle (%)"の入力ボックスにDuty比を入力すると起動時のDuty比を設定できます。ここで重要なのがその下にある"PWMDC Value"で、プログラム内でDuty比を変化させる際にはDuty比設定関数にこの数値を書き込む必要があります。75%の場合は"374"です。一方、25%の場合をボックスに入力し確かめると"124"でした。また、一応100%の場合を確認すると"499"とのこと。あとは10%にしたかったら499*0.1 ≒ 50 を入れてあげればいいことになります。この後説明しますがduty比をロードする関数は整数型なので小数点以下は適宜まるめてください。
なお、PWMの分解能は"PWMDC Value"の100%の時の値となります(最大10bit,0~1023)。つまり今回は499段階の調光が可能です。
このPWMの分解能は動作周波数やTMR2のプリスケーラ(Prescaler)の値、設定した周期で左右されます。下手な設定をすると分解能が著しく落ちます。データシートのPWMの項目に詳細の計算式が記載されていますので慣れてみたら読んでみてください。
なお、この入力ボックスの下のほうに"PWM Frequency(Hz) 1000"と表示されているはずです。正しくTMR2が設定できていればここに設定したはずの周波数が表示されますので確認してください。
最後にPWM波形を出力させるGPIOピンを設定します。今回はRA0にLEDが繋がっていますのでRA0にPWM5出力を割り当てたいのですが、今現在は単にoutputに設定されていますので、これを解除します。
まず、"PORTA-0"の列,"Pins-GPIO-output"の行のオレンジの閉じた南京錠アイコンをクリックし青い開いた南京錠アイコンの状態にします。"0"の列のアイコンがすべて青くなったことを確認し、今度は"PWM5-PWM5OUT-output"の行の"PORTA-0"の列にある青色南京錠アイコンをクリックしオレンジ色にします。これで割り当ては完了です。
ここまで来たら再度左上の"Generate"ボタンを押してライブラリを生成させてください。これでMCC設定は完了です。
以下の画像は見切れていますので適宜クリックして拡大して下さい。
main関数内に書くソースコードは以下の通りです。
MCCによりvoid PWM5_LoadDutyValue(uint16_t dutyValue)
関数が生成されています。
この関数は引数に先ほど調べた"PWMDC Value"を代入することにより出力PWM波形のDuty比を設定してくれます。
なおuint16_t型はXC8ではunsigned int型と同義で、16bit符号なし整数型ですから小数点や負の値で設定することはできません。
while(1)
{
/*以下、記載するコード*/
//RA2のSWが押された場合にRA0のLEDの明るさを25%に落とす
//押されていない間は75%
if(IO_RA2_PORT == 0){
PWM5_LoadDutyValue(124);
}
else{
PWM5_LoadDutyValue(374);
}
}
実際にRA0出力波形をオシロスコープで確認しました。ちゃんと設定した通りのパルスとなっています。
補足:もう少し詳しいMCC生成ライブラリの使い方
今回はvoid PWM5_LoadDutyValue(uint16_t dutyValue)
という関数があるということをこの項に記載したので結果的にコピペでプログラムできますが、ではこの関数はどこに生成されいるのでしょうか。もしくは生成されたライブラリ・関数はどのように使えばいいのでしょうか。
答えはMCCが生成したヘッダファイルに書いてあります。順を追って確認していきます。
まず、PWM5のヘッダファイルを開きます。画面左上のタブは"Project"選択します。その中に"Header Files"というフォルダがあるので開きます。ここに"MCC Generated Files"と書かれたフォルダがあり、MCCで設定したペリフェラルに関するライブラリのヘッダファイルが格納されています。更にその中、"pwm"フォルダ内の"pwm5.h"をダブルクリックして開いてください。
ここに生成した関数の使い方が書いてあります。
たとえば"PWM5_LoadDutyValue()"の場合は以下のように書かれています。
/**
* @ingroup pwm5 …PWM5
* @brief Loads the 16-bit duty cycle value. …簡単な説明:16bitのDuty Cycle Valueをロードする
* @param uint16_t dutyValue - PWM5 duty cycle value to be loaded. …引数:uint16_t dutyValue - PWM5にロードさせるDuty Cycle Value
* @return None. …返り値なし
*/
と、このように簡単に使い方が載っています。
半分くらいの関数はヘッダファイルの説明だけでわかるのですが、たとえばこの"PWM5_LoadDutyValue()"の場合は"16-bit duty cycle value"が何なのかはよくわかりません。たぶんここにある値を入れるとPWMのDuty比が変わるんだろうなくらいです。
では、実際のライブラリの中身はどうなっているのでしょうか。今度は"Source Files"フォルダ内を同様に潜っていき、"pwm5.c"を開きます。するとPWM5_LoadDutyValue関数の中身がありました。
void PWM5_LoadDutyValue(uint16_t dutyValue)
{
// Writing to 8 MSBs of PWM duty cycle in PWMDCH register
//意訳:dutyValueの10bit値のうち上位8bitをPWM5DCHレジスタに代入する
PWM5DCH = (uint8_t) ((dutyValue & 0x03FCu) >> 2);
// Writing to 2 LSBs of PWM duty cycle in PWMDCL register
//意訳:dutyValueの10bit値のうち下位8bitをPWM5DCLレジスタに代入する
PWM5DCL = (uint8_t) ((dutyValue & 0x0003u) << 6);
}
さらっと流してましたが今回使用しているPWMモジュールは本来10bitの分解能があります。ただし、PIC16シリーズのレジスタは8bit幅ですので10bitでは収まりません。そこで2Byteぶんレジスタを使用しDutyの設定をします。この関数では10bitの数値の上位8bitをPWM5DCHレジスタに代入、下位2bitをPWM5DCLに入れております。
ゆえにこの関数の引数は16bit幅ありますが、実際は10bitぶんしか使わないことが関数を見るとわかります。
とのことで、勘を含めこの関数の引数に入れる数値は"PWMDC Value"でいいんだろうなと予測できるわけです。
これでもまだ予測ですので、最終的にはデータシートとにらめっこするか実際にプログラムして波形を確認することで機能を確認します。
また、MCCのProject Resource画面中にある青丸のクエスチョンマークをクリックするとそのペリフェラルやライブラリ、関数の使い方を見ることができます。が、執筆時点ではまだ空白ページだらけで十分な情報が載っているとは言い難い状況です。
MCCで生成される関数でやりたいことの8割はできる印象です。
逆に特殊な動作をさせる場合は自分でレジスタを読み書きしていく必要があるわけです。
ただし、レジスタのいじり方を間違えると大きなバグや見つけづらいバグ発生の原因となりますので注意が必要です。
MCC "Melody"にはこれらの方法以外にも、ペリフェラルを制御する関数を生成せずただ初期設定だけ行うやり方があり、レジスタレベルで細かく初期設定したい方はこちらを使用したほうがいいと思います。詳細は省略しますが"Device Resources > Hardware Peripherals"から使用するペリフェラルを選択し設定します。
その他:MCC "Classic"の使い方について
→後閑哲也先生の最新の書籍を買って読んでください
今回取り上げなかったペリフェラルの使い方についても詳細に記載されています。
おわりに
正直現段階ではMCC Classicのほうが機能が多いため、MelodyとClassicが両方対応しているマイコンであれば率先してMCC Melodyを使う理由はありません。が、ゆくゆくはMCC Melodyに移行するとのことが上で紹介した本には記載されていますので今のうち覚えておいてもいいのではないかと思います。
次回はこのMCC Melodyを使用しNeoPixelという便利なLEDをPICで簡単に制御する方法について投稿しようと思います。いつになるのかわかりませんが。
投稿者の人気記事
-
yuzuhara
さんが
2023/08/20
に
編集
をしました。
(メッセージ: 初版)
-
yuzuhara
さんが
2023/08/20
に
編集
をしました。
(メッセージ: 一般公開に変更しました)
ログインしてコメントを投稿する