研究ノート | カウンタ | Keil ソフトウェアの 0xFD 問題 | I/O ポート構成 | STC32G マイクロコントローラのビデオ開発チュートリアル (Brother Chong) | エピソード 12: カウンタの役割と重要性

1. カウンターの目的

DC ブラシ付きモーターの場合、プラスとマイナスの 2 つの端子が接続されている場合、モーターは回転できます。
ここに画像の説明を挿入

ローターは何回転しますか?
裏側にこのようなコードディスクを取り付けます。ここに光電穴が 60 個あるとしますよね? そうすると
1 回転すると 1 軸で 60 個出力できます。 、ブロックされている場合は 1 を出力し、ブロックされていない場合は 0 を出力し、
2 つのパスが交互にこの円内に 60 個のパルスがある場合、60 個のハイレベルとローレベル (パルスの合計数を で割ったもの) 60は回転数です)、
このセクションではスイッチ、アナログカウンターの機能を使用します。
エンコーダはパルス出力も実現でき、出力波形:方形波
液体がどれだけ流れたか、途中で比例変化があります。1 つの High と 1 つの Low を 1 つのパルスとしてカウントします。
出力信号にこのようなハイレベルとローレベルの変化がある限り、その数をカウントしたい場合は、カウンター機能を使用できます。
ここに画像の説明を挿入

2. カウンタ構成

ここに画像の説明を挿入

GATE=O(TMOD.7) (TR1=1 など) の場合、タイマーがカウントされます。GATE=1 のとき、外部入力 INT1 によるタイマ 1 の制御が可能となり、
パルス幅測定が可能になります。TR1 は TCON レジスタの制御ビットです。TCON レジスタの各ビットの具体的な機能の説明については、前のセクションの TCON レジスタの概要を参照してください。
c/T=0 の場合、マルチウェイ スイッチはシステム クロックの分周出力に接続され、T1 は内部システム クロックをカウントし、T1 はタイミング モードで動作します。スイッチは
外部パルス入力 P3.5/T1 に接続されており、T1 はカウントモードで動作します。
STC マイクロコントローラーのタイマー 1 には 2 つのカウント レートがあります: 1 つは 12T モードで、従来の 8051 マイクロコントローラーと同じ 12 クロックごとに 1 を加算します。もう 1 つは 1T モードで、クロックごとに 1 を加算します。従来の 8051 マイクロコントローラーの 12 倍です。T1 のレートは特殊機能レジスタ AUXR の T1x12 によって決まります。T1x12=0 の場合、T1 は 12T モードで動作します。T1x12=1 の場合、T1 は 1T モードで動作します。タイマ 1 には 2 つの隠しレジスタ RL_TH1 および RL_TL1 があります。RL_TH1 と TH1 は同じアドレスを共有し、RL_TL1 と TL1 は同じアドレスを共有します。TRI=0、つまりタイマ/カウンタ I が無効の場合、TL1 に書き込まれた内容は RL_TL1 に同時に書き込まれ、
TH1 に書き込まれた内容は RL_TH1 にも同時に書き込まれます。TR1=1、つまりタイマ/カウンタ I の動作が許可されている場合、TL1 に書き込まれた内容は、実際には現在のレジスタ TL1 ではなく、隠しレジスタ RL_TL1 に書き込まれます。現在のレジスタ TH1 に書き込み、隠しレジスタ RL_TH1 に書き込みます。これにより、16 ビット リロード タイマーを巧みに実装できます。TH1とTL1の内容を読み出す場合、読み出される内容はTH1とTL1の内容であり、RL_TH1とRL_TL1の内容ではありません。
タイマ 1 がモード 1 (TMOD[5:4][M1.MO]=00B) で動作する場合、[THl, TL1l] のオーバーフローは TF1 を設定するだけでなく、[RL_TH1, RL_TL1] の内容を自動的にリロードします。 TH1、TL1]。
T1CLKO/INT_CLKO.1=1 の場合、P3.4/TO ピンはタイマ 1 のクロック出力 T1CLKO として設定されます。出力クロック周波数は、T1 オーバーフロー レート/2 です。
C/T=0 の場合、タイマ/カウンタ T1 は内部システム クロックをカウントします。
T1 が 1T モードで動作するときの出力クロック周波数 (AUXR.6/T1x12=1) = (SYsclk) (TM1PS+1) (65536 -) [RL_TH1,RL_TL1])/2T1 が 12T モードで動作するときの出力クロック周波数 (AUXR.6/TIx12=0)=(SYSclk)(TM1PS+1)/12/(65536-[RL_TH1,RL_TLI])/2 の場合C/T=1、タイマ/カウンタ T1 が外部パルス入力 (P3.5/Tl) をカウントすると、出力クロック周波数 = (Tl_Pin_CLK)/(65536-[RL_TH1,RL_TL1])/2

