PICマイコンでLEDの明るさを変更する

PICマイコンとスイッチを使用し、LEDの明るさを変更します。

次のようなステップになります。

  1. 必要なパーツを揃える
  2. ブレッドボードに回路を作成する
  3. C言語でプログラムを作成する
  4. MPLAB X IDEでプログラムをPICに書き込む
  5. PICをブレッドボードに取り付けてLEDを点灯させてスイッチを押す

1. 必要なパーツを揃える

必要なもの

補足

2. ブレッドボードに回路を作成する

PIC16F84AのPORT Bは内部にプルアップ抵抗を持っていますが、今回はPORT Aを使用するため外部にプルアップ抵抗を配置します。

回路図を参考にブレッドボードに回路を作成します。

回路図

Circuit diagram

Circuit diagram

スイッチが押されていない状態ではRA0は電源とつながるになるため、RA0は1になります。
スイッチが押された状態ではRA0はグラウンドとつながるため、RA0は0になります。

2. MPLABのプロジェクトを作成する

前回と同様にプロジェクトを作成します
名前は、pic_0004_led_brightnessとします。

3. C言語でプログラムを作成する

軽く調べてみたところ、LEDの明るさを変更するには2つのやり方がありそうです。

  1. LEDに流す電流値を変える
    流れる電流が大きいほど明るくなり、小さいほど暗くなります。
    つまり、抵抗値を小さくすると明るくなり、大きくすると暗くなります。
  2. LEDを点灯している時間を変える
    点灯・消灯を高速で切り替えた場合、人間の目は点滅しているかどうかがわかりません。これを利用します。
    次に例を示します。
    • 点灯・消灯・点灯・消灯は半分の明るさになります。
    • 点灯・消灯・消灯・消灯は4分の1の明るさになります。

今回は2を採用して明るさを変更ます。

点灯・消灯の切り替えが遅いと点滅していることがわかってしまいます。そこで、切り替えの間隔は2[ms]にします。
また、LEDの明るさを変更するにはスイッチを使い、スイッチが押されるたびに明るさを変更します。

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config CP = OFF
#define _XTAL_FREQ 20000000

// 156 = 2[ms] * 5[MHz] / 64
#define TMR0_VALUE (256 - 156)

#define L8 (128 * 1 + 64 * 1 + 32 * 1 + 16 * 1 + 8 * 1 + 4 * 1 + 2 * 1 + 1 * 1)
#define L7 (128 * 0 + 64 * 1 + 32 * 1 + 16 * 1 + 8 * 1 + 4 * 1 + 2 * 1 + 1 * 1)
#define L6 (128 * 0 + 64 * 1 + 32 * 1 + 16 * 1 + 8 * 0 + 4 * 1 + 2 * 1 + 1 * 1)
#define L5 (128 * 0 + 64 * 1 + 32 * 0 + 16 * 1 + 8 * 0 + 4 * 1 + 2 * 1 + 1 * 1)
#define L4 (128 * 0 + 64 * 1 + 32 * 0 + 16 * 1 + 8 * 0 + 4 * 1 + 2 * 0 + 1 * 1)
#define L3 (128 * 0 + 64 * 0 + 32 * 0 + 16 * 1 + 8 * 0 + 4 * 1 + 2 * 0 + 1 * 1)
#define L2 (128 * 0 + 64 * 0 + 32 * 0 + 16 * 1 + 8 * 0 + 4 * 0 + 2 * 0 + 1 * 1)
#define L1 (128 * 0 + 64 * 0 + 32 * 0 + 16 * 0 + 8 * 0 + 4 * 0 + 2 * 0 + 1 * 1)
#define L0 (128 * 0 + 64 * 0 + 32 * 0 + 16 * 0 + 8 * 0 + 4 * 0 + 2 * 0 + 1 * 0)

static const unsigned char data[] = {
L8, L7, L6, L5, L4, L3, L2, L1, L0
};

static const unsigned short length = sizeof(data) / sizeof(data[0]);

static unsigned short input0 = 0;
static unsigned short index = 0;
static unsigned short t0 = 0;

void interrupt tc_int(void) {
unsigned short switch0;

if (T0IF != 1) {
return;
}

T0IF = 0;

if (PORTAbits.RA0 == 0 && input0 == 0) {
switch0 = 1;
} else {
switch0 = 0;
}

input0 = 1 - PORTAbits.RA0;

if (switch0 == 1) {
index++;
if (index >= length) {
index = 0;
}
}

t0 = (t0 + 1) & 0x07;

if (((data[index] >> t0) & 0x01) == 1) {
PORTBbits.RB0 = 1;
} else {
PORTBbits.RB0 = 0;
}

TMR0 = TMR0_VALUE;
}

int main() {
GIE = 1; // Enables all unmasked interrupts
T0IE = 0; // Disable the TMR0 interrupt
T0CS = 0; // Internal instruction cycle clock (CLKOUT)
PSA = 0; // Prescaler is assigned to the Timer0 module

OPTION_REGbits.T0CS = 0; // Internal instruction cycle clock
OPTION_REGbits.PS = 5; // Prescaler Rate = (1:64)
OPTION_REGbits.PSA = 0; // Timer0

TRISAbits.TRISA0 = 1;

TRISBbits.TRISB0 = 0;

TMR0 = TMR0_VALUE;
T0IE = 1; // Enable the TMR0 interrupt

while(1) {
}

return 0;
}

解説

まずは明るさの表現方法について説明します。
ソースコード中のL8は全灯、L4は半分の明るさ、L0は消灯です。

例えばL4の0x55を2進数で表すと、0101 0101となります。これは点灯と消灯を交互に切り替えることを表します。
まずは、0ビットシフトし最下位ビットの1を読み込みます。1であるため点灯です。
続いて、1ビットシフトし最下位ビットの0を読み込みます。0であるため消灯です。
これを繰り返します。7ビットシフトしたあとは0ビットシフトに戻ります。

続いてスイッチが押されたときの処理についてです。
スイッチが押されるたびにindexを1加算していき明るさデータの参照先を変更します。
データの最後まで進んだらindexを0にして先頭を参照します。

4. MPLAB X IDEでプログラムをPICに書き込む

省略

5. PICをブレッドボードに取り付けてLEDを点灯させてスイッチを押す

省略