タミヤ1/24 ニスモR34 GT-R Z-tune 電飾編製作3 [PICマイコンのプログラム]

 タミヤ1/24 ニスモR34 GT-R Z-tune 製作3 [PICマイコンのプログラム]

前回はシャーシの加工をしました。



今回はPICマイコンのプログラムを書きます。

プログラム

PICマイコンのプログラムは今回の電飾の要です。

とはいえ特に難しいことはしていないと思います。


機能として
  • 各種ライトの点灯、消灯
  • ロー、ハイ、フォグ、テールのみPWMで光量を調節
  • ウインカーの点滅
  • 赤外線リモコンで操作
を組み込みます。

使用するPICマイコンはPICマイコンの定番(らしい)16F1827のSSOPパッケージ版です。

比較画像ですが、一般的(?)なDIPパッケージと比べても非常に小さいことが分かります。



模型の電飾をする上で小ささは武器です。
これは前回のスープラでの失敗で痛感しました…

もちろん小さすぎてはんだごてで扱えなければどうにもなりませんが、SSOPまでなら配線も出来ます。

長所は上記の通り。

短所は通常のPICマイコン書き込み機がそのままでは使えないので変換アダプタ(約\1800)を噛まさないといけません。


とはいえ初期投資がかさむだけで用意すれば壊れない限りずっとつかえます。


話が逸れましたがいよいよプログラムの話に入ります。

※プログラミングに関してド素人です。
公開したプログラムを使用したことによる事故等のいかなる責任も負いません。

まずはコンフィグから
コンフィグとピン設定などはMCCを利用しています。
  // CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF    // Watchdog Timer Enable->WDT disabled
#pragma config PWRTE = OFF    // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF    // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF    // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF    // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = OFF    // Brown-out Reset Enable->Brown-out Reset disabled
#pragma config CLKOUTEN = OFF    // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = ON    // Internal/External Switchover->Internal/External Switchover mode is enabled
#pragma config FCMEN = ON    // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled

// CONFIG2
#pragma config WRT = OFF    // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = OFF    // PLL Enable->4x PLL disabled
#pragma config STVREN = ON    // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config BORV = LO    // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF    // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
  

つづいてファイルのインクルードとディレイ用の周波数定義、各種変数の定義です。

#include <xc.h>
#include <stdbool.h>
#include <pic16f1827.h>
#define _XTAL_FREQ 16000000

void    __interrupt () isr (void); //割り込み関数プロトタイプ宣言
int a,b,c,d,e,f; //リモコン2進数用変数
bool lowb,highb,pos,brake,winkerL,winkerR,plate; //各電飾用フラグ
int Lpwm,Hpwm,Ppwm,Bpwm; //PWM用変数
void Lup(void);
void Ldown(void);
void Hup(void);
void Hdown(void);
void Pup(void);
void Pdown(void);
void Bup(void);
void Bdown(void);
  
つづいてピン設定とメインのプログラムです。

