2010-10-27 15:26:00 zzjslt 阅读数 243
  • 定时计数器-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    2040 人正在学习 去看看 朱有鹏

单片机之定时器/计数器总结

准备工作: 基础

(一)两种个工作方式:

1、定时工作方式,加1信号由振荡器的12分频产生,即每过一个机器周期,计数值增1,直至计满溢出为止。

2、计数工作方式,通过引脚T0T1对外部信号计数,外部脉冲的下降沿触发计数, 当输入脉冲信号从10的负跳变时,计数器就自动加1,外部输入的计数脉冲的最高频率为系统振荡频率的1/24,外部输入信号脉冲宽度至少保持1个机器周期。

(二)16位的定时器/计数器分别由两个专用寄存器组成,即T0TH0TL0构成;T1TH1TL1构成,这些寄存器由于存放定时和计数初值。

(三)两个重要的寄存器:

一个是8位的TMOD,另一个是8位的TCON 

TMOD 主要用于选定定时器的工作方式   TMOD  GATE C/T M1 M0 GATE C/T M1 M0

TCON主要用于控制定时器的启动与停止  TCON   TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0

控制计数器运行是根据  门控位gate和外部引脚Int0Int1 以及TRX来决定

(四)定时器/计数器有四种工作方式:

           T0有四种工作方式,T1有三种工作方式。

(1) 方式013位计数器方式

     溢出值是:213=8192

(2) 方式116位计数器方式

             溢出值是:216=65536

(3) 方式28位自动重装初值方式

溢出值是:28=256

(4) 方式3T0分成两个独立的8位计数器方式

(五)接着比较重要的是定时器/计数器的初始化

初值X的计算:X  =   M  -  计数值(计数次数)

 实战:

 写了两个比较简单的应用程序

1.流水灯控制程序(半秒点亮一个灯,如果你想要相隔时间更长的话则需要更换晶振,我开发板上的晶振是 12MHZ的所以就定半秒了)功能已在开发板上实现,代码:

   org  0000h

     ljmp main

     org  000bh

     ljmp loop

main:mov tmod,#01h

     mov tcon,#10h

     mov ie,#82h

     mov th0,#3ch

     mov tl0,#0b0h

     mov a,#0feh

     mov p1,a

     sjmp $

loop:rl a

     mov p1,a

     mov th0,#3ch

     mov tl0,#0b0h

     reti

     End

2.根据T0(P3.4)输入低频负脉冲,要求P3.4每次发生负调变时,P1.0输出一个1ms的方波,看书花了将近20分钟才看懂了后改编,这里的系统晶振得6MHZ才行 代码:

       org 0000h

       ljmp main

       org 000bh

       ljmp t0i

       org 001bh

       ljmp t1i

main:   mov tmod,#25h

    mov ie,#82h

        mov ip,#0ah

    mov tcon,#10h

      mov th0,#0ffh

    mov tl0,#0ffh

      mov th1,#06h

     mov tl1,#06h

   clr f0

loop:  jnz f0,loop

   setb et1

   setb tr1

loop1: ajmp loop1 

t0i:   clr tr0  

       setb f0

       reti

t1i: cpl p1.0

    reti

       

至于门控位它可用于计算脉冲宽度代码更简单只需设置 tmod即可 代码就不放在这了

 

待续…………

2016-05-26 15:48:00 he_wen_jie 阅读数 3229
  • 定时计数器-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    2040 人正在学习 去看看 朱有鹏

定时器顾名思义就是设定一段时间,这段时间到了之后可以触发中断,在中断中处理我们的任务。定时器还有一个功能就是计数,每次一个出发定时器内部的TH.TL就会加一,如果加满了就会产生溢出中断。那如何控制定时器呢?
第一个是模式寄存器TMOD

gate T/C M1 M0 gate T/C M1 M0
定时器1 定时器2

其中的T/C标志用来选择定时功能还是计数功能。为1表示定时,为0表示计数。

