PIC16F1938 PWM調光の作り方(ロータリスイッチ入力)

PICの基礎

 

今回はPIC16F1938を使い、
10進ロータリスイッチ入力からPWM調光を作りました。
この記事では、回路図、コード、オシロ波形、
ハマったポイントをまとめています。

ロータリスイッチは、うちの会社でもよく使うスイッチなので、
しっかり使えるようになっておきたいとは思っていました。

前回、PIC16F1938でADC入力からPWM調光を作る方法【LEDをボリューム制御】ボリュームでの調光には成功したので、
このタイミングでロータリスイッチの入力から、
PWMの段階的な出力を作りました。

ロータリスイッチの4bit出力をそのまま読み、
0~9の値をPWMデューティに変換しました。

結果的にはきれいに10等分の調光を作ることができましたが、
今回もなかなか罠にハマってしまいました。

 

①今回の回路図

A6A-10R(下図)という
0~9までの10段階のロータリスイッチを使用しました。

このスイッチの出力コードは

1248
0
1
2
3
4
5
6
7
8
9

となっています。
例えば、ロータリスイッチのポジションが
”7”
の場合、上の回路図の接続だと、
1,2,4pin
から5Vが出力されるという仕組みです。

 

②今回のコード

今回は次のようなコードを書き込みます。

ポイントは、ロータリスイッチの4bit出力をそのまま読み、
PWM dutyに変換しているところです。

c

#include <xc.h>
#pragma config FOSC = INTOSC
#pragma config PWRTE = OFF
#pragma config WDTE = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF

#define _XTAL_FREQ 8000000UL

void LAT_Init(void){
    OSCCON = 0b01110010;    //8MHz

    ANSELA = 0x00;
    TRISA = 0b00111100; //RA2~RA5 input

    TRISCbits.TRISC2 = 0;   //RC2(CCP1) Output

    T2CONbits.T2CKPS = 0b10;    //Prescaler
    T2CONbits.TMR2ON = 1;   
    PR2 = 124;              //1kHz
    CCP1CON = 0b00001100;   //PWM mode
}

void main(void)
{
    unsigned int duty;
    unsigned char value;

    LAT_Init();

    while(1){
        value = (PORTA >> 2) & 0x0F;    //RA2~RA5を4bitで読む

        if(value > 9){
            value = 9;
        }

        duty = value * 50;

        CCPR1L = duty >> 2;
        CCP1CONbits.DC1B = duty & 0x03;
    }
}

最初は、2進数を10進数に変換して、
それをDuty値として計算させないといけないと
考えていて、いろいろややこしいコードを書きました。

しかし、結局は

c
   while(1){
        value = (PORTA >> 2) & 0x0F;    //RA2~RA5を4bitで読む

        if(value > 9){
            value = 9;
        }

        duty = value * 50;

        CCPR1L = duty >> 2;
        CCP1CONbits.DC1B = duty & 0x03;
    }

これだけ。なんだったら、

c

 while(1){
        value = PORTA >> 2    //RA2~RA5を4bitで読む

        duty = value * 50;

        CCPR1L = duty >> 2;
        CCP1CONbits.DC1B = duty & 0x03;
    }

これだけでもOK。

PORTA >> 2 だけでも動作しますが、安全のために
“& 0x0F” を入れて下位4bitだけを取り出しています。

また、4bit入力であるため、理論上は0~15まで読めてしまいます。
今回のロータリスイッチは
0~9しか使わないため、

if(value > 9){
value = 9;
}

このコードで想定外の値を防いでいます。

 

③オシロスコープで確認

完全におかしい…

めっちゃ暴れてるし…

写真だと暴れているようには見えませんが、
とても暴れていました。

よくよくブレッドボードを見てみると、

”ロータリースイッチのCOMが浮いている”

それを5V + プルアップさせても、

同じように暴れる…

さらによく確認すると、

ブレッドボードの
“-” 表記のあるところにプルダウンさせているのはいいけれど、
その肝心の “-” が “GND” に繋がっていない…

というなかなかに”どんくさい”トラブルを抱えていました。

 

それを解消したのが、次の写真達です。

Rotary値   Duty   波形
110%
330%
880%

ロータリースイッチでのDuty切替できました!!

 

④今日の学び

・ロータリスイッチはCOMが浮いていても、なんとなく動作するが不安定。

・入力は確実にプルダウン/プルアップが必要。

・PICでは4bit入力をそのままPWM dutyに変換できる。

 

⑤次回予告

次回は、3chのADC入力から3ch PWM出力を作ってみます。

コメント

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