void main(void) {
    // SCS INTOSC; SPLLEN disabled; IRCF 16MHz_HF; 
    OSCCON = 0x7A;
    // TUN 0; 
    OSCTUNE = 0x00;
    // SBOREN disabled; 
    BORCON = 0x00;
    // WDTPS 1:65536; SWDTEN OFF; 
    WDTCON = 0x16;
    
    LATA = 0x00;
    LATB = 0x00;
    TRISA = 0x00;
    TRISB = 0x01;
    ANSELB = 0x00;
    ANSELA = 0x00;
    WPUB = 0x00;
    WPUA = 0x00;
    OPTION_REGbits.nWPUEN = 1;
    APFCON0 = 0x00;
    APFCON1 = 0x00;
    
    //Timer2設定
    // PR2 255; 
    PR2 = 0xFF;
    // TMR2 0; 
    TMR2 = 0x00;
    // Clearing IF flag.
    PIR1bits.TMR2IF = 0;
    // T2CKPS 1:1; T2OUTPS 1:1; TMR2ON on; 
    T2CON = 0x04;
    
    //PWM設定
    //RB3 10ピン ポジションランプ
    CCP1CON = 0x3C;    
    ECCP1AS = 0x00;    
    PWM1CON = 0x80;    
    PSTR1CON = 0x01;    
    CCPR1H = 0x00;    
    CCPR1L = 0x7F;
    CCPTMRS0bits.C1TSEL = 0x0;
    
    //RB6 13ピン ブレーキ
    CCP2CON = 0x3C;    
    ECCP2AS = 0x00;    
    PWM2CON = 0x80;    
    PSTR2CON = 0x01;    
    CCPR2H = 0x00;    
    CCPR2L = 0x7F;
    CCPTMRS0bits.C2TSEL = 0x0;
    
    //RA3 2ピン ロービーム
    CCP3CON = 0x3C;    
    CCPR3L = 0x7F;    
    CCPR3H = 0x00;
    CCPTMRS0bits.C3TSEL = 0x0;
    
    //RA4 3ピン ハイビーム
    CCP4CON = 0x3C;    
    CCPR4L = 0x7F;    
    CCPR4H = 0x00;
    CCPTMRS0bits.C4TSEL = 0x0;
    
    // 割込み設定
    INTCONbits.GIE = 1; //全体割込み許可
    INTCONbits.INTE = 1; //RB0外部割込みオン
    INTCONbits.INTF = 0; //外部割込みフラグ0
    OPTION_REGbits.INTEDG = 0; //立下りを検出
    
    a=0;b=0;c=0;d=0;e=0;f=0;
    lowb=1;highb=0;pos=1;brake=1;winkerL=0;winkerR=0;plate=1;
    Lpwm=50;Hpwm=50;Ppwm=50;Bpwm=50;
    
    //メインプログラム
    
    while(1){
        //ロービーム 
        if(lowb == 1){
            CCP3CON = 0x3C;
        }
        else{
            CCP3CON = 0x00;
            RA3 = 0;
        }
        
        //ハイビーム
        if(highb == 1){
            CCP4CON = 0x3C;
        }
        else{
            CCP4CON = 0x00;
            RA4 = 0;
        }
        
        //ポジションランプ
        if(pos == 1){
            CCP1CON = 0x3C;
        }
        else{
            CCP1CON = 0x00;
            RB3 = 0;
        }
        
        //ブレーキ
        if(brake == 1){
            CCP2CON = 0x3C;
        }
        else{
            CCP2CON = 0x00;
            RB6 = 0;
        }
        
        //ナンバー灯
        if(plate == 1){
            RB4 = 1;
        }
        else{
            RB4 = 0;
        }
        
        //ウインカー
        //左のみ
        if(winkerL == 1 && winkerR == 0){
            RA1 = 1;
            RA7 = 0;
            __delay_ms(330);
            RA1 = 0;
            RA7 = 0;
            __delay_ms(330);
        }
        //右のみ
        if(winkerL == 0 && winkerR == 1){
            RA1 = 0;
            RA7 = 1;
            __delay_ms(330);
            RA1 = 0;
            RA7 = 0;
            __delay_ms(330);
        }
        //左右(ハザード)
        if(winkerL == 1 && winkerR == 1){
            RA1 = 1;
            RA7 = 1;
            __delay_ms(330);
            RA1 = 0;
            RA7 = 0;
            __delay_ms(330);
        }
        //ウインカーオフ
        if(winkerL == 0 && winkerR == 0){
            RA1 = 0;
            RA7 = 0;
        }
    } //while
} //main

つづいて割り込み関数です。

