[Top]
AVR - 割込みテスト
・割込み処理
今回は、色々な割込み機能のうち,Pin割込みのINT0と,タイマ/カウンタ割込みを使用して,
ボタン一つで多機能処理を試してみました.
AT90S2313はパワーダウン動作のスリープ処理からの復帰には,INT0割込みを「Lowレベル割込み」に
しないと動きませんでした.そこで,スリープに入る寸前で「Lowレベル割込み」を設定して,
復帰直後に割り込みを解除しています.
動作中のボタン判定は,タイマ/カウンタを使用してボタン状態をポーリングして,短押し/長押しを
判定しています.
・概要
プログラムには3つのモードを持たせました.
モードはLEDフラッシュモード・LED点灯モード・スリープモードです.
モードの切り替えはボタンの長押し,スリープモード以外では点灯方法の変更を短押しで行います.
テストプログラムのため,あまり意味のない動作しかしませんができるだけ関数に分担させて,
さらにコメントをかなり入れてるのでわかると思います.
あと起動時にLEDパフォーマンスも実装してみました.
今回,勉強したのはボタン一つでの多機能化実装と,状態遷移図をイメージした処理体系にしたことです.
・プログラム
この,プログラムを以下に示します.int.zip[main.c/makefile]
表. 1 割込みテストプログラム

// 2006/01/22 
/*----------------------------------------------------------------------------
・プロジェクト名
	ボタン一つで多機能処理を行うテストプログラム

・仕様
	INT0ポートの割り込みを使用したボタンの
	短押し(〜2秒)、長押し(2秒〜5秒)、長押し(5秒以降)で動作変更

・出力ポート
	PB0...7:LED駆動(Lアクティブ)
	PD6:LED駆動(Lアクティブ)
	PD0,1,3,4,5:H出力(未接続)

・入力ポート
	PD2:プッシュスイッチ端子(INT0)

・著作等
	nemy
	WinAVRコンパイル用Cソースコード
----------------------------------------------------------------------------*/

//----------------------------------------------------------------------------
//インクルード、定義など
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/sleep.h>

#define CPU_CLOCK 40//CPUクロックを100k分の1で書く。(40=4MHz)

//sbi  cbi をC言語で感覚的に使えるように…。
#define sbi(PORT,BIT) PORT|=_BV(BIT) // PORTの指定BITに1をセット
#define cbi(PORT,BIT) PORT&=~_BV(BIT) // PORTの指定BITをクリア

//ボタン状態遷移列挙子
enum _ButtonStat {STANDBY,CLICK,LONGPUSH};
enum _ModeStat {BOOT,FLASH,LIGHT,SLEEP,WAKE};

//グローバル変数
enum _ButtonStat g_btnstat;
enum _ModeStat g_modestat;
unsigned char g_ucBtnCount;//ボタンPD2の押下時間

//----------------------------------------------------------------------------
//プロトタイプ宣言
void wait(unsigned char);
void BootPerformance(void);
void PowerDown(void);

void SetInt0(unsigned char);
void KillInt0(void);

