PICマイコン(PIC16F1827)でRGB LEDの色を調整

組み込みエンジニア
本記事はプロモーションが含まれています。

こんにちは、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を操作する

引用:PL9823のデータシート Timing waveform
引用:PL9823のデータシート Timing waveform

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で待機させてタイミング波形を生成します。

NOPは1命令分(動作クロック1パルス)処理せず待機させるものです。例えば動作クロックが1MHz(1us)の場合は1us間何も処理せず待機する動作になります。

広告

タイミング波形を生成と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()関数を指定しています。

スポンサーリンク

使用例では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()は登録した関数がコールされるため制御値に応じたタイミング波形を送出することができます。

各ビット間でSet0code()関数もしくはSet1code()関数に遷移するための命令処理によって若干の遅延が出ますが1us程度であり問題なく処理することができます。

広告

MCCの設定

PIC16F1827の設定はMCCを使っています。MCCの使い方については下記記事にまとめています。

MPLAB Code Configurator(MCC)の追加と使い方

今回はMCCを使用してSystem clock、TMR0、MSSP1の設定を行っています。

System Moduleの設定

最初に共通事項であるSystem Moduleの設定を行います。MPLAB X IDEを起動しMCCのアイコンをクリックしてMCCを有効にします。

System Moduleの設定(MCC)
System Moduleの設定(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をクリックして追加します。

TMR0の設定(MCC)
TMR0の設定(MCC)

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)の設定

MSSP1の設定
MSSP1の設定

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()関数も実装されているため用途によって使い分けることができます。

スポンサーリンク

動作確認

PL9823の動作確認回路
PL9823の動作確認回路

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のピン配置は以下の通りです。

PIC16F1827のピン設定(MCC)
PIC16F1827のピン設定(MCC)

PB0はINPUTでウィークプルアップ(WPU)設定しています。WPUを有効にするためにはRegistersのnWPUENをenabledにする必要があります。

Easy SetupでWPUにチェックするのみでは有効にならないので注意が必要です。Notificationsにワーニングで通知されます。

抵抗を実装しなかった場合はバランスよく点灯するためどうしても色味が気になる場合は抵抗せずに動作させてもよいと思います。データシートの回路例で抵抗が実装されていますが推奨の抵抗値などの記載がないため色味に応じて判断する必要があります。

PR:スキマ時間を有効に!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"

#define TIME_OFF -1     //タイマーを使用しない場合
#define TIME_UP 0       //タイムアップ
#define LED_FL 10
#define TIME_FILTER_MAX 1    //ベースタイマカウント値
#define DI_FILT_MAX 4            //DIフィルタのサンプリング数
#define DI_MAX 3
#define	CNT_INIT_MAX 10     //10ms×10 = 100ms
#define BTN_ON_KEEP  20
#define RED_LIMID 128

#define SLAVE_ADRS 0x3E//0x3E 0x7C
#define LINE1_ADRS 0x40
#define LINE2_TOP (0x40 +0x80)
#define FUNC1_SET 0x38
#define FUNC2_SET 0x39
#define INT_OSC 0x14
#define CONST_SET 0x77 //0x73
#define PWR_ICON_SET 0x54 //0x56
#define FOLLOWER_SET 0x6C
#define CLR_DISP 0x01
#define DISP_ONOFF_SET 0x0D
#define LINE_MAX 16

typedef enum{
    LED_R = 0,
    LED_G,
    LED_B,
    LED_MAX        
}LED_MODE_NO;

typedef struct{
    void (*red7)(void);
    void (*red6)(void);
    void (*red5)(void);
    void (*red4)(void);
    void (*red3)(void);
    void (*red2)(void);
    void (*red1)(void);
    void (*red0)(void);
    void (*green7)(void);
    void (*green6)(void);
    void (*green5)(void);
    void (*green4)(void);
    void (*green3)(void);
    void (*green2)(void);
    void (*green1)(void);
    void (*green0)(void);    
    void (*blue7)(void);
    void (*blue6)(void);
    void (*blue5)(void);
    void (*blue4)(void);
    void (*blue3)(void);
    void (*blue2)(void);
    void (*blue1)(void);
    void (*blue0)(void);         
}FUNC_SET;

