51单片机--定时器测量脉宽

介绍如何使用51单片机通过TMOD寄存器的GATE位实现脉冲高电平宽度的测量,并提供了两种不同实现方式的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学51也算有一段时间了 以前学的相当的粗糙 很多原理性的东西 都不知道 今天上课的时候听老师说  这个LOW的单片机可以测量脉宽   去手册上看了一下 加上课本上说的  卧槽 真的可以 哈哈  

直接上手册上的来说吧  

就是这个东西  TMOD寄存器中的那个GATE位  很明显 手册中说道  当这位置1的时候 只有在INT0(P3.2)引脚为高电平的时候  并且TR0或者TR1置位的时候 定时/计数器才打开  我们就可以利用这个特点来测量一个脉冲的高电平的宽度  就是这个高电平的持续时间  那么怎么测量呢  说一下思路  

首先  我们让门控位GATE=1   并且启动定时/计数器 TR0  但是这时候寄存器TH0  TL0里面的数值并不会增加  因为INT0这个引脚上还没高电平  我们把要测量的脉冲接到P3.2这个引脚上   当高电平来的时候   TH0和TL0里面的数值就开始每过一个机器周期增加一   知道P3.2引脚上的高电平消失   当高电平消失的时候 自然 TH0和TL0也就停止计数了  这时候我们把TH0和TL0里面的数值读出来   根据时钟和机器周期的关系就可以的出来高电平的时间了  这里 简单算一下 吧   好算一点  假设晶振频率是12MHZ那么机器周期就是1US   如果读出来 TH0+TL0=50000    那么这个高电平的持续时间就是50mS  能明白不 !!!

我用仿真做了一下  得出的结果基本正确   这里说一下仿真的问题   就是 仿真里面好像默认的51的晶振频率是12MHZ   即使你搭建外部晶振电路也不能改变改变频率 还要复位貌似也不太好用  哎呀 算了 这个不太影响

直接上代码 上图  看一下 下面的代码  我仿真里面设置的脉冲频率是1KHZ 占空比是50%    由这个代码得到的高电平的时间 理论值是500us   测得位501us 我觉得基本正确

