<PIC16F688 SW_LED>

スイッチ4個とLED4個を接続して、スイッチを押すとLEDが点灯する単純な動作です。


回路図


プログラム
今まで、OSCCONレジスタで内部発振器の周波数を設定していましたが、しなくても動作しています。
(LED点滅など時間関連が不必要なプログラムだから・・・?)
-----------------------------------------------------------------------------------------
#include <htc.h>

__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

main()
{

//RC1,RC2,RC3,RC4が入力ピン、RA0,RA1,RA2,RA4が出力ピンの場合
TRISA=0b00000000;  //RA0,RA1,RA2,RA4を出力モードに設定
TRISC=0b00011110;  //RC1,RC2,RC3,RC4を入力モードに設定
PORTA=0b00000000;  //出力ピンRA0,RA1,RA2,RA3の初期値はL(0)にする
PORTC=0b00011110;  //入力ピンRC1,RC2,RC3,RC4の初期値はH(1)にする
ANSEL=0b00000000;   //RC1,RC2,RC3,RC4をデジタルI/OモードL(0)にする
CMCON0=0b00000111;  //RC1,RC2,RC3,RC4をデジタルI/Oモードにする

	while(1){
		
		 if (RC1==0) RA0=1;

		 if (RC2==0) RA1=1;

		 if (RC3==0) RA2=1;

		 if (RC4==0) RA4=1;

	}
}
-----------------------------------------------------------------------------------------

次は、押されたスイッチ対応のLEDだけ点灯します。


プログラム
-----------------------------------------------------------------------------------------
#include <htc.h>

__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

main()
{

//RC1,RC2,RC3,RC4が入力ピン、RA0,RA1,RA2,RA4が出力ピンの場合
TRISA=0b00000000;  //RA0,RA1,RA2,RA4を出力モードに設定
TRISC=0b00011110;  //RC1,RC2,RC3,RC4を入力モードに設定
PORTA=0b00000000;  //出力ピンRA0,RA1,RA2,RA3の初期値はL(0)にする
PORTC=0b00011110;  //入力ピンRC1,RC2,RC3,RC4の初期値はH(1)にする
ANSEL=0b00000000;   //RC1,RC2,RC3,RC4をデジタルI/OモードL(0)にする
CMCON0=0b00000111;  //RC1,RC2,RC3,RC4をデジタルI/Oモードにする

	while(1){
		
		 if (RC1==0) RA0=1;
		 else RA0=0;

		 if (RC2==0) RA1=1;
		 else RA1=0;

		 if (RC3==0) RA2=1;
		 else RA2=0;

		 if (RC4==0) RA4=1;
		 else RA4=0;

	}
}
-----------------------------------------------------------------------------------------

次は、押されたスイッチのLEDだけが点滅します。


点滅さすので、次の時間関連命令が必要です(1つでもないと正しく動作しません)
OSCCON=0x00;               //内部発振器の設定  31k:OSCCON=0x00; 4M:OSCCON=0x60; 8M:OSCCON=0x70
#define _XTAL_FREQ 31000    // 31k
#define JIKAN 300           //JIKANに300が入る
__delay_ms(JIKAN)      //300msの待ち時間

プログラム
-----------------------------------------------------------------------------------------
#include <htc.h>


__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);


#define _XTAL_FREQ 31000  //31k
#define JIKAN 300

main()
{

OSCCON=0x00;  //31k

//RC1,RC2,RC3,RC4が入力ピン、RA0,RA1,RA2,RA4が出力ピンの場合
TRISA=0b00000000;  //RA0,RA1,RA2,RA4を出力モードに設定
TRISC=0b00011110;  //RC1,RC2,RC3,RC4を入力モードに設定
PORTA=0b00000000;  //出力ピンRA0,RA1,RA2,RA3の初期値はL(0)にする
PORTC=0b00011110;  //入力ピンRC1,RC2,RC3,RC4の初期値はH(1)にする
ANSEL=0b00000000;   //RC1,RC2,RC3,RC4をデジタルI/OモードL(0)にする
CMCON0=0b00000111;  //RC1,RC2,RC3,RC4をデジタルI/Oモードにする

	while(1){
		
		 if (RC1==0){
		 RA0=1;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		 RA0=0;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		}

		 if (RC2==0){
		 RA1=1;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		 RA1=0;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
 		}	

		 if (RC3==0){
		 RA2=1;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		 RA2=0;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		}

		 if (RC4==0){
		 RA4=1;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		 RA4=0;
		__delay_ms(JIKAN);	/* JIKANミリ秒待つ */
		}


	}
}
-----------------------------------------------------------------------------------------

上記までのプログラムで、スイッチが押された判断は、入力ポートRC1,RC2・・・がL(0)になったときを判断しています。
プログラムの if (RC0==0)など・・・です。

PIC16F688には、次の機能でスイッチが押された判断をすることも出来ます。

@入力ポートが変化(H→L or L→H)すると、あるレジスタ(INTCON)のビット(RAIF)がH(1)になります。
ARA2ポート専用ですが、入力エッジの立上り(立下り)でINTFビットがH(1)になります。

@入力ポートの変化を使う(RA0〜RA5が対象、RC0〜RC5は使えない)
例としてRA0に接続したスイッチを押すとRC1のLEDが点滅

※デジタルI/Oとして使うのが多いので、下記はどのプログラムにも定番として記述します。

ANSEL=0x00;                 //デジタルI/Oピンとして使う
CMCON0=0x07;                //デジタルI/Oピンとして使う
OSCCON=0x00;               //内部発振器の設定  31k:OSCCON=0x00; 4M:OSCCON=0x60; 8M:OSCCON=0x70
#define _XTAL_FREQ 31000    // 31k:31000 4M:4000000 8M:8000000
#define JIKAN 300           //JIKANに300が入る LED点滅など、待ち時間が必要な時
__delay_ms(JIKAN)      //300msの待ち時間  LED点滅など、待ち時間が必要な時



プログラム
-----------------------------------------------------------------------------------------
#include <htc.h>

IOCA0=1; //RA0ポート変化

TRISA=0b00000001;  //RA0を入力モードに設定
TRISC=0x00;        //RC1を出力モードに設定
PORTA=0x01;        //RA0をH(1)にする
PORTC=0x00;        //RC1をL(0)にする

__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

#define _XTAL_FREQ 31000  //31k
#define JIKAN 300

main()
{

OSCCON=0x00;  //31k

ANSEL=0x00;
CMCON0=0x07;

RAIF=0;  //ポート入力変化があるとH(1)になるのでL(0)にしておく
IOCA0=1; //RA0ポート変化

TRISA=0b00000001;  //RA0を入力モードに設定
TRISC=0x00;        //RC1を出力モードに設定
PORTA=0x01;        //RA0をH(1)にする
PORTC=0x00;        //RC1をL(0)にする

	while(1){

		if (RAIF==1){
		 RC1=1;
		__delay_ms(JIKAN);
		 RC1=0;
		__delay_ms(JIKAN);

		}
	}
}
-----------------------------------------------------------------------------------------

上のプログラムのwhile(1)文の中にRAIF=0;を入れると1回だけ点灯して消えます。
RAIF=0;でリセットしているので再度スイッチを押すとけ点灯して消えます。

	while(1){

		if (RAIF==1){
		 RC1=1;
		__delay_ms(JIKAN);
		 RC1=0;
		__delay_ms(JIKAN);

        RAIF=0;
		}
	}




ARA2ポートの入力エッジ(立上り・立下り)でRC1のLEDを点灯させます。


立下りエッジ(左側、スイッチを押した瞬間)


プログラム
-----------------------------------------------------------------------------------------
#include <htc.h>

__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

#define _XTAL_FREQ 31000  //31k
#define JIKAN 300