typedef struct{
    uint8_t wp;
    uint8_t buf[DI_MAX][DI_FILT_MAX];
    uint8_t di[DI_MAX];
}DIFILT_TYP;

uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t colormd;
bool cntflg;
bool btnflg[DI_MAX];
int16_t timLed= LED_FL;
int16_t timdifilt;   //DIフィルタ起動
int16_t timbtnkeep[DI_MAX];
uint8_t CntInit;	//初期化時のみ使用
DIFILT_TYP difilt;
FUNC_SET led;
uint8_t initmoji[2][16] ={"RGB LED-TEST    ","         Ver1.00"};

/* プロトタイプ宣言*/
void mainApp(void);
void mainTimer(void);
void makeWavePattern(void);
void makeNpWave(void);
void WaveStart(void);
void Set1code(void);
void Set0code(void);
void DiFilter(void);
void BtnCnt(uint8_t md, bool plus);
void LcdInit(void);
void DspLine2Top(void);
void DspLine2TopCursor(uint8_t no);
void DspClear(void);
void DispSet(void);

/* Main application */
void main(void)
{
    SYSTEM_Initialize();
    TMR0_SetInterruptHandler(mainTimer);
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    
    CntInit = CNT_INIT_MAX;
    while(CntInit > 0){  //0になるまでフィルタを実施
        DiFilter();         //DIフィルタ処理
        __delay_ms(10);     //10ms遅延させてDIフィルタ処理
        CntInit--;
        timdifilt = TIME_UP;
   }
    
    LcdInit();

    red=0;
    green=0;
    blue=0;
    cntflg = true;
    
    while (1)
    {
        DiFilter();
        mainApp();
    }
}
/* TMR0オーバーフロー割り込みでの処理  */
/* タイマ管理関数 */
void mainTimer(void){
    uint8_t i;
    
    if( timLed > TIME_UP ){
      timLed--;
    }
    if( timdifilt > TIME_UP ){
      timdifilt--;
    }
    
    for(i=0;i<DI_MAX;i++){
        if( timbtnkeep[i] > TIME_UP ){
            timbtnkeep[i]--;
        }
    }
}
/* メイン処理 */
void mainApp(void){
    uint8_t i;
    
    if( timLed == TIME_UP){
        timLed = LED_FL;
        if(cntflg){
            cntflg = false;
            makeWavePattern();
            WaveStart();
            DispSet();
        }
        DspLine2TopCursor(colormd);
    }
    
    for(i=0; i < DI_MAX; i++){
        if( difilt.di[i] == 0){
            if( btnflg[i] == false ){
                btnflg[i] = true;
                timbtnkeep[i] = BTN_ON_KEEP;
                
                switch(i){
                    case 0:
                        BtnCnt(colormd,true);
                        cntflg = true;
                        break;
                    case 1:
                        BtnCnt(colormd,false);
                        cntflg = true;
                        break;
                    case 2:
                        if(++colormd >=LED_MAX){
                            colormd = LED_R;
                        }
                        break;
                }
            }
            else{
                if(timbtnkeep[i] == TIME_UP){
                    timbtnkeep[i] = BTN_ON_KEEP;
                    
                    switch(i){
                        case 0:
                            BtnCnt(colormd,true);
                            cntflg = true;
                            break;
                        case 1:
                            BtnCnt(colormd,false);
                            cntflg = true;
                            break;
                    }
                }
            }
        }
        else{
            btnflg[i] = false;
            timbtnkeep[i] = TIME_OFF;
        }
    }
}
/* LEDパターン生成*/
void makeWavePattern(void){
    //赤のパターン(関数登録)
    (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);
    //緑のパターン(関数登録)
    (green & 0x80) ? (led.green7 = Set1code) : (led.green7 = Set0code);
    (green & 0x40) ? (led.green6 = Set1code) : (led.green6 = Set0code);
    (green & 0x20) ? (led.green5 = Set1code) : (led.green5 = Set0code);
    (green & 0x10) ? (led.green4 = Set1code) : (led.green4 = Set0code);
    (green & 0x08) ? (led.green3 = Set1code) : (led.green3 = Set0code);
    (green & 0x04) ? (led.green2 = Set1code) : (led.green2 = Set0code);     
    (green & 0x02) ? (led.green1 = Set1code) : (led.green1 = Set0code);
    (green & 0x01) ? (led.green0 = Set1code) : (led.green0 = Set0code);
    //青のパターン(関数登録)
    (blue & 0x80) ? (led.blue7 = Set1code) : (led.blue7 = Set0code);
    (blue & 0x40) ? (led.blue6 = Set1code) : (led.blue6 = Set0code);
    (blue & 0x20) ? (led.blue5 = Set1code) : (led.blue5 = Set0code);
    (blue & 0x10) ? (led.blue4 = Set1code) : (led.blue4 = Set0code);
    (blue & 0x08) ? (led.blue3 = Set1code) : (led.blue3 = Set0code);
    (blue & 0x04) ? (led.blue2 = Set1code) : (led.blue2 = Set0code);     
    (blue & 0x02) ? (led.blue1 = Set1code) : (led.blue1 = Set0code);
    (blue & 0x01) ? (led.blue0 = Set1code) : (led.blue0 = Set0code);
}