# include<reg52.h>
# define uint unsigned int 
# define uchar unsigned char
uchar code table1[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; 
uint High,Low;
sbit K=P3^2;
sbit led0=P2^0;  
sbit led1=P2^1;  
sbit led2=P2^2;  
sbit led3=P2^3;
void delay(uint k)   //延时函数    这个延时是为了数码管  
{  
    uint i,j;  
    for(i=k;i>0;i--)  
        for(j=113;j>0;j--) ;  
}
void Init_T0()
{
	TMOD=0x09;
	TH0=0;
	TL0=0;
}
void Display(disnum)  
{  
    led0=1;  
    P0=table1[disnum/1000];  
    delay(3);  
    P0=0xff;  
    led0=0;   
  
    led1=1;  
    P0=table1[disnum%1000/100];  
    delay(3);  
    P0=0xff;  
    led1=0;  
  
    led2=1;  
    P0=table1[disnum%100/10];  
    delay(3);  
    P0=0xff;  
    led2=0;  
  
    led3=1;  
    P0=table1[disnum%10];  
    delay(3);  
    P0=0xff;  
    led3=0;  
  
}
void Message_Width()
{
	while(K);
	TR0=1;
	while(!K);
	while(K);
	TR0=0;
	High=TH0;
	Low=TL0;
}
void main()
{
	while(1)
	{
	   Init_T0();
	   Message_Width();	
	   Display(High*256+TL0);
	}
}


此代码得到下图 


但是无意间让我发现了一个很无奈的问题  我觉得上面的数码管写的太小学生了 于是想让程序少几行 把数码管的函数变更了一下  但是测得脉宽长度居然不一样了 多了8个us即使两个函数执行时间不一样  可是我实在数码管显示函数之前就把脉宽测量完成了 啊  为啥会多这个8us呢   有哪位大佬看到希望指点一下 啊 下面附上代码和图

# include<reg52.h>
# define uint unsigned int 
# define uchar unsigned char
uchar code table1[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; 
uchar code table2[]={0x01,0x02,0x04,0x08};
uchar table3[4]={0};
uint High,Low,n;
sbit K=P3^2;
void delay(uint k)   //延时函数    这个延时是为了数码管  
{  
    uint i,j;  
    for(i=k;i>0;i--)  
        for(j=113;j>0;j--) ;  
}
void  Data_Process(disnum)
{
	table3[0]= disnum/1000;
	table3[1]= disnum%1000/100;
	table3[2]= disnum%100/10;
	table3[3]= disnum%1000;
}
void Display()  
{  
	uchar i;
	for(i=0;i<4;i++)
	{
		P2=table2[i];
		P0=table1[table3[i]];
		delay(3);
		P0=0xff;
		P2=0; 
	} 
}
void Init_T0()
{
	TMOD=0x09;
	TH0=0;
	TL0=0;
}
void Message_Width()
{
	while(K);
	TR0=1;
	while(!K);
	while(K);
	TR0=0;
	High=TH0;
	Low=TL0;
}
void main()
{
	while(1)
	{
		Init_T0();
		Message_Width();
		Data_Process(High*256+TL0);
		Display();
	}
}




### 使用51单片机定时器测量信号的方法 对于51单片机而言,定时器作为一种重要的外设资源,在测量信号方面有着广泛应用。通过配置特定的工作模式并结合外部中断或边沿触发机制可以实现对输入脉冲宽度的有效检测[^1]。 #### 配置与初始化 为了完成这一任务,通常会采用如下方式设置: - **选择合适的定时器工作模式**:一般会选择自动重装载模式(Mode 2),这样可以在每次溢出后自动恢复初值,便于计算时间差。 - **设定初始计数值**:根据所需精度调整预设值,使得能够覆盖待测范围的同时保持足够的分辨率。 - **使能相应的中断源**:当捕捉到上升沿或下降沿时触发中断服务程序ISR,在其中记录当前时刻以便后续处理。 ```c #include <reg52.h> sbit PULSE_IN = P3^2; // 假定冲信号接入P3.2脚 unsigned int rise_time, fall_time; void Timer0_Init(void){ TMOD &= 0xF0; TMOD |= 0x02; // 设置T0为8位自动重载模式 TH0 = (65536-500)/256; // 设定高字节部分的初值 TL0 = (65536-500)%256; // 设定低字节部分的初值 } // 中断函数定义 void External_Interrupt_Init(){ EX0=1; // 开启INT0中断请求允许 IT0=1; // 边沿触发(负跳变有效) EA =1 ; // 总控开关打开 } ``` #### 实现测量的核心逻辑 在实际应用过程中,每当检测到一次完整的高低电平转换即构成一个有效的冲事件,则可通过比较两次相邻的时间戳来获取该次冲的实际持续期长度。具体操作是在进入和退出中断服务子程序(ISR)时分别读取定时寄存器中的即时值作为标记点,并据此推算出目标参数。 ```c void Int0_ISR() interrupt 0 { static bit flag = 0; if(flag == 0){ // 上升沿到来 TR0 = 1; // 启动定时器 TF0 = 0; // 清除溢出标志位 TH0 = (65536-500)/256; TL0 = (65536-500)%256; rise_time = TH0*256 + TL0; flag = ~flag; }else{ // 下降沿到达 TR0 = 0; // 关闭定时器 fall_time = TH0*256 + TL0; unsigned long pulse_width = ((fall_time-rise_time)*1000)/(11.0592); // 计算(ms),假设晶振频率为11.0592MHz flag = ~flag; } } ``` 上述代码片段展示了如何利用51系列MCU内部集成的硬件特性配合软件算法达到精准测定任意波形周期特性的目的[^3]。
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值