16F873A XC8開発例 - LED調光回路(CCPモジュールのPWM機能)
はじめに
本ページでは,PIC16F873AとMPLAB XC8 C Compilerを使用した開発例として,PWM方式LED調光回路の製作例を紹介します. LEDの輝度制御には,PIC16F873Aに搭載されているCCPモジュールのPWM機能を使用しています. 今回はPIC16F873Aを使用していますが,一部を変更することで,同様のCCPモジュールが搭載されているPIC16F877Aなどでも下記のプログラムを使用できると思います.
下記の環境で動作を確認しておりますが,動作を保証するものではありません. 掲載情報は自己責任の上でご利用ください.
PIC | 16F873A-I/SP |
---|---|
MPLAB X IDE | MPLAB X IDE v1.85 for Mac |
MPLAB XC8 | MPLAB XC8 C Compiler v1.20 for Mac |
PICkit 2 | MPLAB X IDEを使用して書込み |
回路
回路図
今回は,自作にした汎用PICマイコンボードを使用しました. 下記のプログラムの動作に必要な部分を抜粋した回路は,下図の通りです. 下図の回路では,PICkit 2によるICSP (In Circuit Serial Programming)と電源供給を行うことし,回路部品数を必要最低限に抑えています.
回路部品
上記の回路図中で使用している回路部品のリストです. 参考単価は,特に記載がない限り,秋月電子通商で購入した場合のものです.
番号 | 部品名 | 型番 | 数量 | 参考単価 |
---|---|---|---|---|
U1 | PICマイコン | Microchip 16F873A-I/SP | 1 | 350円 |
X1 | セラロック | 村田製作所 20MHz | 1 | 30円 |
LED1 - 2 | LED | 各社 φ5 高輝度タイプ 各色 | 2 | 10円 |
R1 | 炭素皮膜抵抗 | 各社 1/4W 10kΩ | 1 | 1円 |
R2 - 3 | 炭素皮膜抵抗 | 各社 1/4W 330Ω | 2 | 1円 |
その他 | リード線など | 適量 |
プログラム
このプログラムはMPLAB XC8 C Compiler向けです.Cコンパイラの種類にご注意ください.
PIC16F873AにはCCPモジュールが2系統ありますので,これらを利用して2つのLEDの輝度を制御するプログラムです. 蛍の光のように,光が明るくなったり暗くなったりをゆっくりと繰り返します. PWMの分解能は10bitですので,デューティ比設定用変数(duty1およびduty2)には0から1023までの値を設定可能です. しかし,下記のプログラムではLEDの最大輝度を抑えるために最大値を511としています. プログラムを改変して使用される場合はご注意ください. LEDの最大輝度は,電流制限用抵抗であるR2およびR3の抵抗値でも調整可能です. 使用するLEDに合わせてデューティ比の最大値と電流制限用抵抗の抵抗値を調整してください.
下記はソースファイル「main.c」です.
#include <xc.h>
#include "pwm.h"
#define _XTAL_FREQ 20000000 // 20MHz
#define PR2_DATA 0xFF
#pragma config BOREN = ON, CPD = OFF, DEBUG = OFF, WRT = OFF, FOSC = HS, WDTE = OFF, CP = OFF, LVP = OFF, PWRTE = ON
void main()
{
unsigned int duty1, duty2;
unsigned char flag1, flag2;
TRISA = 0x00; // PORTAの入出力設定
TRISB = 0x00; // PORTBの入出力設定
TRISC = 0x00; // PORTCの入出力設定
PORTA = 0x00; // PORTAを初期化
PORTB = 0x00; // PORTBを初期化
PORTC = 0x00; // PORTCを初期化
initPWM1(PR2_DATA, T2_DIV_BY_1); // CCP1をPWMモードに設定
initPWM2(PR2_DATA, T2_DIV_BY_1); // CCP2をPWMモードに設定
setPWM1Duty(0); // デューティ値を初期化
setPWM2Duty(0);
duty1 = 0; // 制御変数を初期化
flag1 = 0;
duty2 = 511;
flag2 = 1;
while (1) { // 無限ループ
// CCP1 (PWM1)
if (flag1 == 0) { // デューティ比の変化方向の判定
setPWM1Duty(duty1); // デューティ比を設定
duty1++; // デューティ比をインクリメント
if (duty1 >= 511) { // デューティ比が最大値を超過した場合
flag1 = 1; // 変化方向を反転
}
}
else {
setPWM1Duty(duty1);
duty1--; // デューティ比をデクリメント
if (duty1 <= 0) {
flag1 = 0;
}
}
// CCP2 (PWM2)
if (flag2 == 0) { // デューティ比の変化方向の判定
setPWM2Duty(duty2); // デューティ比を設定
duty2++; // デューティ比をインクリメント
if (duty2 >= 511) { // デューティ比が最大値を超過した場合
flag2 = 1; // 変化方向を反転
}
}
else {
setPWM2Duty(duty2);
duty2--; // デューティ比をデクリメント
if (duty2 <= 0) {
flag2 = 0;
}
}
__delay_ms(5); // 5ミリ秒タイマ
}
}
下記はヘッダファイル「pwm.h」です.
#ifndef PWM_H
#define PWM_H
#define T2_DIV_BY_1 0b00000000
#define T2_DIV_BY_4 0b00000001
#define T2_DIV_BY_16 0b00000010
#define CCP_PWM 0b00001100
// プロトタイプ宣言
void initPWM1(unsigned char pr2, unsigned char t2ckps);
void setPWM1Duty(unsigned int duty);
void initPWM2(unsigned char pr2, unsigned char t2ckps);
void setPWM2Duty(unsigned int duty);
#endif // PWM_H
下記はソースファイル「pwm.c」です.
#include <xc.h>
#include "pwm.h"
void initPWM1(unsigned char pr2, unsigned char t2ckps)
{
PR2 = pr2;
CCP1CON = CCP_PWM;
setPWM1Duty(0);
T2CON = t2ckps;
T2CON |= 0x04;
}
void setPWM1Duty(unsigned int duty)
{
CCPR1L = duty >> 2;
CCP1CON &= 0b11001111;
CCP1CON |= 0b00110000 & (duty << 4);
}
void initPWM2(unsigned char pr2, unsigned char t2ckps)
{
PR2 = pr2;
CCP2CON = CCP_PWM;
setPWM2Duty(0);
T2CON = t2ckps;
T2CON |= 0x04;
}
void setPWM2Duty(unsigned int duty)
{
CCPR2L = duty >> 2;
CCP2CON &= 0b11001111;
CCP2CON |= 0b00110000 & (duty << 4);
}
実装
回路構成例
今回は,自作にした汎用PICマイコンボードを使用しました. LEDは上側からLED1 (RC1, CCP2),LED2 (RC2, CCP1)です.
動作例
上記のプログラムを実際に動作させたときの動画です.
__delay_ms関数にエラーマークが表示されるときは
文法や関数の利用方法に問題がなくコンパイルが成功するにも関わらず, __delay_ms関数や__delay_us関数にエラー(警告)マークが表示される場合,下記の記事をご一読ください.
更新履歴
日付 | 内容 |
---|---|
2014/07/02 | 関数定義を「pwm.h」から「pwm.c」に移行 |
2014/06/29 | 一部の記号定数定義を「main.c」から「pwm.h」に移行 |
2014/05/19 | 「pwm.h」にインクルードガードを追記 |
2013/--/-- | 公開開始 |