/* タイミング波形の送信*/
void WaveStart(void){
    //赤のパターン
    led.red7();
    led.red6();
    led.red5();
    led.red4();
    led.red3();
    led.red2();
    led.red1();
    led.red0();
    //緑のパターン
    led.green7();
    led.green6();
    led.green5();
    led.green4();
    led.green3();
    led.green2();
    led.green1();
    led.green0();
    //青のパターン
    led.blue7();
    led.blue6();
    led.blue5();
    led.blue4();
    led.blue3();
    led.blue2();
    led.blue1();
    led.blue0();    
}
/* ボタンによる値の更新 */
void BtnCnt(uint8_t md, bool plus){
    
    switch(md){
        case LED_R:
            if(plus){
                ++red;
            }
            else{
                --red;
            }
            break;
        case LED_G:
            if(plus){
                ++green;
            }
            else{
                --green;
            }           
            break;
        case LED_B:
            if(plus){
                ++blue;
            }
            else{
                --blue;
            }                   
            break;
    }
}
/* DiFilter function add */
void DiFilter(void){
    uint8_t i;

    if( timdifilt == TIME_UP ){
        timdifilt = TIME_FILTER_MAX;
        difilt.buf[0][difilt.wp] = IO_RB0_GetValue();
        difilt.buf[1][difilt.wp] = IO_RB2_GetValue();
        difilt.buf[2][difilt.wp] = IO_RB3_GetValue();
        
        for(i=0; i < DI_MAX; i++){
            if( difilt.buf[i][0] == difilt.buf[i][1] &&
            difilt.buf[i][1] == difilt.buf[i][2] &&
            difilt.buf[i][2] == difilt.buf[i][3] ){ //4回一致を確認
            difilt.di[i] = difilt.buf[i][0];
            }
        }

        if( ++difilt.wp >= DI_FILT_MAX ){
          difilt.wp = 0;
        }
    }
}
/* 1 code のタイミング */
void Set1code(void){
    //1 codeの例
    IO_RA0_SetHigh();//DOをHIGH
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    IO_RA0_SetLow();//DOをLOW
    NOP();
}
/* 0 code のタイミング */
void Set0code(void){
    //0 codeの例
    IO_RA0_SetHigh();//DOをHIGH
    NOP();
    IO_RA0_SetLow();//DOをLOW
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
 
}
/* LCDの初期化 */
void LcdInit(void){
    uint8_t i;
    
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, FUNC1_SET ); //8ビットバス・2LINE表示
    __delay_us(40);
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, FUNC2_SET ); //拡張コマンド
    __delay_us(40);
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, INT_OSC ); //内部周波数調整
    __delay_us(40);    
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, CONST_SET ); //コントラスト1
    __delay_us(40);    
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, PWR_ICON_SET );//コントラスト2
    __delay_us(40);   
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, FOLLOWER_SET );//フォロワー制御
    __delay_ms(250);
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, FUNC1_SET ); //拡張コマンドをオフ
    __delay_us(40);
    
    DspClear();
    
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, DISP_ONOFF_SET );
    __delay_us(40);
    
    for( i = 0; i < sizeof(initmoji[0]); i++ ){
        I2C1_Write1ByteRegister(SLAVE_ADRS,LINE1_ADRS,initmoji[0][i]);
    }  
    
    //I2C1_WriteNBytes( SLAVE_ADRS,&initmoji[0][0], sizeof(initmoji[0]));
    //DspLine2Top();

    //for( i = 0; i < sizeof(initmoji[1]); i++ ){
    //    I2C1_Write1ByteRegister(SLAVE_ADRS,LINE1_ADRS,initmoji[1][i]);
    //}        
    //__delay_ms(2000);
}
    
