こんにちは、ENGかぴです。
PIC16F1827のDOとNOPを使用することでマイコン内蔵のRGB LEDの操作して色のパターンを生成して点灯させることができます。赤、緑、青の制御値をLCDで表示することで色のパターンを確認しながら点灯させました。
本記事はDOとNOPを使用してRGB LEDの点灯パターンを切り替えた下記記事の応用です。
PICマイコン(PIC16F1827)でRGB LEDを操作する
RGB LEDはマイコン内蔵RGB LED 5mm PL9823-F5(秋月電子で購入)を使用しています。LCDはAQM1602XA-RN-GBW(秋月電子で購入)を使用しています。PIC16F1827で動作確認したことについてリンクをまとめています。
PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ
マイコン内蔵RGB LEDを操作する

RGB LEDはユニポーラゼロ調整コードを使用します。一色あたり8ビットの構成であるため256パターンの調整ができます。RGB LEDは赤・緑・青の3色の調整を行うためプロトコル(Timing waveformの集合体)は24ビット構成になります。Timing waveformはHighでスタートしHighの長さとLowの長さによって1の指定か0の指定かを判定します。
PL9823のデータシートによると1 codeとして認識させるためには標準でT1H(1 code, high level time)が1.36usとT1L(1 code, low level time)が0.35us必要です。
0 codeとして認識させる場合は標準でT0H(0 code, high level time)が0.35usとT0L(1 code, low level time)が1.36usが必要です。誤差を含めると標準±150nsの間で制御する必要があります。
PL9823を制御するためにPIC16F1827のシステムクロックを32MHzに設定した状態でDOを操作しNOPで待機させてタイミング波形を生成します。
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
タイミング波形を生成とLCDの使用方法
PIC16F1827のDOとNOPを使用してRGB LEDを操作します。DOとNOPを使用したタイミング波形の生成方法は下記記事で説明しています。
PICマイコン(PIC16F1827)でRGB LEDを操作する
LCDの使用方法については下記記事まとめています。
PICマイコン(PIC16F1827)のI2C通信を実装する
LCDについてはI2Cを使用していますが、System Clockの変更により通信速度を変更していますが、使用方法については同様です。
点灯パターンの判定

