技術共有

04:タイマー

2024-07-12

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


タイマを使用する場合、内部発振回路に依存してカウントします。タイマを使用するように設定されている場合、カウンタ メモリの値はマシン サイクルごとに 1 ずつ増加します。

1. タイマーの設定方法

1. 水晶発振器(水晶発振器)がパルスを発し、そのパルス数をタイミングとして記録します。
2. パルスの周波数がクロック周波数であり、この周波数の逆数が発振周期 (クロック サイクル) であり、これはコンピュータの時間の最小単位でもあります。
ここに画像の説明を挿入します

図に示すように、水晶発振器の周波数は 11.0592MHz なので、そのクロック周期は 1/11.0592MHz (秒)、つまり 1 パルス周期に非常に長い時間がかかります。

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 つのレジスタがあります。1 つ目は TCON、2 つ目は TCOM で、どちらもそれぞれ 8 ビットです。
  • 図に示すように、タイマには 2 つのタイプがあります。1 つ目はビット タイマ T0、2 つ目はタイマ 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 は合計 16 ビットで、上位 8 ビット TH0 と下位 8 ビット TL0 に分かれています。したがって、合計 2^16 (65536) 個の数値をカウントでき、1 つの数値をカウントする周期は 1.085us であるため、デフォルトでは 0 からカウントを開始し、累積タイミングは約 71ms になります。

3. ケース: タイマ T0 を使用して、1 秒間隔で LED をオン/オフに制御します。

コード①:

#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