Tl_C/T: Tl_C/T ビットに 1 を書き込むとタイマ 1 をタイマまたはカウンタとして使用するように制御します、0 にクリアするとタイマ (内部システム クロックのカウント) として使用します、1 に設定すると使用しますカウンタとして (カウント用のピン T1/P3 .5 外部パルスへ)。
Tl_GATE: タイマ 1 を制御します。1 に設定すると、INT1 ピンが High で TRI 制御ビットが 1 の場合にのみタイマ/カウンタ 1 をオンにできます。ここでは TR1 カウントのみが必要なため、Tl_GATE を 0 に設定できます。

公式ルーティン

ここに画像の説明を挿入
ここに画像の説明を挿入
TMOD = 0X40 =0100 0000 に設定します。つまり、カウントのために Tl_C/T を 1 に設定します。16 ビットのオートリロード。
TL1 = 0xff; //1111 1111,65535、もう 1 つのパルスに相当し、割り込みを入力してピンを反転できます。パルスが来るたびに反転します。
TH1 = 0xff;

始める

ボタン シミュレーションを使用し、高レベルでリリースし、連続的に押して放します。
参考として次の例を使用してください。
ここに画像の説明を挿入

内部 4K プルアップ抵抗をオンにし、ポート プルアップ抵抗制御レジスタ (PxPU) を使用する必要があります。ここに画像の説明を挿入

ここに画像の説明を挿入

STC-ISP ソフトウェアには、この IO ポート用の構成ツールがあります。
ここに画像の説明を挿入

8. counter という名前に変更された前のセクションのルーチンを使用すると、T1 を使用して実装できます。
void Timer0_Isr(void) 割り込み 1 をマスクし、T0 割り込みマスクを呼び出します。これはこのセクションでは必要ありません。
マニュアルの手順通りに書きます。

ヒント: コンパイル中にエラー「FILE DOES NOT EXIST」が表示されます。

ここに画像の説明を挿入

C251 FATAL-ERROR -
  ACTION:  OPENING INPUT-FILE
  FILE:    \STC32\8.计势鱘COMM\stc32g.h
  ERROR:   FILE DOES NOT EXIST
C251 TERMINATED.

これには、「付録 I Keil ソフトウェアの 0xFD 問題の説明」が含まれます。

Keil プロジェクトのパス名の文字には、OxFD エンコードの中国語文字を含めることはできません。そうしないと、Keil ソフトウェアはプロジェクトを正しくコンパイルできません。したがって、このプロジェクトのディレクトリ名を変更する必要があります:
英語名: 8.Count_T1 に変更します。コンパイルは正常に完了し、ボタン LED が周期的に点灯および消灯します。
授業の後、H1 と TL1 の値を変更して、オンとオフの 2 クリックを実現する実験を行うことができます。
この値は、STC-ISP の I/O ポート構成ツール、詳細構成、および設定条件を使用して決定できます。
ここに画像の説明を挿入

設定コードを取得します: P3PU = 0x20;

3. カウンターの適用

2017年度全国大学生電子設計コンクールの試験問題 - DCモーター速度測定装置(問題O)を参照、問題は次のとおりです
ここに画像の説明を挿入

問題解決のアイデアは次のとおりです。
ここに画像の説明を挿入

M法速度測定:周波数測定法とも呼ばれます。一定時間(秒単位)のエンコーダパルス数をカウントし、速度値を算出する方法です。1回転のエンコーダパルスの総数をC、時間T0内にカウントしたエンコーダパルス数をM0とすると、速度nの計算式は次のようになります。
ここに画像の説明を挿入

まず、u16 Count_T1 = 0 という変数を定義します。初期値は 0 に設定されます。
割り込み処理関数を書き換えます: void Timer0_Isr(void) 割り込み 1:

