利用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的时候为定时器 第三位和第四位是控制定时器和计数器的模式选择的
- 模式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() ; } }
如果大家有什么更好的方法欢迎交流啊, 如我有什么错误还望大家多多指出,交流一下哈