M1 M0 工作模式
0 0 方式0,13位计数/计时器
0 1 方式,1,16位计数/计时器
1 0 方式2,8位自动加载计数/计时器
1 1 方式3,仅适用于T0,定时器0分为两个独立的8位定时器/计数器TH0及TL0,T1在方式3时停止工作

还有一个TCON的寄存器

TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
  • TF1:定时器T1溢出标志,可由程序查询和清零,TF1也是中断请求源,当CPU响应T1中断时由硬件清零。
  • TF0:定时器T0溢出标志,可由程序查询和清零,TF0也是中断请求源,当CPU响应T0中断时由硬件清零。
  • TR1:T1充许计数控制位,为1时充许T1计数。
  • TR0:T0充许计数控制位,为1时充许T0计数。
  • IE1:外部中断1请示源(INT1,P3.3)标志。IE1=1,外部中断1正在向CPU请求中断,当CPU响应该中断时由硬件清“0”IE1(边沿触发方式)。
  • IT1:外部中断源1触发方式控制位。IT1=0,外部中断1程控为电平触发方式,当INT1(P3.3)输入低电平时,置位IE1。
  • IE0:外部中断0请示源(INT0,P3.2)标志。IE0=1,外部中断1正在向CPU请求中断,当CPU响应该中断时由硬件清“0”IE0(边沿触发方式)。
  • IT0:外部中断源0触发方式控制位。IT0=0,外部中断1程控为电平触发方式,当INT0(P3.2)输入低电平时,置位IE0。

中断标号可以看一下

中断号 中断源 中断入口地址
0 INT0—外部中断0 0003H
1 T0 — 定时器/计数器0 000BH
2 INT1—外部中断1 0013H
3 T1 —定时器/计数器1 0018H
4 TI/RI 串行口中断 0023H

定时和计数的主要寄存器是THx,TLx。这两个寄存器是用来存储计数值和定时值的。当选择计数功能是每一次脉冲,THTL寄存器的值都会自动加一,当超出选定模式容纳的最大计数值是,TF会硬件置一,产生中断。选择级数功能时,每一个时钟周期都会自动加一,一直加到选定模式的容许的最大值,此时会出发中断。简单说定时器的中断有两种方式,一种是计数值达到最大(定时或计数都可以),会产生溢出中断。另一种是外部脉冲触发中断(只有计数时),此时的中断标志位IT需要软件清除。
那么如何定时呢,比如定时50ms。定时器每一个机器周期自动加一(时钟周期 = 1/晶振频率,机器周期是12个时钟周期)。如果晶振是12M,那么一个机器周期是12 * 1 / 12M = 1us.如果我们定时50ms,那么计数器加了50ms/1us = 50000次。如果THTL初始设置为0,当THTL为50000时我们就可以进行操作了,但是问题是如何捕获THTL=50000这个事件,所以我们让THTL初始值 = 65536-50000 = 15536,这样定时器从15536一直加到65536就可以产生溢出中断,我们可以捕获中断事件,并且进行频率读取。读取频率是设置定时器为计数模式,每一个脉冲THTL加一,只要在定时中断中读取就可以计算出频率。

我用51做的是频率计。定时1设置为计数功能,定时器0设置定时功能,定时为50ms,每50ms进一次中断,20次中断为1s,读取计数器的值,这个值就是频率。

uint16_t fre = 0;
uint8_t extfre=0;
void main()
{   
    TMOD = 0x51;  //0101 0001,定时器1选择计数功能,定时器0选择定时功能,都工作在模式一
    TH0 = (65536-50000) / 256; //设定初始值
  TL0 = (65536-50000) % 256;
  EA = 1;
  ET0 = ET1 = 1;//使能定时器T0,T1 Enable Time
  TR0 = TR1 = 1;//定时器运行  Time Run

    while(1)        
    {
    }
}
void T0_time()interrupt 1    //50ms
{
    static uint8_t count = 0;

    TH0=(65536-50000)/256; //初始化定时器
  TL0=(65536-50000)%256;

    if(20 == ++count)//1s
    {
        count = 0;
        fre = extfre << 16 + TH1 << 8 + TL1;
        TH1 = TL1 =0;//初始化计数器
        extfre = 0;
    }
}
void T1_time()interrupt 3 
{
    if(TF1) 
    {
        extfre++;
    }
}
2019-03-18 15:24:21 Easadon 阅读数 186
  • 定时计数器-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    2040 人正在学习 去看看 朱有鹏

程序中实现延时:1.软件延时  2.硬件延时

软件延时缺点:延时过程中,CPU时间被占用,无法进行其他任务,导致系统效率降低。延时时间越长,该缺点便越明显,因此软件延时只适用于短暂延时,或简单项目。

51单片机中有两个定时/计数器T0、T1,既可以实现定时功能,也可以实现计数功能。

T0可工作在四种定时器模式下,

在定时方式1下,定时/计数器0的核心是一个16位宽的由计数脉冲触发的按递增规律(即累加方式)工作的循环累加计数器(TH0+TL0)。从预先设定的初始值开始,每来一个计数脉冲就加1,当加到计数器为全1时,再输入一个脉冲,就会发生            溢出现象,计数器回零,同时产生溢出中断请求信号(TF0置1)。如果定时/计数器工作于定时模式,则表示定时时间已到。

定时器操作步骤:
选择工作方式(设置M1,M0)
选择控制方式(设置GATE)
选择定时器还是计数器模式(设置C/T)
给定时/计数器赋初值(设置THx和TLx)
开启定时器中断(设置ET0或ET1)
开启总中断(设置EA)
打开计数器(设置TR1或TR0)

 

相关寄存器:

1计时器模式寄存器  TMOD (89H)

D7

D6

D5

D4

D3

D2

D1

D0

GATE

C/T

M1

M0

GATE

C/T

M1

M0

→                计时器1                ←   →                计时器0               ←

 

GATE  :GATE=1时表示T0或T1必须在INT0或INT1是高点位时才会初始化。

C/T    :C/T=1由外引脚T0或T1做计数脉冲,C/T=0由TH和TL做定时数。

M1,M0:用来选择计时计数器工作模式

M1

M0

工作模式

说明

0

0

0

13位计时计数器 (8192)

0

1

1

16位计时计数器 (65536)

1

0

2

8位计时计数器,可自动重新载入计数值 (256)

1

1

3

当成两组独立的8位计时器(256,T0和T1不能同时用)

4计时器控制寄存器  TCON (88H)

D7

D6

D5

D4

D3

D2

D1

D0

TF1

TR1

TF0

TR0

IE1

IT1

IE0

IT0

→            用于定时/计数器             ←   →               用于中断                ←

TF1  :TF1=1表示T1有中断产生。

TR1  :TR1=1表示T1开始运行。

TF0  :TF0=1表示T0有中断产生。

TR0  :TR0=1表示T0开始运行。

IE1   :IE1=1表示INT1有中断产生。

IT1   :IT1=1表示INT1为下降沿触发,IT1=0表示INT1为低电平触发。

IE0   :IE0=1表示INT0有中断产生。

IT0   :IT0=1表示INT0为下降沿(负跳变)触发,IT0=0表示INT0为低电平触发。

 其实按着步骤一步一步来的话,定时器的使用也是比较简单的

老规矩,直接上代码,辅助理解

以下代码是利用定时器实现60s的循环倒计时

实现原理:定时器每50ms中断一次,中断20次就是1s

/*****************************
* 本代码实现的是:	 
*利用定时器中断实现60s循环倒计时		       	                     
******************************/   

#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int

sbit duan = P2^6;
sbit wei = P2^7;
sbit K1 = P3^4;
sbit K2 = P3^5;
sbit K3 = P3^6;
sbit K4 = P3^7;

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                        0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};	 

uchar countt = 0;
void delay(uchar xms)
{
	int i,j;
	for(i = xms;i >= 0;--i)
	{
		for(j = 112;j >= 0;--j)
		{
		;
		}
	}
}

uchar time = 60;
void display(unsigned char a)
{
	P0 = 0;
	duan = 1;
	duan = 0;
	P0 = table[a/10];
	duan = 1;
	duan = 0;
	P0 = 0xfe;
	wei = 1;
	wei = 0;
	delay(1);
	P0 = table[a%10];
	duan = 1;
	duan = 0;
	P0 = 0xfd;
	wei = 1;
	wei = 0;
	delay(1);

}
void Timer0nit()
{
	TMOD |= 0x01;
	TH0 = 0x4c;
	TL0 = 0x00;  //50ms
	ET0 = 1;
	EA = 1;
	TR0 = 1;

}
void main()
{
	Timer0nit();
	while(1)
	{
		if(countt == 20)
		{
			time--;
			countt = 0;
		}
		display(time);
		if(time == 0)
		{
			time = 60;
		}
	}
}
void Timer0() interrupt 1
{
	TH0 = 0x4c;
	TL0 = 0x00;  //50ms
	countt++;
}

 

 

本文前面部分理论主要是“亚博科技”的学习资料做整理的

2015-03-07 13:25:49 lonely_Quan 阅读数 5136
  • 定时计数器-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    2040 人正在学习 去看看 朱有鹏

一、实验内容

采用12MHZ时钟频率的单片机,通过一个开关输入,触发定时计数。按下开关10次,计算按键的平均时间,并通过数码管显示出来。

二、实验目的

了解定时器的各种工作方式

掌握定时器/计数器的使用和编程方法

三、实验设备

DELL台式机 、keilC51版本7、proteus版本6

四、实验电路图


五、程序流程图


六、程序源码  

#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit Dot=P0^7;//小数点
sbit P3_5=P3^5;//按钮
uchar Count=0;//循环次数
uchar flag=0;//判断标志
uchar Times=0;
//数码管段码定义
uchar code DSY_CODE[]=
{ 0xc0,0xf9,0xa4,0xb0,
  0x99,0x92,0x82,0xf8,
  0x80,0x90
};
//延时
void DelayMS(uint x)
{
uchar i;
while(--x)for(i=0;i<120;i++);
}
//6只数码管上显示的数字
uchar Digit[]={0,0,0,0,0,0};
void main()
{
  uchar i,j;
P0=0xff;
P2=0x00;
P3_5=1;
TMOD=0x01;//设T0为定时方式1
EA=1;ET0=1;//开总控,INT0
TH0=(65536-50000)/256;//设置50ms定时
TL0=(65536-50000)%256;
while(Count!=10){
if(P3_5==1)//开关高电平
{
if(flag==1)//判断标志位
  {
flag=0;Count++;//修改标志位,循环次数+1
}
           TR0=0;//关中断
}
else if(P3_5==0)//开关低电平
  {
flag=1; TR0=1;//修改标志位,关中断
}
}
//显示数码管
while(1)
{
j=0x80;
for(i=0;i<6;i++)
{
j=_crol_(j,1);
P2=j;
P0=DSY_CODE[Digit[i]];
if(i==2)//因为是平均时间,所以小数点左移一位
Dot=0;
DelayMS(2);
}
} 	
}
void Time0()interrupt 1
{	
uchar i;
TH0=(65536-50000)/256;//定时
TL0=(65536-50000)%256;
if((++Times)==2)//50ms*2=0.1s
{
Times=0;
Digit[0]++;//0.1s累加
for(i=0;i<=5;i++)//进位处理
{
if(Digit[i]==10)
{
Digit[i]=0;
if(i!=5)
Digit[i+1]++;
}
}
}
} 


2019-12-24 18:04:51 weixin_45474595 阅读数 134
  • 定时计数器-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    2040 人正在学习 去看看 朱有鹏

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,测量出来多了一点点,是运行程序锁消耗的时间,为什么官方给出的数据跟实际测量的不一样我就不得而知了。

没有更多推荐了,返回首页