应广单片机-16位计数定时器

16位计数器的使用

PMS132B内置一个16位硬件计数器,我一般都是用来做定时器中断

下面这个是数据手册上面介绍的

只能向上计数
只能向上计数,计数初始值可以通过stt16指令来设置,待会看代码里面,用来做中断就是当计数溢出是触发中断,具体的看例程吧。

/************************************************************************************/
/*							  16位计数定时器T16 								    */
/************************************************************************************/
#define USER_TIMER_CONFIG()		$ T16M IHRC, /16, BIT10 //对t16寄存器进行配置   时钟:IHRC 分频:/16  中断源:BIT10   
#define ENABLE_TIMER()			SET1 INTEN.2 //$ INTEN T16 //开定时器中断
#define DISENABLE_TIMER()		SET0 INTEN.2 //关定时器中断
#define INIT_TIMER_VALUE(n)		STT16 n//装载定时器计数值
#define EA_INT()				ENGINT//开总中断
#define DIS_INT()				DISGINT//关总中断
#define CONST_TIME_VALUE        0//0x10E//224//  (BIT - CONST_TIME_VALUE) / (IHRC / 分频) = us
word    T16val;
/************************************************************************************/
//一次中断的时间计算公式   (BIT - CONST_TIME_VALUE) / (IHRC / 分频) = us
//                         (2^10 - 0) / (16 / 4) = 1024us    
void Set_User_T16(void)
{	
	USER_TIMER_CONFIG();
	T16val = CONST_TIME_VALUE;
	INIT_TIMER_VALUE(T16val);
	INTRQ = 0;//清除INTRQ
	EA_INT();
	ENABLE_TIMER();
}

void	FPPA0 (void)
{
	.ADJUST_IC	SYSCLK=IHRC/4, IHRC=16MHz		//	SYSCLK=IHRC/2
    // SetPortA();
    // SetPortB();
    Set_User_T16();


	while (1)
	{
//		...
//		wdreset;
        //主函数功能实现区

	}
}


void	Interrupt (void)
{
	pushaf;

	if (Intrq.T16)
	{	//	T16 Trig
		//	User can add code
		Intrq.T16	=	0;
		T16val = CONST_TIME_VALUE;
        INIT_TIMER_VALUE(T16val);
        //中断执行区
        
        
	}

	popaf;
}

有关其他的外部IO引脚中断目前正在研究中,没弄明白怎么回事,这个计数器中断时可以直接使用的,数据手册里面的计算公式跟我们实际测量出来的不一样,上面那个公式是我自己测量总结的,可行,大家也可以这样配置然后在中断里面通过IO口翻转看一下进一次中断的时间,下面那个是编译器里面使用手册对T16的计算方法。

在这里插入图片描述

有关16位计数器的就分享到这里,下次更新8位计数器和11位计数器的使用。

今天看到了官方的DEMO,16位定时器的中断时间还是跟我们实际测量到的不一样,先看一下官方给的DEMO 吧,`BIT p_Key_In : PA.0; // At ICE, has the circuit, you can try it.
BIT p_LED_Out : PA.1; //

void FPPA0 (void)
{
.ADJUST_OTP_IHRCR 4MIPS // IHRC/4 = 4MIPS, WatchDog Disable, RAM 0,1 temporary be used

$	p_LED_Out		Out, Low;
$	p_Key_In		In;	//, Pull;
PAPH		=		_FIELD(p_Key_In);

$ T16M		IHRC, /1, BIT11;			//	16MHz / 1 = 16MHz : the time base of T16.   //这里是官方的对16位计数器寄存器的配置

BYTE	Key_Flag;
BIT		f_Key_In	:	Key_Flag._BIT(p_Key_In);
Key_Flag			=	_FIELD(p_Key_In);

BYTE	Sys_Flag	=	0;
BIT		f_Key_Trig	:	Sys_Flag.0;
BIT		f_LED_On	:	Sys_Flag.1;
BIT		t16_10ms	:	Sys_Flag.2;
BIT		t16_1s		:	Sys_Flag.3;
BIT		t16_over2	:	Sys_Flag.4;
BIT		t16_over3	:	Sys_Flag.5;

// pmode Program_Mode;
// fppen = 0xFF;

BYTE	t16_flag;
BYTE	count1, count2, count3;
BYTE	cnt_Key_10ms	=	4;				//	Key debounce time = 40 mS

while (1)
{
	if  (INTRQ.T16)
	{
		INTRQ.T16		=	0;
		If (--count1 == 0)					//	DZSN  count
		{
			count1		=	39;				//	256uS * 39 = 9,984 uS ≤ 10 mS 
			t16_10ms	=	1;
		}
	}

//
WORD T16_Cnt, T_100mS;
ldt16 T16_Cnt;
if (T16_Cnt.15)
{
t16_over3 = 1;
}
else if (t16_over3)
{
t16_over3 = 0;
if (–count3 == 0)
{
count3 = 244; // 4,096uS * 244 = 999,424 uS ≤ 1S
t16_1s = 1;
}
}
//*
if (T16_Cnt.12)
{
t16_over2 = 1;
}
else if (t16_over2)
{
t16_over2 = 0;
if (–count2 == 0)
{
count2 = 195; // 512uS * 195 = 99,840 uS ≤ 100 mS
T_100mS++;
}
}
//
A = (t16_flag ^ T16_Cnt$1) & 0x20; // Another way for calucate 100 mS
if (! ZF) // it use t16_flag.5 ^ T15_Cnt.13
{ // the code is more little,
t16_flag ^= A; // but, not everyone like it.
if (–count2 == 0)
{
count2 = 195;
T_100mS++;
}
}
//
/

	while (t16_10ms)
	{
		t16_10ms	=	0;

		A	=	(PA ^ Key_Flag) & _FIELD(p_Key_In);	//	only check the bit of p_Key_In.
		if (! ZF)
		{										//	if is not same,
			if (--cnt_Key_10ms == 0)
			{									//	and over debounce time.
				Key_flag	^=	_FIELD(p_Key_In);
				f_Key_Trig	=	1;				//	so Trigger, when stable at 30 mS.
			}
			else	break;
		}
		cnt_Key_10ms	=	4;		break;
	}

	if (f_Key_Trig)
	{
		f_Key_Trig	=	0;

		if (! f_Key_In)
		{
			if (p_LED_Out)
			{						//			3 )		if next key in, then LED off
				f_LED_On	=	0;
				p_LED_Out	=	0;
			}
			else
			{						//	1 )				when first key press, then LED on
				p_LED_Out	=	1;
			}
		}
		else
		{
			if (p_LED_Out)
			{						//		2 )			when first key release, then start to count
				f_LED_On	=	1;
				T_100mS		=	0;
			}
			else
			{						//				4 )	nothing to do
			}
		}
	}

	if (f_LED_On)
	{
		if (T_100mS >= 50)
		{	//	Over 5 S, then close
			f_LED_On	=	0;
			p_LED_Out	=	0;
		}
	}
}

}
`