void Timer0_Isr(void) interrupt 1 //1ms进来执行一次,无需其他延时,重复赋值
{

	TimCount++; //计算2000次=2s,可以一直运行
	if(TimCount>= 2000)
	{
		TimCount = 0;

		Count_T1 = (TH1 * 256) + TL1; //单位:转/s,

		TH1 = 0;
		TL1 = 0;

		Show_Tab[4] = TimCount/1000%10;
		Show_Tab[5] = TimCount/100%10+10;
		Show_Tab[6] = TimCount/10%10;
		Show_Tab[7] = TimCount/1%10;		//取10位

	}

	SEG_Fre();		//计算得到结果后,数码管刷新

}

この例の完全なコードは次のとおりです。

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"

#define KEY1 P32		//定义一个按键 引脚选择P32
#define KEY2 P33		//定义一个按键 引脚选择P33

#define BEEP P54		//定义一个按键 引脚选择P54

#define SEG_Delay  1	//延时多少ms

#define MAIN_Fosc 24000000UL	//定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
	
u8 SEG_Tab[21] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff};	//0-9段码,0-9带小数点
u8 COM_Tab[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };	//0-7的位码数组
u8 Show_Tab[8] = {20,20,20,20,0,0,0,0};

u32 TimCount = 0;		//计数单位1ms
bit RUN_State = 0;		//开始运行/结束运行
u8 num = 0;

u16 Count_T1 = 0;

void sys_init();	//函数声明
void delay_ms(u16 ms);	//unsigned int 

void SEG_Fre( void ) 
{
	//位码选择第一位,段码选择0  
	P7 = COM_Tab[num];			//位码的选择
	P6 = SEG_Tab[Show_Tab[num]];//需要显示的数字的内码 赋给 P6   NUM =0 -> Show_Tab[num]] = 1 -> p6 = oxF9 
	//delay_ms(SEG_Delay);

	num++;
	if( num >7 )
		num = 0;	
}

//========================================================================
// 函数名称: Timer0_Init
// 函数功能: 定时器0初始化
// 入口参数: 无
// 函数返回: 无
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者: 
// 其他备注: 
//========================================================================
void Timer0_Init(void)		//1毫秒@24.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x30;				//设置定时初始值
	TH0 = 0xF8;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
}




void main()					//程序开始运行的入口
{
	
	sys_init();				//USB功能+IO口初始化
	usb_init();				//usb库初始化

	TMOD = 0x50;			//设置计数器模式   
	TL1 = 0x00;				//设置计数初始值
	TH1 = 0x00;				//设置计数初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1 = 1;				//使能定时器1中断
	    
	P3PU = 0x20; 			//打开内部上拉4.1K

	Timer0_Init();
	
	EA = 1;					//CPU开放中断,打开总中断。
	
	while(1)		//死循环
	{
		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
			continue;
		if( bUsbOutReady )								
		{
			usb_OUT_done();

		}

	
		
	}
}


void Timer0_Isr(void) interrupt 1
{
	
	
	TimCount++;			//每隔1ms+1		//	计数到2000 = 2s
	if( TimCount>=2000 )		//2秒定时时间到了
	{
		TimCount = 0;
		
		Count_T1 = (TH1 *256 )+ TL1;		// 转/2s  转/min
		TH1 = 0;
		TL1 = 0;
		
		Show_Tab[4] = Count_T1/1000%10;
		Show_Tab[5] = Count_T1/100%10;	
		Show_Tab[6] = Count_T1/10%10;		
		Show_Tab[7] = Count_T1/1%10;		//取10位 
	}
	SEG_Fre();		//数码管刷新的
}

void Timer1_Isr(void) interrupt 3
{
	
}

/*
 11111110 0XFE
 11111101 0XFD
 11111011 0XFB
 11110111 0XF7
 11101111 0XEF
 11011111 0XDF
 10111111 0XBF
 01111111 0X7F
*/

void sys_init()		//函数定义
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

	P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
	
    P3M0 = 0x00;
    P3M1 = 0x00;
    
    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;    //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));  //等待时钟稳定

    USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}


void delay_ms(u16 ms)	//unsigned int 
{
	u16 i;
	do
	{
		i = MAIN_Fosc/6000;
		while(--i);
	}while(--ms);
}

要約する

カウンタの使用方法とアプリケーションシナリオを理解する

宿題:

T 法速度測定 (周期測定法とも呼ばれます) を実装してみます。周波数が既知の高周波パルスを発生させてカウントする方法で、エンコーダの隣り合うパルス間の捕捉間隔TEで決まるカウント時間、カウント値はM1となります。エンコーダ1回転の総パルス数をC、高周波パルスの周波数をF0とすると、回転速度nの計算式は次のようになります。
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/Medlar_CN/article/details/132718232