Study notes | Counter | 0xFD problem in Keil software | I/O port configuration | STC32G microcontroller video development tutorial (Brother Chong) | Episode 12: The role and significance of counters

1. Purpose of counter

For DC brushed motors, connect the two positive and negative terminals at the back, and the motor can turn
Insert image description here

How many turns does the rotor have?
We can install such a code disk on the back. Let's assume that there are 60 photoelectric holes here, right? Then if
we make one turn, we can output 60 on one shaft. For such a pulse, if it is blocked, it will output 1, if it is not blocked, it will output 0, and
the two paths alternate. If there are 60 pulses in this circle, 60 high and low levels (the total number of pulses divided by 60 is the number of turns),
this section uses switches , the function of analog counter.
The encoder can also achieve pulse output. The output waveform is: square wave.
There is a proportional change in the middle depending on how much liquid has flowed. One high and one low count as one pulse.
As long as the output signal has such high and low level changes, if you want to count the number, you can use the counter function.
Insert image description here

2. Counter configuration

Insert image description here

When GATE=O(TMOD.7), if TR1=1, the timer counts. When GATE=1, the external input INT1 is allowed to control timer 1,
so that pulse width measurement can be achieved. TR1 is the control bit in the TCON register. For the specific function description of each bit of the TCON register, see the introduction of the TCON register in the previous section.
When c/T=0, the multi-way switch is connected to the frequency division output of the system clock, Tl counts the internal system clock, and T1 works in the timing mode. When C/T=1, the multi-way switch is connected to the
external pulse input P3. 5/T1, that is, T1 works in counting mode.
Timer 1 of the STC microcontroller has two counting rates: one is the 12T mode, which adds 1 every 12 clocks, which is the same as the traditional 8051 microcontroller; the other is the 1T mode, which adds 1 every clock, and the speed is the same as that of the traditional 8051 microcontroller. 12 times. The rate of T1 is determined by T1x12 in the special function register AUXR. If T1x12=0, T1 works in 12T mode; if T1x12=1, T1 works in 1T mode. Timer 1 has two hidden registers RL_TH1 and RL_TL1. RL_TH1 and TH1 share the same address, and RL_TL1 and TL1 share the same address. When TRI=0, that is, timer/counter I is disabled, the content written to TLl will be written to RL_TLl at the same time, and
the content written to TH1 will also be written to RL_TH1 at the same time. When TR1=1, that is, timer/counter I is allowed to work, the content written to TLl is actually not written to the current register TL1, but to the hidden register RL_TL1. The content written to THl is actually written. Instead of writing to the current register TH1, write to the hidden register RL_THl, which can cleverly implement the 16-bit reload timer. When reading the contents of THl and TL1, the contents read are the contents of TH1 and TL1, not the contents of RL_TH1 and RL_TLl.
When timer 1 works in mode 1 (TMOD[5:4][M1.MO]=00B), the overflow of [THl, TL1l] not only sets TF1, but also automatically reloads the contents of [RL_TH1, RL_TL1] Enter [TH1,TL1].
When T1CLKO/INT_CLKO.1=1, the P3.4/TO pin is configured as the clock output T1CLKO of timer 1. The output clock frequency is T1 overflow rate/2.
If C/T=0, timer/counter T1 counts the internal system clock, then: The
output clock frequency when T1 works in 1T mode (AUXR.6/T1x12=1) = (SYsclk) (TM1PS+1) (65536 -[RL_TH1,RL_TL1])/2The output clock frequency when T1 works in 12T mode (AUXR.6/TIx12=0)=(SYSclk)(TM1PS+1)/12/(65536-[RL_TH1,RL_TLI])/2 If C/T=1, timer/counter T1 counts external pulse input (P3.5/Tl), then: output clock frequency = (Tl_Pin_CLK)/(65536-[RL_TH1,RL_TL1])/2

Tl_C/T: Write 1 to the Tl_C/T bit to control timer 1 to be used as a timer or counter. Clear it to 0 to use it as a timer (counting the internal system clock). Set 1 to use it as a counter (to pin T1/P3 .5 external pulses for counting).
Tl_GATE: Controls timer 1. When set to 1, timer/counter 1 can only be turned on when the INT1 pin is high and the TRI control bit is 1. Only TR1 counting is needed here, so Tl_GATE can be set to 0.

Official routine

Insert image description here
Insert image description here
Set TMOD = 0X40 =0100 0000, that is, Tl_C/T is set to 1 for counting. 16-bit auto-reload.
TL1 = 0xff; //1111 1111,65535, which is equivalent to one more pulse, and you can enter an interrupt and invert the pin. Every time a pulse comes, it is inverted.
TH1 = 0xff;

start

Use a button to simulate, release it to a high level, and then press and release it continuously.
Use the example for reference:
Insert image description here

It is necessary to turn on the internal 4K pull-up resistor and use the port pull-up resistor control register (PxPU):Insert image description here

Insert image description here

There is a configuration tool for this IO port in the STC-ISP software:
Insert image description here

Using the routine in the previous section, renamed 8. counter, it can be implemented using T1.
Mask void Timer0_Isr(void) interrupt 1 and call T0 interrupt mask, which is not needed in this section.
Write in the order of the routines in the manual.

Tips: The error FILE DOES NOT EXIST is prompted during compilation:

Insert image description here

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

This involves "Appendix I Description of the 0xFD problem in Keil software".

The characters of the Keil project path name cannot contain Chinese characters with OxFD encoding, otherwise the Keil software will not be able to compile the project correctly. Therefore, it is necessary to modify the directory name of this project:
change it to the English name: 8.Count_T1, the compilation is passed normally, and the button led turns on and off in a cycle.
After class, you can experiment by changing the values ​​​​of H1 and TL1 to realize 2 lights and extinguishes.
This value can be determined by using the I/O port configuration tool in STC-ISP, advanced configuration, and setting conditions:
Insert image description here

Get the setting code: P3PU = 0x20;

3. Application of counter

See the test question of the 2017 National College Student Electronic Design Competition - DC Motor Speed ​​Measuring Device (Question O), the question is as follows
Insert image description here

The problem-solving ideas are as follows:
Insert image description here

M method speed measurement: also called frequency measurement method. This method is to count the number of encoder pulses during a fixed time period (in seconds), and calculate the speed value. Let the total number of encoder pulses per revolution be C, and the counted number of encoder pulses in the time T0 be M0, then the formula for calculating the speed n is:
Insert image description here

First we define a variable called u16 Count_T1 = 0; the initial value is set to 0.
Rewrite the interrupt processing function: void Timer0_Isr(void) interrupt 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();		//计算得到结果后,数码管刷新

}

The complete code for this example:

#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);
}

Summarize

Understand how to use counters and application scenarios

Homework:

Try to implement T method speed measurement: also called period measurement method. This method is to establish a high-frequency pulse with a known frequency and count it. The counting time is determined by the captured interval TE between two adjacent pulses of the encoder, and the counting value is M1. Assume that the total number of pulses in a single revolution of the encoder is C, and the frequency of high-frequency pulses is F0, then the calculation formula of the rotation speed n is:
Insert image description here

Guess you like

Origin blog.csdn.net/Medlar_CN/article/details/132718232