官方这个DEMO直接在大循环里面判断的中断,实际建项目的时候,会出来一个单独的中断函数,下面看一下实际建项目的源代码,是我自己写的,然后用逻辑分析仪抓取出了波形。

#include	"extern.h"

//.outfile %S_%T_%x.PDK

typedef byte u8; 
typedef word u16;
typedef EWORD u24;
typedef DWORD u32;

#define     SetPortA()      paph=0x18;pac=0x10;pa=0x00  
#define     SetPortB()      pbph=0x00;pbc=0x00

#define     LED_ON()        PA.4 = 1
#define     LED_OFF()       PA.4 = 0

u16 T16val;
u8 gCnt;

void sys_init(void)
{
    T16val = 0;
    gCnt = 0;
    
}

/************************************************************************************/
/*							  16位计数定时器T16 								    */
/************************************************************************************/
#define USER_TIMER_CONFIG()		$ T16M IHRC, /1, BIT11 //对t16寄存器进行配置   时钟:IHRC 分频:/16  中断源:BIT10   
#define ENABLE_TIMER()			SET1 INTEN.2 //$ INTEN T16 //开定时器中断
#define DISENABLE_TIMER()		SET0 INTEN.2 //关定时器中断
#define INIT_TIMER_VALUE(n)		STT16 n//装载定时器计数值
#define EA_INT()				ENGINT//开总中断
#define DIS_INT()				DISGINT//关总中断
#define CONST_TIME_VALUE        0//0x10E//224//  (BIT - CONST_TIME_VALUE) / (IHRC / 分频) = us

/************************************************************************************/
//一次中断的时间计算公式   (BIT - CONST_TIME_VALUE) / (IHRC / 分频) = us
//                         (2^10 - 0) / (16 / 4) = 1024us    
void Set_User_T16(void)
{	
	USER_TIMER_CONFIG();
	T16val = CONST_TIME_VALUE;
	INIT_TIMER_VALUE(T16val);
	INTRQ = 0;//清除INTRQ
	EA_INT();
	ENABLE_TIMER();
}

void	FPPA0 (void) //主函数
{
	.ADJUST_IC	SYSCLK=IHRC/4, IHRC=16MHz		//	SYSCLK=IHRC/2
    SetPortA();
    SetPortB();
    sys_init();
    Set_User_T16();


	while (1)
	{
//		...
//		wdreset;
        //主函数功能实现区

	}
}


void	Interrupt (void) //中断函数
{
	pushaf;

	if (Intrq.T16)
	{	//	T16 Trig
		//	User can add code
		Intrq.T16	=	0;
		T16val = CONST_TIME_VALUE;
        INIT_TIMER_VALUE(T16val);
        //中断执行区
        if (gCnt) {  // 利用IO口翻转看中断时间
            LED_OFF();
            gCnt = 0;
        } else {
            LED_ON();
            gCnt = 1;
        }
        
	}

	popaf;
}

16位计数器的中断源是BIT11,/1分频,时钟IHRC16M,跟官方例程里面的一样,下面是我测量出来的波形,翻转一次的时间是130us,根据我上面程序里面的公式(2^11-0)/(16/1) = 128us,测量出来多了一点点,是运行程序锁消耗的时间,为什么官方给出的数据跟实际测量的不一样我就不得而知了。

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值