//割り込み処理(リモコン受信)
void    __interrupt () isr (void){
    INTCONbits.GIE = 0; //全体割り込み不許可
    INTCONbits.INTE = 0; //外部割り込み不許可
    
    while(INTF == 1){
        a=0;b=0;c=0;d=0;e=0;f=0;//2進数用データ
        
        if(RB0 == 0) //スタートビット検出
            __delay_us(300);
        else break; //検出できなかった場合割り込み終了
        
        if(RB0 == 0) //スタートビット確認
            __delay_us(600);
        else break;
        
        //ここから2進数解析

        if(RB0 == 0) //受信する2進数1ケタ目
            b = 1; //1なら1を代入
        __delay_us(600);
        
        if(RB0 == 0) //受信する2進数2ケタ目
            c = 5; //1なら5を代入
        __delay_us(600);
        
        if(RB0 == 0) //受信する2進数3ケタ目
            d = 10; //1なら10を代入
        __delay_us(600);
        
        if(RB0 == 0) //受信する2進数4ケタ目
            e = 20; //1なら20を代入
        __delay_us(600);
        
        if(RB0 == 0) //受信する2進数5ケタ目
            f = 50; //1なら50を代入
        __delay_us(600);
        
        //2進数解析ここまで
        //ここからストップビット
        
        if(RB0 == 0) //ストップビット1
            __delay_us(600);
        else break; //検出できなかった場合は割り込み終了
        
        if(RB0 == 1)//ストップビット0
            __delay_us(600);
        else break;
        
        if(RB0 == 0) //ストップビット1
            __delay_us(600);
        else break;
        
        if(RB0 == 1)//ストップビット0
            __delay_us(600);
        else break;

        if(RB0 == 0) //ストップビット1 
        a=b+c+d+e+f; //受信した2進数の代入値を合計
        else break;
        
        //ロービームオンオフ
        if(a == 51){
            lowb = !lowb;
        }
        //ロービーム光量アップ
        if(a == 21){
            Lup();
        }
        //ロービーム光量ダウン
        if(a == 11){
            Ldown();
        }
        
        //ハイビームオンオフ
        if(a == 5){
            highb = !highb;
        }
        //光量アップ
        if(a == 10){
            Hup();
        }
        //光量ダウン
        if(a == 20){
            Hdown();
        }
        
        //ポジションランプオンオフ
        if(a == 15){
            pos = !pos;
        }
        //光量アップ
        if(a == 30){
            Pup();
        }
        //光量ダウン
        if(a == 70){
            Pdown();
        }
        
        //ブレーキオンオフ
        if(a == 25){
            brake = !brake;
        }
        //光量アップ
        if(a == 76){
            Bup();
        }
        //光量ダウン
        if(a == 56){
            Bdown();
        }
        
        //ナンバー灯オンオフ
        if(a == 66){
            plate = !plate;
        }
        //右ウインカーオンオフ
        if(a == 61){
            winkerR = !winkerR;
        }
        //左ウインカーオンオフ
        if(a == 50){
            winkerL = !winkerL;
        }
        
        //全てオフ
        if(a == 6){
            if(lowb==1 || highb==1 || brake==1 || pos==1 || winkerL==1 || winkerR==1 || plate==1){
                lowb = 0;
                highb = 0;
                brake = 0;
                pos = 0;
                winkerL = 0;
                winkerR = 0;
                plate = 0;
            }
            else if(lowb==0 && highb==0 && brake==0 && pos==0 && winkerL==0 && winkerR==0 && plate==0){
                lowb = 1;
                brake = 1;
                pos = 1;
                plate = 1;
            }
        }
        
        break;
    } //while
    
    INTCONbits.INTF = 0; //フラグをゼロクリア
    INTCONbits.GIE = 1; //全体割り込み許可
    INTCONbits.INTE = 1; //外部割込み許可
    
} //INT

つづいて光量調整用PWMのデューティー比変更関数です。

void Lup(){
    if(Lpwm<100){
        Lpwm += 10;
        switch(Lpwm){
            case 10:
                CCPR3L = 0x19;
                break;
            case 20:
                CCPR3L = 0x33;
                break;
            case 30:
                CCPR3L = 0x4C;
                break;
            case 40:
                CCPR3L = 0x66;
                break;
            case 50:
                CCPR3L = 0x7F;
                break;
            case 60:
                CCPR3L = 0x99;
                break;
            case 70:
                CCPR3L = 0xB2;
                break;
            case 80:
                CCPR3L = 0xCC;
                break;
            case 90:
                CCPR3L = 0xE5;
                break;
            case 100:
                CCPR3L = 0xFF;
                break;
        } //switch
    } //if
} //Lup

void Ldown(){
    if(Lpwm>10){
        Lpwm -= 10;
        switch(Lpwm){
            case 10:
                CCPR3L = 0x19;
                break;
            case 20:
                CCPR3L = 0x33;
                break;
            case 30:
                CCPR3L = 0x4C;
                break;
            case 40:
                CCPR3L = 0x66;
                break;
            case 50:
                CCPR3L = 0x7F;
                break;
            case 60:
                CCPR3L = 0x99;
                break;
            case 70:
                CCPR3L = 0xB2;
                break;
            case 80:
                CCPR3L = 0xCC;
                break;
            case 90:
                CCPR3L = 0xE5;
                break;
            case 100:
                CCPR3L = 0xFF;
                break;
        } //switch
    } //if
} //Ldown

void Hup(){
    if(Hpwm<100){
        Hpwm += 10;
        switch(Hpwm){
            case 10:
                CCPR4L = 0x19;
                break;
            case 20:
                CCPR4L = 0x33;
                break;
            case 30:
                CCPR4L = 0x4C;
                break;
            case 40:
                CCPR4L = 0x66;
                break;
            case 50:
                CCPR4L = 0x7F;
                break;
            case 60:
                CCPR4L = 0x99;
                break;
            case 70:
                CCPR4L = 0xB2;
                break;
            case 80:
                CCPR4L = 0xCC;
                break;
            case 90:
                CCPR4L = 0xE5;
                break;
            case 100:
                CCPR4L = 0xFF;
                break;
        } //switch
    } //if
} //Hup