Set0code()関数は0 codeのタイミング波形を生成する自作の関数とします。Set1code()関数は1codeのタイミング波形を生成する自作の関数とします。これらの関数を使って点灯のパターンを構成します。赤色の制御を例を説明します。
赤色はR7からR0までの各ビットに0 codeもしくは1 codeを指定する必要があります。データシートには各ビット間のタイミングについては特に規定されていませんが、各ビット間の送信間隔を可能な限り短くする必要があります。他のRGB LED(SK6805)ではLowの区間を20us以下とすることが規定されています。
点灯パターン(制御値)に応じて0 codeもしくは1 codeのパターンを判断してSet0code()関数またはSet1code()関数に遷移する仕組みを作って点灯パターンを切り替えます。
typedef struct{
void (*red7)(void); //R7の関数
void (*red6)(void); //R6の関数
void (*red5)(void);
void (*red4)(void);
void (*red3)(void);
void (*red2)(void);
void (*red1)(void);
void (*red0)(void);
}FUNC_SET;
FUNC_SET led; //変数を宣言
//登録の例
led.red7 = Set0code; //red7で遷移させる関数名を指定
led.red6 = Set1code; //red6で遷移させる関数名を指定
//使用例
led.red7(); //red7で登録した関数をコールする
led.red6(); //red6で登録した関数をコールする
FUNC_SETはR7~R0の各構成要素において遷移させる関数のアドレスを登録する構造体です。FUNC_SET型の変数を宣言してメンバー変数に各ビットに対応するcodeに応じて遷移させる関数を指定します。
登録の例ではR7に相当するred7にSet0code()関数を指定しています。R6に相当するred6にSet1code()関数を指定しています。
PR:(即戦力のスキルを身に着ける:DMM WEBCAMP 学習コース(はじめてのプログラミングコース))
使用例ではred7で登録した関数とred6で登録した関数をコールする例を示しています。使用する前に関数名を登録する必要があります。
次に制御値から各ビットにSet0code()関数またはSet1code()関数を登録する方法について説明します。
red = 123;
(red & 0x80) ? (led.red7 = Set1code) : (led.red7 = Set0code);
(red & 0x40) ? (led.red6 = Set1code) : (led.red6 = Set0code);
(red & 0x20) ? (led.red5 = Set1code) : (led.red5 = Set0code);
(red & 0x10) ? (led.red4 = Set1code) : (led.red4 = Set0code);
(red & 0x08) ? (led.red3 = Set1code) : (led.red3 = Set0code);
(red & 0x04) ? (led.red2 = Set1code) : (led.red2 = Set0code);
(red & 0x02) ? (led.red1 = Set1code) : (led.red1 = Set0code);
(red & 0x01) ? (led.red0 = Set1code) : (led.red0 = Set0code);
//以下の例と同じ
if(red & 0x80 ){ //1以上の場合
led.red7 = Set1code;
else{ //0の場合
led.red7 = Set0code;
}
赤色(red)が123の場合のタイミング波形の関数の登録について説明します。123は2進数で表現すると0b01111011なのでタイミング波形はMSBから順にred7が0 code、red6が1 code、red5が1 code、red4が1 code、red3が1 code、red2が0 code、red1が1 code、red0が1 codeになります。
redに対して各ビットが立っているかを確認するために各ビットの値に対する論理積を算出します。計算結果が各ビットの値と同等であれば1 codeと判定することができ、計算結果が0であれば0 codeと判定することができます。
例)red7及びred6の判定
red7 = 0b0111 1011 AND 0b1000 0000(0x80) = 0
red6 = 0b0111 1011 AND 0b0100 0000(0x40) = 0x40
red7の論理積の結果は0になるのでSet0code()関数を登録します。red6の論理積の結果は0x40になるのでSet1code()関数を登録します。各ビットで同様の計算を行いタイミング波形の生成関数をセットしていきます。
/* タイミング波形の送信*/
void WaveStart(void){
led.red7();
led.red6();
led.red5();
led.red4();
led.red3();
led.red2();
led.red1();
led.red0();
}
制御値に対する関数の登録した順番にタイミング波形を送信するためにred7()からred0()までを降順にコールします。red7()~red0()は登録した関数がコールされるため制御値に応じたタイミング波形を送出することができます。
MCCの設定
PIC16F1827の設定はMCCを使っています。MCCの使い方については下記記事にまとめています。
MPLAB Code Configurator(MCC)の追加と使い方
今回はMCCを使用してSystem clock、TMR0、MSSP1の設定を行っています。
System Moduleの設定
最初に共通事項であるSystem Moduleの設定を行います。MPLAB X IDEを起動しMCCのアイコンをクリックしてMCCを有効にします。

内部クロックを使用するためINTOSCを選択しています。NOPの分解能を上げるためシステムクロックを最大にするためPLLを使用します。System Clock SelectをFOSCを指定しIntemal Clockを8MHz_HFを指定します。PLL Enabledにチェックを入れるとPLLが動作しSystem Clockが32MHzになります。
TMR0を設定する
TMR0はDevice Resources内のPeripherals欄のTimerを選択しTMR0をクリックして追加します。

Timer Clock内でクロックに関する設定を行います。Clock Sourceは内部クロックを使用しているためFOSC(FOSC/4)を指定します。PrescalerはClock Sourceに対してTMR0のカウントアップする分周比を指定します。
Timer PeriodはTMR0がオーバーフローするタイミングを設定します。1ms毎にオーバーフロー割り込みが発生しますがCallback Function Rateを0x0A(10)を指定しているため10ms毎にコールバック関数が呼び出されます。
void mainTimer(void); //タイマー0割り込みのコールバック関数
//コールバック関数の使用例
TMR0_SetInterruptHandler(mainTimer); //コールバック関数を指定
上記例ではmainTimer()が10ms毎にコールされます。
MSSP1(I2C)の設定