/* LCDの表示を2段目にセット */
void DspLine2Top(void){
    
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, LINE2_TOP );
    __delay_us(40);    
}
/* LCDの表示をクリア */
void DspClear(void){
  
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, CLR_DISP );
    __delay_us(40);
}
/* カーソルの移動 */
void DspLine2TopCursor(uint8_t no){
    
    I2C1_Write1ByteRegister(SLAVE_ADRS, 0x00, LINE2_TOP + no * 5 );
   __delay_us(40);

}
/* DispSet function add */
void DispSet(void){
    uint8_t i;
    uint8_t line2[LINE_MAX];
    uint8_t r_100;
    uint8_t r_10;
    uint8_t r_1;
    uint8_t g_100;
    uint8_t g_10;
    uint8_t g_1;
    uint8_t b_100;
    uint8_t b_10;
    uint8_t b_1;    
    //0x30を加えて文字コードの0から9を生成
    r_100 = (red /100) + 0x30;
    r_10 = ((red % 100) / 10) +0x30;
    r_1 = ((red % 100) % 10) + 0x30;
    g_100 = (green /100) + 0x30;
    g_10 = ((green % 100) / 10) + 0x30;
    g_1 = ((green % 100) % 10) + 0x30;    
    b_100 = ( blue /100) + 0x30;
    b_10 = ((blue % 100) / 10) +0x30;
    b_1 = ((blue % 100) % 10) +0x30;
    
    if(r_100 == '0'){
        r_100 = ' ';
        if(r_10 =='0'){
            r_10 = ' ';
        }
    }
    if(g_100 == '0'){
        g_100 = ' ';
        if(g_10 =='0'){
            g_10 = ' ';
        }
    }    
    if(b_100 == '0'){
        b_100 = ' ';
        if(b_10 =='0'){
            b_10 = ' ';
        }
    }    
    
    line2[0] = 'R';
    line2[1] = r_100;
    line2[2] = r_10;
    line2[3] = r_1;
    line2[4] = ' ';
    line2[5] = 'G';
    line2[6] = g_100;
    line2[7] = g_10;
    line2[8] = g_1;
    line2[9] = ' ';    
    line2[10] = 'B';
    line2[11] = b_100;
    line2[12] = b_10;
    line2[13] = b_1;
    line2[14] = ' ';    
    line2[15] = ' ';    
    
    DspLine2Top();
    //sprintfを使いたいが容量オーバーになるのでコメントアウト
    //sprintf((char*)line2, "R%3d G%3d B%3d  ", red, green,blue);
    
    for( i = 0; i < LINE_MAX; i++ ){
        I2C1_Write1ByteRegister(SLAVE_ADRS,LINE1_ADRS,line2[i]);
    } 
}
/* End of File */

本ソースコードはMPLAB X IDEにMCCのプラグインをインストールしていることが前提となります。MCCをインストールする方法は下記記事を参考にしてください。

MPLAB Code Configurator(MCC)の追加と使い方

関連リンク

PICマイコンを使ってマイコンのレジスタの設定やMPLAB X IDEのプラグインであるMCCを使用して動作確認したことについてまとめています。

PICマイコン(PIC12F675)で実現できる機能と解説リンクまとめ

PICマイコン(PIC16F1827)で実現できる機能と解説リンクまとめ

広告

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました