기술나눔

04: 타이머

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina


타이머를 사용하면 내부 발진기 회로를 사용하여 계산됩니다. 타이머 사용으로 구성되면 카운터 메모리 값은 기계 사이클마다 1씩 증가합니다.

1. 타이머 설정 방법

1. 수정 발진기(Crystal Oscillator)는 펄스를 방출하고 타이밍을 위해 펄스 수를 기록합니다.
2. 펄스의 주파수는 클럭 주파수이고, 이 주파수의 역수는 발진 주기(클럭 주기)이며, 이는 컴퓨터에서 가장 작은 시간 단위이기도 합니다.
여기에 이미지 설명을 삽입하세요.

그림에 표시된 것처럼 수정 발진기의 주파수는 11.0592MHz이고 클록 주기는 1/11.0592MHz(초)입니다. 즉, 하나의 펄스 주기에 매우 많은 시간이 걸립니다.

3. 기계주기를 CPU주기라 하고, 기본적인 동작에 소요되는 시간을 기계주기라 한다. 일반적으로 머신 사이클은 여러 클럭 사이클로 구성됩니다. 일반적으로 12배/6배입니다.
여기에 이미지 설명을 삽입하세요.

여기에 이미지 설명을 삽입하세요.

  • 1을 추가한 후 얼마나 시간이 지났나요?
    수정 발진기 주파수가 11.0592MHz이면 11059.2KHz = 11059200Hz와 같습니다.
    기계 사이클 = 12 x 클록 사이클 = 12 x (1/클록 주파수) 초 = 12 / 클록 주파수 초 = 12 / 11059200 초 = 12 000 000 / 11059200 마이크로초 = 1.085(us)
    즉, 12의 배수를 사용할 때 카운터는 1.085us마다 +1됩니다.

2. 계산을 구현하는 방법은 무엇입니까?

관련 레지스터 구성: 다음 그림은 타이머의 관련 레지스터를 보여줍니다.
여기에 이미지 설명을 삽입하세요.

  • 그림에 표시된 대로 2개의 레지스터가 있습니다. 첫 번째는 TCON이고 두 번째는 TCOM이며 둘 다 각각 8비트입니다.
  • 그림에 표시된 대로 타이머에는 두 가지 유형이 있습니다. 첫 번째는 비트 타이머 T0이고 두 번째는 타이머 T1입니다. 둘 다 각각 16비트입니다.

2.1. 제어 레지스터 TCON

여기에 이미지 설명을 삽입하세요.

TF0:定时器T0溢出中断标志,当定时器0开始计数时,计数到规定的时间时,定时器产生了溢出。TF0自动由0变位1(由硬件置1)。
如果不用中断,需要手动清零。

TR0:定时器T0的控制位,当为1时,定时器T0才能计数,相当于T0的开关(由软件控制)。
  • 1
  • 2
  • 3
  • 4

2.2. 작업 모드 등록 TCOM

여기에 이미지 설명을 삽입하세요.

GATE:门控制位,当GATE=0时:计数条件只有TR1一个(TR1=1就计数,TR1=0就不计数)。
			   当GATE=1时:是否计数不仅取决于TR1还取决于INT1引脚
C/T :时钟输入选择为,为1时,时钟从外部引脚P3.5口输入;为0时,时钟从内部输入
M1      M0
0        0        :13位定时器,使用高8位和低5位
0        1        :16位定时器,全用
1        0        :8位自动重装载定时器,当溢出时将TH1存放的值自动重装入TL1.
1        1        :定时器无效
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.3. 타이머 T0

여기에 이미지 설명을 삽입하세요.

타이머 T0은 상위 8비트 TH0와 하위 8비트 TL0으로 나누어 총 16비트를 갖는다. 따라서 총 2^16개의 숫자(65536)를 카운트할 수 있으며, 1개의 숫자를 카운트하는 주기는 1.085us이므로 기본값은 0부터 카운트를 시작하는 것이고, 누적 타이밍은 약 71ms이다.

3. 사례: 타이머 T0을 사용하여 LED가 1초 간격으로 켜지고 꺼지도록 제어합니다.

코드 ①:

#include <REGX52.H>

sbit LED1 = P3^7;
void main(void)
{
	int cnt = 0;
	LED1 = 1;//先让灯熄灭的状态
	
/*1、选择定时器T0,并配置为16位定时器*/
	TMOD =0x01;							// 0000 0001
	
/*
	2、定一个10ms的时间,数1下需要1.085us
	10ms需要数则需要数9216下,那从65536-9126=56320
	从56320这里开始数,数9216下就到了65536。当超过了
	65536时就报表了,控制寄存器TCON的TF0由0变为1	
*/
	TL0 = 0x00; //0000 0000
	TH0 = 0xDC;//1101 1100
	
/*3、打开定时器T0*/
	TR0 = 1;
	
	TF0 = 0;//先个溢出标志清零
	while(1)
	{
		if(TF0 == 1)//10ms报表了
		{	
			TF0 = 0;//软件清零,现在不使用中断
			TL0 = 0x00; //重新给初值
			TH0 = 0xDC;
			cnt++;
			if(cnt == 100)//数100次,相当于1s
			{
				cnt = 0;
				LED1 = !LED1;
			}
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

【메모】

  • 각 보고 후에 타이머에는 새로운 초기 값이 제공되어야 합니다.
  • cnt는 10밀리초마다 1씩 증가합니다. cnt가 100으로 증가하면 1초가 지났다는 의미입니다.

코드 최적화②:

#include <REGX52.H>

sbit LED1 = P3^7;

void Timer0_Init_10ms(void)//定时器初始化10ms
{
	TMOD =0x01;							
	
	TL0 = 0x00; //0000 0000
	TH0 = 0xDC;//1101 1100
	
	TR0 = 1;
	TF0 = 0;
}

void main(void)
{ 
	int cnt = 0;
	LED1 = 1;//先让灯熄灭的状态
	Timer0_Init_10ms();
	
	while(1)
	{
		if(TF0 == 1)//10ms报表了
		{	
			TF0 = 0;//软件清零,现在不使用中断
			TL0 = 0x00; //重新给初值
			TH0 = 0xDC;
			cnt++;
			if(cnt == 100)//数100次,相当于1s
			{
				cnt = 0;
				LED1 = !LED1;
			}
			
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

타이머 T0 초기화를 함수로 캡슐화하고 필요할 때 직접 호출합니다.
그러나 TMOD = 0x01을 사용하는 경우에도 결함이 있습니다.

假如定时器T1正在使用,且为16位定时器。则TMOD的高4位应该为:0x1(0001)
而我们使用定时器T0时TMOD初始为0x01,则TMOD的高4位为0x0(0000),则把定时器T1变为一个13位定时器了。所以还需要改进
  • 1
  • 2

코드 최적화 ③:

#include <REGX52.H>

sbit LED1 = P3^7;

void Timer0_Init_10ms(void)		//10毫秒@11.0592MHz
{
	//AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0xDC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void main(void)
{ 
	int cnt = 0;
	LED1 = 1;//先让灯熄灭的状态
	Timer0_Init_10ms();
	
	while(1)
	{
		if(TF0 == 1)//10ms报表了
		{	
			TF0 = 0;//软件清零,现在不使用中断
			TL0 = 0x00; //重新给初值
			TH0 = 0xDC;
			cnt++;
			if(cnt == 100)//数100次,相当于1s
			{
				cnt = 0;
				LED1 = !LED1;
			}
			
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

TMOD의 초기화는 다음과 같습니다.

TMOD &= 0xF0;		//设置定时器模式
TMOD |= 0x01;		//设置定时器模式
  • 1
  • 2

이렇게 초기화하면 어떤 이점이 있나요?

假如定时器T1正在使用,且为16位定时器。则TMOD的高4位应该为:0x1(0001),而要使用定时器T0,且也为16位定时器,则TMOD =  0x11;
TMOD &= 0xF0;表示TMOD = TMOD & 0xf0,则与出来的TMOD = 0x10,由此可见,这一步就是让TMOD的高4位不变,低4位清零。
TMOD |= 0x01;表示TMOD = TMOD | 0x01,则或出来的TMOD = 0x11,由此可见,这一步就是让TMOD的高4位不变,低4位初始化。
通过这样初始化,既保证了TMOD的高4位不变(不改变定时器T1的初始化),由对低4位进行了改变(对定时器T0初始化)。
当然:也可以直让TMOD = 0x11;
  • 1
  • 2
  • 3
  • 4
  • 5