利用c51单片机实现测频仪(基于proteus仿真)

主要使用了c51单片机内部的定时器计数器功能

最近在准备期末考试,就结合这个实验复习了一下TMOD,TCON, EA, IP的使用 还有就是今年的蓝桥杯单片机省赛的时候就考到了测频功能,当时还没有学习单片机,估计就是挂在了这里,现在学完了回过头来看一下, 原来这么简单,太可惜了。

TMOD, TCON, IE寄存器的主要功能

TMOD寄存器主要是对于定时器和计数器的模式控制 从高位到地位为GATE C/T M1 M0 GATE C/T M1 M0 第一位主要控制的是定时器的启动是否和外部信号有关INT0和INT1,不过基本上很少用到 第二位为定时器和计数器的选择,为1的时候是计数器, 为0的时候为定时器 第三位和第四位是控制定时器和计数器的模式选择的

  1. 模式0,使用THi的高八位和TLi的第五位(13位定时器/计数器)使用很少,一般使用模式1代替
  2. 模式1,使用16位定时器/计数器一次最多可以延时65536个机器周期,或者记65536个外部脉冲
  3. 模式2,自动填充八位定时器/计数器(当TLi达到溢出的时候,自动填充THi的初始值)
  4. 模式3,对于定时器/计数器1没有模式3,模式3直对定时器/计数器0有效(两个独立的八位定时器/计数器)

TCON控制定时器/计数器和外部中断 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 TF1定时器/计数器1的溢出标志位 TR1为定时器/计数器1的开启控制位 IE1为外部中断1的标志位 IT1为外部中断方式的控制位 为1的时候为下降沿触发 为0的时候为低电平触发

IE寄存器主要是控制中断的开启 EA为是总中断位 EX0 ET0 EX1 ET1 ES 分别是四种中断的控制位

下面说一下思路

  1. 两个定时器计数器,应该一个作为定时器,定时1s,另一个作为计数器,来进行外部脉冲的计数
  2. 程序应该有四个模块主程序模块, 中断模块, 计算频率模块, 显示模块
  3. 细节的部分,应该考虑在计数器达到溢出的时候要有一个变量进行存储,进行频率计算的时候要计算到TL1和TH1中的个数,两个的单位是不统一,要进行转化

下面是程序

#include<reg51.h>		//这里的晶体震荡频率为12MHz
#define uchar unsigned char 
uchar Tcode[10] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67 } ;	//数码管共阴极的显示代码
int i = 0 , t = 0 ;	//计数器溢出的存储变量
long frency = 0 ; 	//频率值


void dispaly() ;	//显示模块
void calculate() ;	//计算频率模块

void main()
{

	TMOD = 0X51;	//设置为定时器计数器1为脉冲计数模式,定时器计数器0为定时模式
	TH1 = 0X00 ;
	TL1 = 0X00 ; 
	TH0 = 0XB1 ;
	TL0 = 0XE0 ; 		//为定时器计数器赋初值

	TR1 = 1 ;
	TR0 = 1 ;
	EA = 1; 
	ET0 = 1 ;
	ET1 = 1 ;			//打开中断
					
	while(1){
	dispaly();
	} ;
}

void time0() interrupt 1
{
	TH0 = 0XB1 ;
	TL0 = 0XE0 ; 
	if( ++t >= 50 ) {		//使用多次中断实现1s的延时
	 TR1 = 0 ; 		//为了计数的准确性,在计算的时候将计数器1关闭
	 calculate() ;
	 t = 0 ; 
	 TH1 = 0  ;		//清空计数器中的值,防止对下一个周期计数产生影响
	 TL1 = 0 ;
	 TR1 = 1 ;		//最后打开中断
	 }
}

void time1() interrupt 3
{
	i++ ;
}

void calculate()
{
	frency = i*65535 + TH1*256 + TL1 ; 
	i = 0 ; 				//将溢出的次数清零,为下一次计数做准备
}

void delay()		//延时程序,使得数码管的显示达到稳定
{
	int i = 1000 ;
	for(;i>=0 ;i--) ;
}

void dispaly() 
{
	int show[6] ;
	int i = 0 ;
	int temp = 0x20 ;	
	int six_number = frency/100000 ;
	int five_number = frency%100000/10000 ;
	int four_number = frency%100000/1000 ;
	int three_number = frency%1000/100 ;
	int two_number = frency%100/10 ; 
	int one_number = frency%10 ;
	show[0] = one_number ; 
	show[1] = two_number ; 
	show[2] = three_number ; 
	show[3] = four_number ; 
	show[4] = five_number ;
	show[5] = six_number  ;
	for(; i<6; i++){
		P2 = ~temp ;	//利用循环结构,减少了大量重复代码
		temp = temp>>1 ;	//每次将要显示的位置向右移动一位
		P1 = Tcode[show[i]] ;	 //显示对应的数值
		delay() ;
	}
}

如果大家有什么更好的方法欢迎交流啊, 如我有什么错误还望大家多多指出,交流一下哈

经验分享 程序员 微信小程序 职场和发展