点师大灯——STM32应用笔记(十一)

十一、中断处理改成C++

        STM32F103的外设中断处理,用C语言写出来感觉很疏远。外设感觉是孩子送人,NVIC感觉是托儿所。本来外设和自己的中断是紧密联系得,为了简洁而有些不方便。

        外设中断是外设的一部分,这才符合我们的思维。比如有个闪烁的LED灯:我们自然想到设个定时器,在定时器里开关灯。如果用C处理,感觉是定时器的中断要知道定时器和LED灯的相关信息。就像给自己孩子喂饭,要自己把饭端到托儿所里去喂。这不科学。我们可以通过语言的小手段,改变成我们习惯的方式。

       具体的实现,有个例子:我们有个COUNT,每500毫秒加1。这里用的定时器是SysTick,主要图的是代码简单。

int main()
{
	IRQDefaultInit();

	MySysTick sys_tick;
	volatile int count=0;
	
	while(1)
	{
		if( true == sys_tick.Delay(500) )
		{
			count++;
		}
		else
			__WFI();
	}
	return 0;
}

这个定时器由SysTick通过中断实现。中断函数被改写成调用默认处理函数,传递自己IRQN的函数。

//中断处理函数都成这样了,简单明了。
extern "C" void SysTick_Handler()
{
		IRQDefaultHandler( SysTick_IRQn );
}

而这个IRQDefaultHandler(int)函数,则调用构造好的handler数组对象OnHandler()。

void IRQDefaultHandler(int input_irqn)
{
	//IRQN	从-3开始,对应数组要加 3
	input_irqn+=3;
	handler[input_irqn%NVIC_COUNT]->OnHandler();
}

构造这个handler数组对象,看最后的代码。

我们好的地方是IRQHandler类:

/***********************************************************/
class IRQHandler{
	private:
		int irqn;
		void Empty() {}
		void Dead()  { while(1);}
	public:
		IRQHandler(int input_irqn):irqn(input_irqn) { IRQDefaultRegister( this, input_irqn);}
		virtual void OnHandler() { Empty(); }
		virtual ~IRQHandler() { IRQDefaultUnRegister( irqn ); }
};
static IRQHandler DefaultHandler(0);

它在构造自己的时候,就自动向IRQDefault注册。析构的时候自动反注册。自己的OnHandler()函数,就是被调用的中断处理函数;而这个虚函数又可以在子类里改变自己的中断处理。我们只需继承这个IRQHandler类,就有了相应中断的处理能力。例子里的MySysTick类就是这么搞的。

class MySysTick : public IRQHandler{
	private:
		bool is_free;
	public:
		MySysTick();
		virtual void OnHandler();		
		bool Delay(unsigned int ms);
};

最终的全部代码如下,乱七八糟。

//具体中断处理类
class IRQHandler;
//中断处理默认类,单一静态对象退化为 C 
//class IRQDefault;

/***********************************************************/
//默认的中断处理函数,STM32F103C8一共68个
const unsigned int NVIC_COUNT=68;
static  IRQHandler* handler[NVIC_COUNT];
void 		IRQDefaultRegister(IRQHandler* input_handler, int input_irqn);
void 		IRQDefaultUnRegister( int input_irqn);
void 		IRQDefaultInit();
void		IRQDefaultHandler( int input_irqn);

/***********************************************************/
class IRQHandler{
	private:
		int irqn;
		void Empty() {}
		void Dead()  { while(1);}
	public:
		IRQHandler(int input_irqn):irqn(input_irqn) { IRQDefaultRegister( this, input_irqn);}
		virtual void OnHandler() { Empty(); }
		virtual ~IRQHandler() { IRQDefaultUnRegister( irqn ); }
};
static IRQHandler DefaultHandler(0);


void IRQDefaultHandler(int input_irqn)
{
	//IRQN	从-3开始,对应数组要加 3
	input_irqn+=3;
	handler[input_irqn%NVIC_COUNT]->OnHandler();
}
void IRQDefaultInit()
{
	static bool inited = false;
	if( inited == false )
	{
		for(int i=0; i< NVIC_COUNT; i++ )
			handler[i] = &DefaultHandler;
	}
}
void IRQDefaultRegister(IRQHandler* input_handler, int input_irqn)
{
	//IRQN	从-3开始,对应数组要加 3
	input_irqn += 3;
	input_irqn = input_irqn%NVIC_COUNT;
	handler[ input_irqn ] = input_handler;
}
void IRQDefaultUnRegister( int input_irqn)
{
	//IRQN	从-3开始,对应数组要加 3
	input_irqn += 3;
	input_irqn = input_irqn%NVIC_COUNT;
	handler[ input_irqn ] = &DefaultHandler;	
}
/***********************************************************/
//以SYSTICK 为例子
#include "stm32f10x.h"
//中断处理函数都成这样了,简单明了。
extern "C" void SysTick_Handler()
{
		IRQDefaultHandler( SysTick_IRQn );
}

class MySysTick : public IRQHandler{
	private:
		bool is_free;
	public:
		MySysTick();
		virtual void OnHandler();		
		bool Delay(unsigned int ms);
};
void MySysTick::OnHandler()
{
	SysTick->CTRL = SysTick_CTRL_TICKINT;
	is_free = true;
}
MySysTick::MySysTick():IRQHandler(SysTick_IRQn)
{
		SysTick->CTRL = SysTick_CTRL_TICKINT;
		is_free = true;
}
bool MySysTick::Delay( unsigned int ms)
{
	if( is_free )
	{
		ms %= 0xffffff;
		SysTick->LOAD = ms-1;
		SysTick->CTRL |= SysTick_CTRL_ENABLE;
		is_free = false;
		return true;
	}
	else
		return false;
}



int main()
{
	IRQDefaultInit();

	MySysTick sys_tick;
	volatile int count=0;
	
	while(1)
	{
		if( true == sys_tick.Delay(500) )
		{
			count++;
		}
		else
			__WFI();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值