unsigned char GetInt0Type(void);
void SetTimerCounter0(unsigned char);
void SetTimerCounter1(unsigned char,unsigned char,unsigned char);
//----------------------------------------------------------------------------
//ウェイト関数
void wait(unsigned char ucLoop)
{
	unsigned char i,j;
	for(i = 0;i < ucLoop;i++)
	{
		for(j = 1;j < 0xFF;j++)//unsigned char は最大0xFFのはず
		{
			j--;	//ダミー処理
			j++;	//ダミー処理
		}
	}
	return;
}
//----------------------------------------------------------------------------
//スリープ(パワーダウン)関数
void PowerDown(void)
{
	//スリープ動作のパワーダウンに設定
	sbi(MCUCR, SM);//MCUCRのSMビットをセット(1)
	//スリープ動作のアイドルに設定
	//cbi(MCUCR, SM);//MCUCRのSMビットをセット(0)
	//スリープ動作許可
	sbi(MCUCR, SE);//MCUCRのSEビットをセット(1)
	//スリープ
	sleep_mode();
	
	return;
}
//----------------------------------------------------------------------------
//外部割り込み処理(INT0)設定
#define INT_LOW 0x00 //ISC01=0, ISC00=0 → INT0Lowレベルで発生(SLEEPパワーダウンからの復帰条件)
#define INT_DOWN 0x02 //ISC01=1, ISC00=0 → INT0立下りエッジ検出
#define INT_UP 0x03 //ISC01=1, ISC00=1 → INT0立上りエッジ検出
void SetInt0(unsigned char ucType)
{
	unsigned char tmp;
	cbi(DDRD, PD2); //INT0を入力に設定
	sbi(GIMSK, INT0); //一般割込みマスクレジスタ(GIMSK)のINT0(外部割込み0)を1にして割込み許可

	tmp = MCUCR & 0xFC;
	MCUCR = tmp | ucType;
	return;
}
//----------------------------------------------------------------------------
//外部割り込み処理(INT0)設定解除
void KillInt0(void)
{
	cbi(GIMSK, INT0); //一般割込みマスクレジスタ(GIMSK)のINT0(外部割込み0)を1にして割込み不許可
	return;
}
//----------------------------------------------------------------------------
//外部割り込み処理(INT0)設定読込
unsigned char GetInt0Type(void)
{
	if(bit_is_clear(MCUCR, ISC01) && bit_is_clear(MCUCR, ISC00))
		return INT_LOW;
	if(bit_is_set(MCUCR, ISC01) && bit_is_clear(MCUCR, ISC00))
		return INT_DOWN;
	if(bit_is_set(MCUCR, ISC01) && bit_is_set(MCUCR, ISC00))
		return INT_UP;
		
	return INT_LOW;
}
//----------------------------------------------------------------------------
//タイマ/カウンタ0設定
#define STC0_STOP 0x00//動作停止
#define STC0_CK 0x01//CPUクロック1分周
#define STC0_CK8 0x02//CPUクロック8分周
#define STC0_CK64 0x03//CPUクロック64分周
#define STC0_CK256 0x04//CPUクロック256分周
#define STC0_CK1024 0x05//CPUクロック1024分周
#define STC0_DOWN 0x06//T0ピン立下りエッジ
#define STC0_UP 0x07//T0ピン立上りエッジ
void SetTimerCounter0(unsigned char ucType)
{
	TCCR0 = ucType;
	TCNT0 = 0x00;//カウント値の初期化(8bit)
	return;
}
//----------------------------------------------------------------------------
//タイマ/カウンタ1設定
#define STC1_STOP 0x00//動作停止
#define STC1_CK 0x01//CPUクロック1分周
#define STC1_CK8 0x02//CPUクロック8分周
#define STC1_CK64 0x03//CPUクロック64分周
#define STC1_CK256 0x04//CPUクロック256分周
#define STC1_CK1024 0x05//CPUクロック1024分周
#define STC1_DOWN 0x06//T0ピン立下りエッジ
#define STC1_UP 0x07//T0ピン立上りエッジ
void SetTimerCounter1(unsigned char ucType,unsigned char ucCompareH,unsigned char ucCompareL)
{
	unsigned char tmp;

	//カウンタ設定
	tmp = TCCR1B & 0xFC;
	TCCR1B = tmp | ucType;
	//比較割込を有効化
	sbi(TIMSK,OCIE1A);
	
	//比較カウント値設定
	OCR1AH = ucCompareH;
	OCR1AL = ucCompareL;
	TCNT1 = 0x0000;//カウント値の初期化
	return;
}
//----------------------------------------------------------------------------
//メイン
int main(void)
{
	//ポートIO設定
	DDRB = 0xFF;//ポートB OOOO OOOO
	DDRD = 0x7B;//ポートD xOOO OIOO

	//ポート状態の初期化
	PORTB = 0xFF;//Port_B HHHH HHHH
	PORTD = 0x7F;//Port_D xHHH HUHH H:出力(1) L:出力(0) U:内蔵プルアップ(1) D:プルアップなし(0)
	
	//ウォッチドッグタイマ設定(一応明示的に)
	//WDTCR = 0x18;
	sbi(WDTCR,WDTOE);//ウォッチドッグ不許可への条件
	cbi(WDTCR,WDE);//ウォッチドッグ不許可に

	//タイマ割込設定
	// CPUCLOCK(4MHz) / 1024 = 3906 Hz よって割込比較値651(0x028B)で1秒6回(0.1667秒毎)割込
	SetTimerCounter1(STC1_CK1024,0x02,0x8B);
	
	//変数宣言・初期化
	g_btnstat = STANDBY;//ボタン状態遷移
	g_modestat = BOOT;//モード状態遷移
	unsigned char ucFlashType = 0x00;//Flashモード時の点灯データ
	unsigned char ucLightType = 0x00;//Lightモード時の点灯データ

	//動作メイン処理
	while(1)
	{
		//各モードの処理ルーチン
		switch(g_modestat)
		{
			//初期化
			case BOOT:
				cli();//割り込み処理禁止
				g_ucBtnCount = 0x00;
				ucFlashType = 0x01;
				ucLightType = 0x01;
				g_btnstat = STANDBY;
				g_modestat = FLASH;
				BootPerformance();
				sei();//割り込み処理解禁
				break;

			//点滅
			case FLASH:
				//処理
				PORTB = ~ucFlashType;
				wait(0xff);
				PORTB = 0xFF;
				wait(0xff);
				//ボタン状態遷移・処理ルーチン
				switch(g_btnstat)
				{
					case STANDBY:
						break;
					case CLICK:
						ucFlashType++;
						g_btnstat = STANDBY;
						break;
					case LONGPUSH:
						g_modestat = LIGHT;
						g_btnstat = STANDBY;
						break;
				}
				break;

			//点灯
			case LIGHT:
				//処理
				PORTB = ~ucLightType;
				//ボタン状態遷移・処理ルーチン
				switch(g_btnstat)
				{
					case STANDBY:
						break;
					case CLICK:
						ucLightType++;
						g_btnstat = STANDBY;
						break;
					case LONGPUSH:
						g_modestat = SLEEP;
						g_btnstat = STANDBY;
						break;
				}
				break;

			//スリープ
			case SLEEP:
				PORTB = 0xff;//非点灯に
				SetInt0(INT_LOW);//INT0割込み設定(Lowレベル) スリープ復帰用
				PowerDown();
				KillInt0();//INT0割込み禁止
				g_modestat = WAKE;
				g_btnstat = STANDBY;
				break;

			//スリープ復帰
			case WAKE:
				//ボタン状態遷移・処理ルーチン
				switch(g_btnstat)
				{
					case STANDBY:
						break;
					case CLICK:
						g_modestat = SLEEP;
						g_btnstat = STANDBY;
						break;
					case LONGPUSH:
						g_modestat = BOOT;
						g_btnstat = STANDBY;
						break;
				}
				break;
		}
	}
	return 0;
}
//----------------------------------------------------------------------------
//INT0 外部割り込み処理
SIGNAL(SIG_INTERRUPT0)
{
	switch(GetInt0Type())
	{
		//Lowレベルでした
		case INT_LOW:
			break;
		
		//立下りでした
		case INT_DOWN:
			break;
		
		//立上りでした
		case INT_UP:
			break;
	}
	return;
}
//----------------------------------------------------------------------------
//タイマ/カウンタ0 比較一致割込み処理
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
	//ボタン状態Lであれば押下時間計測継続
	if(bit_is_clear(PIND,PD2))
	{
		g_ucBtnCount += 1;
	}
	else
	{
		//ボタンが離されたのか、元々からか?
		if(g_ucBtnCount == 0)
		{
			//元々
		}
		else
		{
			//離された
			g_ucBtnCount = 0;
			g_btnstat = CLICK;
		}
	}
	
	//長時間押して2秒以上たった
	if(12 < g_ucBtnCount)
	{
		g_ucBtnCount = 0;
		g_btnstat = LONGPUSH;
	}

	//カウンタを0に戻す
	TCNT1H = 0x00;
	TCNT1L = 0x00;
	
	return;
}
//----------------------------------------------------------------------------
//起動時のパフォーマンス
void BootPerformance(void)
{
	unsigned char ucTmp;
	for(ucTmp = 1;ucTmp < 0x80;ucTmp = ucTmp << 1)
	{
		PORTB = ~ucTmp;
		wait(0xff);
	}
	for(ucTmp = 128;1 < ucTmp;ucTmp = (ucTmp >> 1) & 0x7F)
	{
		PORTB = ~ucTmp;
		wait(0xff);
	}
	for(ucTmp = 0;ucTmp < 10;ucTmp++)
	{
		PORTB = 0x00;
		wait(0xff);
		PORTB = 0xff;
		wait(0xff);
	}
	
	return;
}
//----------------------------------------------------------------------------