main()
{

OSCCON=0x00;  //31k

ANSEL=0x00;
CMCON0=0x07;

INTEDG=0; //立下りエッジ
INTF=0;   //ポート入力変化があるとH(1)になるのでL(0)にしておく


TRISA=0b00000100;  //RA2を入力モードに設定
TRISC=0x00;        //RC1を出力モードに設定
PORTA=0x04;        //RA2をH(1)にする
PORTC=0x00;        //RC1をL(0)にする

	while(1){

		if (INTF==1){
		 RC1=1;
		__delay_ms(JIKAN);
		 RC1=0;
		__delay_ms(JIKAN);
		
		}
	}
}
-----------------------------------------------------------------------------------------


立下りエッジ(右側、スイッチを押した瞬間)


プログラムはINTEDG=0;をINTEDG=1; に変更するだけ

下の回路図でスイッチを、押して離した時にLEDが点滅


スイッチを、押して離すと(立上りエッジ)LEDが点滅


プログラム
-----------------------------------------------------------------------------------------
#include <htc.h>


__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

#define _XTAL_FREQ 31000  //31k
#define JIKAN 300

main()
{

OSCCON=0x00;  //31k

ANSEL=0x00;
CMCON0=0x07;

INTEDG=1; //立上りエッジ
INTF=0;   //ポート入力変化があるとH(1)になるのでL(0)にしておく


TRISA=0b00000100;  //RA2を入力モードに設定
TRISC=0x00;        //RC1を出力モードに設定
PORTA=0x04;        //RA2をH(1)にする
PORTC=0x00;        //RC1をL(0)にする

	while(1){

		if (INTF==1){
		 RC1=1;
		__delay_ms(JIKAN);
		 RC1=0;
		__delay_ms(JIKAN);
		
		}
	}
}
-----------------------------------------------------------------------------------------

//割り込み//
@入力ポート変化割り込み
例えば、あるポート(RC1)に接続のLEDが点滅しているとき、スイッチ(RA0)を押すと入力ポートが変化
すると、割り込みが発生してその点滅を中断して別のポート(RC4)接続のLEDを点灯させる。

割り込み専用関数 interruptを書けばよい
interruptに続いて書く名前はなんでもよい、ここではf_ra0()を書いている。



-----------------------------------------------------------------------------------------
#include <htc.h>

__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

#define _XTAL_FREQ 31000  //31k
#define JIKAN 300

main()
{

OSCCON=0x00;  //31k

ANSEL=0x00;
CMCON0=0x07;

//ポート入力変化割り込みを使うときの設定項目
IOCA0=1;  //RA0入力変化
RAIF=0;   //ポート入力変化あるとH(1)になるのでL(0)にしておく
GIE=1;    //割り込みを使うときH(1)
RAIE=1;   //ポート入力変化割り込みを使うときH(1)


TRISA=0b00000001;  //RA0を入力モードに設定
TRISC=0x00;        //RC1,RC4を出力モードに設定
PORTA=0x01;        //RA0をH(1)にする
PORTC=0x00;        //RC1をL(0)にする

	while(1){
		 RC1=1;
		__delay_ms(JIKAN);
		 RC1=0;
		__delay_ms(JIKAN);
	}
}

//割り込み専用関数
interrupt f_ra0()
{
		RC1=0;
		RC4=1;
}
-----------------------------------------------------------------------------------------

A入力ポートエッジ割り込み

例えば、あるポート(RC1)に接続のLEDが点滅しているとき、スイッチ(RA2)を押したときに
エッジを検出すると、割り込みが発生して点滅を中断させて、別のポート(RC4)接続のLEDを点灯させる。

ここでは立上りエッジを使います。押して離したときが立上りエッジになります。



プログラム
-----------------------------------------------------------------------------------------
#include <htc.h>

__CONFIG(FCMDIS & IESODIS & BOREN & UNPROTECT & MCLREN & PWRTEN & WDTDIS & INTIO);
__IDLOC(0001);

#define _XTAL_FREQ 31000  //31k
#define JIKAN 300

