今回はPIC16F1938を使い、
10進ロータリスイッチ入力からPWM調光を作りました。
この記事では、回路図、コード、オシロ波形、
ハマったポイントをまとめています。
ロータリスイッチは、うちの会社でもよく使うスイッチなので、
しっかり使えるようになっておきたいとは思っていました。
前回、PIC16F1938でADC入力からPWM調光を作る方法【LEDをボリューム制御】ボリュームでの調光には成功したので、
このタイミングでロータリスイッチの入力から、
PWMの段階的な出力を作りました。
ロータリスイッチの4bit出力をそのまま読み、
0~9の値をPWMデューティに変換しました。
結果的にはきれいに10等分の調光を作ることができましたが、
今回もなかなか罠にハマってしまいました。
①今回の回路図

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

このスイッチの出力コードは
| 1 | 2 | 4 | 8 | |
|---|---|---|---|---|
| 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 | 波形 |
| 1 | 10% | ![]() |
| 3 | 30% | ![]() |
| 8 | 80% | ![]() |
ロータリースイッチでのDuty切替できました!!
④今日の学び
・ロータリスイッチはCOMが浮いていても、なんとなく動作するが不安定。
・入力は確実にプルダウン/プルアップが必要。
・PICでは4bit入力をそのままPWM dutyに変換できる。
⑤次回予告
次回は、3chのADC入力から3ch PWM出力を作ってみます。



コメント