void Hdown(){
    if(Hpwm>10){
        Hpwm -= 10;
        switch(Hpwm){
            case 10:
                CCPR4L = 0x19;
                break;
            case 20:
                CCPR4L = 0x33;
                break;
            case 30:
                CCPR4L = 0x4C;
                break;
            case 40:
                CCPR4L = 0x66;
                break;
            case 50:
                CCPR4L = 0x7F;
                break;
            case 60:
                CCPR4L = 0x99;
                break;
            case 70:
                CCPR4L = 0xB2;
                break;
            case 80:
                CCPR4L = 0xCC;
                break;
            case 90:
                CCPR4L = 0xE5;
                break;
            case 100:
                CCPR4L = 0xFF;
                break;
        } //switch
    } //if
} //Hdown

void Pup(){
    if(Ppwm<100){
        Ppwm += 10;
        switch(Ppwm){
            case 10:
                CCPR1L = 0x19;
                break;
            case 20:
                CCPR1L = 0x33;
                break;
            case 30:
                CCPR1L = 0x4C;
                break;
            case 40:
                CCPR1L = 0x66;
                break;
            case 50:
                CCPR1L = 0x7F;
                break;
            case 60:
                CCPR1L = 0x99;
                break;
            case 70:
                CCPR1L = 0xB2;
                break;
            case 80:
                CCPR1L = 0xCC;
                break;
            case 90:
                CCPR1L = 0xE5;
                break;
            case 100:
                CCPR1L = 0xFF;
                break;
        } //switch
    } //if
} //Pup

void Pdown(){
    if(Ppwm>10){
        Ppwm -= 10;
        switch(Ppwm){
            case 10:
                CCPR1L = 0x19;
                break;
            case 20:
                CCPR1L = 0x33;
                break;
            case 30:
                CCPR1L = 0x4C;
                break;
            case 40:
                CCPR1L = 0x66;
                break;
            case 50:
                CCPR1L = 0x7F;
                break;
            case 60:
                CCPR1L = 0x99;
                break;
            case 70:
                CCPR1L = 0xB2;
                break;
            case 80:
                CCPR1L = 0xCC;
                break;
            case 90:
                CCPR1L = 0xE5;
                break;
            case 100:
                CCPR1L = 0xFF;
                break;
        } //switch
    } //if
} //Pdown

void Bup(){
    if(Bpwm<100){
        Bpwm += 10;
        switch(Bpwm){
            case 10:
                CCPR2L = 0x19;
                break;
            case 20:
                CCPR2L = 0x33;
                break;
            case 30:
                CCPR2L = 0x4C;
                break;
            case 40:
                CCPR2L = 0x66;
                break;
            case 50:
                CCPR2L = 0x7F;
                break;
            case 60:
                CCPR2L = 0x99;
                break;
            case 70:
                CCPR2L = 0xB2;
                break;
            case 80:
                CCPR2L = 0xCC;
                break;
            case 90:
                CCPR2L = 0xE5;
                break;
            case 100:
                CCPR2L = 0xFF;
                break;
        } //switch
    } //if
} //Bup

void Bdown(){
    if(Bpwm>10){
        Bpwm -= 10;
        switch(Bpwm){
            case 10:
                CCPR2L = 0x19;
                break;
            case 20:
                CCPR2L = 0x33;
                break;
            case 30:
                CCPR2L = 0x4C;
                break;
            case 40:
                CCPR2L = 0x66;
                break;
            case 50:
                CCPR2L = 0x7F;
                break;
            case 60:
                CCPR2L = 0x99;
                break;
            case 70:
                CCPR2L = 0xB2;
                break;
            case 80:
                CCPR2L = 0xCC;
                break;
            case 90:
                CCPR2L = 0xE5;
                break;
            case 100:
                CCPR2L = 0xFF;
                break;
        } //switch
    } //if
} //Bdown

はい、以上で今回作ったプログラムは以上です。

恐らくもっとシンプルにまとめ上げることは出来るのでしょうが、今の自分にはこれが精いっぱい…ですが求めている動作をしてくれるので良しとします。


このプログラムについての簡単な解説ですが、それぞれのライトのオンオフは0,1のフラグで管理。

赤外線リモコンのデータを受信することで対象のフラグを切り替え。
PWMが含まれるので複雑に見えますが中身はシンプルです。


なお、赤外線受信の処理は自作の赤外線リモコンに合わせて作っています。
自作の赤外線リモコンについてもどこかでご紹介する予定です。


ということで今回は以上です。
では


0 件のコメント :

コメントを投稿