main()
{

OSCCON=0x00;  //31k

ANSEL=0x00;
CMCON0=0x07;

//ポート入力エッジ割り込みを使うときの設定項目
INTEDG=1; //立上りエッジ
INTF=0;   //ポート入力エッジがあるとH(1)になるのでL(0)にしておく
GIE=1;    //割り込みを使うときH(1)
INTE=1;   //エッジ割り込みを使うときH(1)

TRISA=0b00000100;  //RA2を入力モードに設定
TRISC=0x00;        //RC1,RC4を出力モードに設定
PORTA=0x04;        //RA2をH(1)にする
PORTC=0x00;        //RC1をL(0)にする

	while(1){
		 RC1=1;
		__delay_ms(JIKAN);
		 RC1=0;
		__delay_ms(JIKAN);
	}
}

interrupt f_ra2()
{
		RC1=0;
		RC4=1;
}
-----------------------------------------------------------------------------------------


(参考 ポート関連のレジスタ)

ANSELレジスタ
7bit: ANS7 //RC3ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
6bit: ANS6 //RC2ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
5bit: ANS5 //RC1ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
4bit: ANS4 //RC0ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
3bit: ANS3 //RA4ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
2bit: ANS2 //RA2ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
1bit: ANS1 //RA1ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)
0bit: ANS0 //RA0ポートをアナログ入力するにはH(1)デジタルI/OモードにするにはL(0)

CMCON0レジスタ
7bit: C2OUT //省略
6bit: C1OUT //省略
5bit: C2INV //省略
4bit: C1INV //省略
3bit: CIS   //省略
2bit: CM2   //コンパレータ入出力設定(特定のポートをデジタルI/Oモードにする)
1bit: CM1   //コンパレータ入出力設定(特定のポートをデジタルI/Oモードにする)
0bit: CM0   //コンパレータ入出力設定(特定のポートをデジタルI/Oモードにする)
※CMCON0=0x07にすれば最大設定でRA0,RA1,RC0,RC1デジタルI/Oモードになる

INTCONレジスタ
7bit: GIE  //割り込みを使うときH(1)使わないL(0) interrupt関数を使うときに使用(interrupt関数なしでHにすると正しく動作しない)
6bit: PEIE //PIE1レジスタ割り込みイネーブルビット有りイベントを使うときH(1)使わないL(0)
5bit: T0IE //タイマ0オーバフロー割り込みを使うときH(1)使わないL(0)
4bit: INTE //RA2ポートを入力ピンでエッジ割り込みを使うときH(1)使わないL(0)
3bit: RAIE //ポート入力変化割り込みを使うときH(1)使わないL(0)
2bit: T0IF //タイマ0がオーバフローするとH(1)になる、初期設定でL(0)にして使う
1bit: INTF //RA2ポートにエッジ入力があるとH(1)になる、初期設定でL(0)にして使う
0bit: RAIF //ポート入力変化があるとH(1)になる、初期設定でL(0)にして使う

IOCAレジスタ
7bit: ----- //使用なし
6bit: ----- //使用なし
5bit: IOCA5 //RA5ポートの入力変化を取得するにはH(1)しないL(0)
4bit: IOCA4 //RA4ポートの入力変化を取得するにはH(1)しないL(0)
3bit: IOCA3 //RA3ポートの入力変化を取得するにはH(1)しないL(0)
2bit: IOCA2 //RA2ポートの入力変化を取得するにはH(1)しないL(0)
1bit: IOCA1 //RA1ポートの入力変化を取得するにはH(1)しないL(0)
0bit: IOCA0 //RA0ポートの入力変化を取得するにはH(1)しないL(0)

OPTIONレジスタ
7bit: RAPU   //省略
6bit: INTEDG //立上りエッジはH(1)、立下りエッジはL(0)
5bit: T0CS   //省略
4bit: T0SE   //省略
3bit: PSA    //省略
2bit: PS2    //省略
1bit: PS1    //省略
0bit: PS0    //省略


※ポート入力変化、RA2ポートにエッジ入力だけのときは、割り込み用の命令を使用しないこと
 GIE,INTE,RAIEなど。interrupt関数も・・・

 ポート入力変化、RA2ポートにエッジ入力+割り込みを使うときは割り込み用の命令と
 interrupt関数を使用。