主要使用了c51单片机内部的定时器计数器功能
最近在准备期末考试,就结合这个实验复习了一下TMOD,TCON, EA, IP的使用
还有就是今年的蓝桥杯单片机省赛的时候就考到了测频功能,当时还没有学习单片机,估计就是挂在了这里,现在学完了回过头来看一下, 原来这么简单,太可惜了。
TMOD, TCON, IE寄存器的主要功能
TMOD寄存器主要是对于定时器和计数器的模式控制
从高位到地位为GATE C/T M1 M0 GATE C/T M1 M0
第一位主要控制的是定时器的启动是否和外部信号有关INT0和INT1,不过基本上很少用到
第二位为定时器和计数器的选择,为1的时候是计数器, 为0的时候为定时器
第三位和第四位是控制定时器和计数器的模式选择的
- 模式0,使用THi的高八位和TLi的第五位(13位定时器/计数器)使用很少,一般使用模式1代替
- 模式1,使用16位定时器/计数器一次最多可以延时65536个机器周期,或者记65536个外部脉冲
- 模式2,自动填充八位定时器/计数器(当TLi达到溢出的时候,自动填充THi的初始值)
- 模式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 分别是四种中断的控制位
下面说一下思路
- 两个定时器计数器,应该一个作为定时器,定时1s,另一个作为计数器,来进行外部脉冲的计数
- 程序应该有四个模块主程序模块, 中断模块, 计算频率模块, 显示模块
- 细节的部分,应该考虑在计数器达到溢出的时候要有一个变量进行存储,进行频率计算的时候要计算到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() ;
}
}
如果大家有什么更好的方法欢迎交流啊,
如我有什么错误还望大家多多指出,交流一下哈