4.10 51单片机-使用计数器测量NE555脉冲频率

4.10 使用计数器测量NE555脉冲频率

4.10.1 原理图介绍

 图4-10-1

 

图4-10-2

4.10.2 单片机的计数器模式介绍

STC90C51RC/RD+系列单片机内部设置的两个16位定时器/计数器T0和T1都具有计数方式和定时方式两种工作方式。对每个定时器/计数器(T0和T1),在特殊功能寄存器TMOD中都有一控制-C/T来选择T0或者T1为定时器还是计数器。定时器/计数器的核心部件是一个加法计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同:如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每6个时钟得到一个计数脉冲,计数值加1;如果计数脉冲来自单片机外部引脚(T0为P3.3,T1为P3.3),则为计数方式,每来一个脉冲加1。

图4-10-3

4.10.3 NE555定时器介绍

555定时器是一种集成电路芯片,常被用于定时器、脉冲产生器和振荡电路。555可被作为电路中的延时器件、触发器或起振元件。

555定时器可工作在三种工作模式下:

单稳态模式:在此模式下,555功能为单次触发。应用范围包括定时器,脉冲丢失检测,反弹跳开关,轻触开关,分频器,电容测量,脉冲宽度调制(PWM)等。

无稳态模式:在此模式下,555以振荡器的方式工作。这一工作模式下的555芯片常被用于频闪灯、脉冲发生器、逻辑电路时钟、音调发生器、脉冲位置调制(PPM)等电路中。如果使用热敏电阻作为定时电阻,555可构成温度传感器,其输出信号的频率由温度决定。

双稳态模式(或称施密特触发器模式):在DIS引脚空置且不外接电容的情况下,555的工作方式类似于一个RS触发器,可用于构成锁存开关。

4.10.4 示例代码

下面代码里,配置定时器1为16位计数器模式并开启计数中断;NE555脉冲发生器接在单片机的P3.3引脚输入脉冲,通过定时器1进行计数。再配置定时器0为16位定时器模式,50毫秒超时一次,在中断服务函数里记录超时的次数,当超时20次表示1秒钟时间到达。1秒钟时间到达之后,在定时器0的中断服务函数里关闭定时器0和计数器1。在主函数里判断计数器是否停止,如何计数器停止就表示1秒钟时间到达,之后就读取1秒钟之内计数器1记录的脉冲数量,通过数码管进行显示。

用总脉冲量/总时间,就可以得出脉冲的周期。

示例代码:

#include <reg51.h>
u32 time1_cnt=0; //记录计数器1收到的外部脉冲数量
u32 time0_cnt=0; //记录定时器0的超时时间次数
u32 Freq=0;
int main()
{
    Timer0_16bit_Init(50000); //初始化定时器0,定时50ms一次
    Timer1_16bit_CntMode_Init(); //初始化计数器1
    while(1)
    {
        if(TR0==0) //当定时器0停止时,表示1秒钟时间到达
        {
            Freq=time1_cnt+(TH1<<8|TL1); //得到1秒钟内计算的脉冲数
            time1_cnt=0;//清除脉冲计数
            TH1=0; //将计数器的值清零
            TL1=0;
            TR0=1; //开启定时器0
            TR1=1; //开启计数器1
        }
        LED_DisplayNumber(Freq); //显示脉冲个数
    }
}

//共阴极数码管编码(要显示的段就输出1)
//数字0~9
code u8 LED2_Coding[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
//定义38译码器的引脚
sbit HC138_A0=P2^2; //A
sbit HC138_A1=P2^3; //B
sbit HC138_A2=P2^4; //C
#define LED P0  //定义LED引脚

//设置数码管显示指定的数字
void LED_DisplayNumber(unsigned long number)
{
    u16 i,j;
    u8 display_data[8];//存放当前数码管显示的数据
    //以下代码将number按十进制位从低到高依次提取并转为数码管显示字符
    display_data[0] = LED2_Coding[number/10000000%10];     
    display_data[1] = LED2_Coding[number/1000000%10];
    display_data[2] = LED2_Coding[number/100000%10];
    display_data[3] = LED2_Coding[number/10000%10];
    display_data[4] = LED2_Coding[number/1000%10];
    display_data[5] = LED2_Coding[number/100%10];
    display_data[6] = LED2_Coding[number/10%10];
    display_data[7] = LED2_Coding[number/1%10];
    for(i=0;i<8;i++)
    {
        switch(i)    //位选,选择点亮的数码管,
        {
            case 0:
                HC138_A0=0;HC138_A1=0;HC138_A2=0; break;//显示第0位
            case 1:
                HC138_A0=1;HC138_A1=0;HC138_A2=0; break;//显示第1位
            case 2:
                HC138_A0=0;HC138_A1=1;HC138_A2=0; break;//显示第2位
            case 3:
                HC138_A0=1;HC138_A1=1;HC138_A2=0; break;//显示第3位
            case 4:
                HC138_A0=0;HC138_A1=0;HC138_A2=1; break;//显示第4位
            case 5:
                HC138_A0=1;HC138_A1=0;HC138_A2=1; break;//显示第5位
            case 6:
                HC138_A0=0;HC138_A1=1;HC138_A2=1; break;//显示第6位
            case 7:
                HC138_A0=1;HC138_A1=1;HC138_A2=1; break;//显示第7位 
        }
        LED=display_data[i];     //控制数码管的显示数据值
        j = 100;                 //扫描间隔时间设定
        while(j--){}    
        LED=0x00;             //消隐,所有数码管都不显示
    }
}

u16 T0_Update_data;//定时器0的初始值
void Timer0_16bit_Init(u16 us)
{   
    //当前实验板上的晶振实际频率为: 12MHZ
    u16 val=us/(12/12); //得到计数的时间,只要整数部分
    T0_Update_data=65535-val; //得到重装载值
    TMOD&=0xF0;     //清除配置
    TMOD|=0x01;     //配置定时器0工作在16位定时器模式
    TH0=T0_Update_data>>8; //定时器0高位重装值
    TL0=T0_Update_data;    //定时器0低位重装值
    EA=1;                  //开启总中断
    ET0=1;                 //开启定时器0溢出中断
    TR0=1;                 //开启定时器0
}
//定时器0的重装值更新函数
void Timer0_Update(void)
{
    TH0=T0_Update_data>>8; //定时器0高位重装值
    TL0=T0_Update_data;    //定时器0低位重装值
}
/*
配置定时器1初始化为16位计数器模式
*/
void Timer1_16bit_CntMode_Init(void)
{   
    //当前实验板上的晶振实际频率为: 12MHZ
    TMOD&=0x0F; //清除配置
    TMOD|=0x50; //配置定时器1工作在16位计数器模式
    EA=1;       //开启总中断
    ET1=1;      //开启定时器1溢出中断
    TR1=1;      //启动定时器1
}

/*定时器0的中断服务函数*/
void TIM0_IRQHandler(void) interrupt 1
{
    time0_cnt++;
    //定时器0配置50ms超时一次,超时次数到达20次表示1秒钟时间到达
    if(time0_cnt==20)
    {
        time0_cnt=0;
        TR0=0; //关闭定时器0
        TR1=0; //关闭计数器1
    }
    Timer0_Update(); //定时器0的重装载
}

/*定时器1的中断服务函数*/
void TIM1_IRQHandler(void) interrupt 3  //定时器1
{
    //当前计数器配置为16位模式,进入一次中断就表示计数了65536次
time1_cnt+=65536; 
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>