System Clockを32MHzに変更した場合初期の100kHzではLCDが動作しなかったためLCD用のI2Cのクロックを下げて使用します。最低の周波数より少し高い40KHzに変更しています。50kHz以上になるとLCDが反応しなくなったためクロックの速度の影響が出ていると判断しています。
MCCが生成した関数の使用例
IO_RA0_SetHigh();//DOをHIGH
IO_RA0_SetLow();//DOをLOW
IO_RA0_SetHigh()関数はRA0のDO出力をHighにします。IO_RA0_SetLow()関数はRA0のDO出力をLowにします。他のポートのDOの場合はRA0の部分が対象のポート名になります。Header Files内のpin_manager.h内で#defineで定義されています。
//I2Cの例
#include "mcc_generated_files/examples/i2c1_master_example.h"
for( i = 0; i < LINE_MAX; i++ ){
I2C1_Write1ByteRegister(SLAVE_ADRS,LINE1_ADRS,line2[i]);
}
I2Cのサンプル関数を使用するために別途「mcc_generated_files/examples/i2c1_master_example.h”」をインクルードする必要があります。
I2C1_Write1ByteRegister()関数は1バイトずつスレーブにデータを送る場合に使用します。第1引数にスレーブアドレスを指定します。第2引数にレジスタのアドレスを指定します。第3引数に送信するデータを指定します。
複数のバイトを送信するI2C1_WriteNBytes()関数も実装されているため用途によって使い分けることができます。
PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!
動作確認

PIC16F1827のRA0とPL9823のDINを接続します。データシートには外付けの部品不要と記載がありますが回路例では抵抗が実装されています。回路例では電流制限する抵抗を実装しています。
電源をONするとLCDの1段目に「RGB LED-TEST」、2段目に「R 0 G 0 B 0」を表示します。初期化時に一瞬PL9823が点灯することがありますが、初期化時にすべて0 codeとするので消灯します。
SW1は選択中の色のカウントを+1し、SW2はカウントを-1します。SW1とSW2は長押しするとカウント値が自動でアップダウンするようにしています。SW3は色の選択です。Rは赤、Gは緑、Bは青であり選択した色のカーソルがブリンク(点滅)するようにしています。
SW3で色を選択してSW1とSW2で光の3原色を調節して任意の色でRGB LEDを点灯させて動作確認を行いました。

青と緑を調整して水色の点灯パターンを作ることができました。赤と緑を調整して黄色の点灯パターンを作ることができました。赤と青を調整して紫色の点灯パターンを作ることができました。
1kΩの抵抗を実装すると赤色が強く出てる傾向がありました。赤255、緑255、青255にしても赤の発光が強いため赤色にしか見えなくなってしまいました。今回の動作確認の条件では赤127程度が他の色に対して丁度良い調整具合でした。PIC16F1827のピン配置は以下の通りです。

PB0はINPUTでウィークプルアップ(WPU)設定しています。WPUを有効にするためにはRegistersのnWPUENをenabledにする必要があります。
Easy SetupでWPUにチェックするのみでは有効にならないので注意が必要です。Notificationsにワーニングで通知されます。
抵抗を実装しなかった場合はバランスよく点灯するためどうしても色味が気になる場合は抵抗せずに動作させてもよいと思います。データシートの回路例で抵抗が実装されていますが推奨の抵抗値などの記載がないため色味に応じて判断する必要があります。
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。
main.cをコピーすると使用できます。本ソースコードはMPLAB X IDEにMCCのプラグインをインストールしていることが前提となります。MCCをインストールする方法は下記記事を参考にしてください。
MPLAB Code Configurator(MCC)の追加と使い方
関連リンク
PICマイコンを使ってマイコンのレジスタの設定やMPLAB X IDEのプラグインであるMCCを使用して動作確認したことについてまとめています。
PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ
PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ
最後まで、読んでいただきありがとうございました。