#C51中断定时(PWM输出+外部中断频率检测)

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

C51单片机自身无PWM输出,可以借用T1定时中断输出一定频率的脉冲信号,且占空比可调,便于继续开发


提示:以下是本篇文章正文内容,下面案例可供参考

一、场景

  1. 样例1:P3引脚输出固定频率PWM信号,占空比人为调整
  2. 样例2:PWM+外部中断检测频率验证
    步步进阶

二、PWM简介

PWM(Pulse Width Modulation)脉冲宽度调制,是一种对模拟信号电平进行数字编码的方法。
占空比:高电平占周期的比例,如f=1Hz,T=1s,T1=0.5s,占空比即为50%
在这里插入图片描述

为什么这么说呢?
1.pwm本身就是一个方波信号,1和0对应数字电路中高电平、低电平。
2.思考下:负载两端(如LED、直流电机等)直流供电,高电平时ON,低电平时OFF。
3.若是将PWM信号输出至负载两端(如1Hz/5V,占空比50%)~~==~~理论上0.5s全部导通,0.5s全部关闭。此时,负载两端的等效电压约2.5V(5V*50%)工作时状态。电路中电流发生变化,器件工作状态受到影响。
简言之,在合适的频率信号下,通过调整PWM占空比,可以改变输出电压的有效值

三、编程实现

样例1:PWM+占空比软件调整

1.设计思路:

设计f = 10Hz的PWM信号,T = 100ms。
将T分割成100份,每份1ms

2.代码设计

1.T1定时初始化

void Timer1Init(void)		//1ms @11.0592MHz 
{
	TMOD &= 0x0F;		//设置定时模式	GATE C/T^ M1 M0  // 0 0 0 1
	TMOD |= 0x10;		//设置定时模式 T1 方式1 16位定时器
	TH1 = (65536 - 1000) / 256;	//初值	
	TL1 = (65536 - 1000) % 256;		
	TF1 = 0;			//清除TF1标志
	ET1 = 1;//打开定时器T1
	TR1 = 1;			//定时器1开始计时
}

2.T1中断服务函数

//2.PWM输出处理
	TR1  = 0;
	vPWMCnt++;
	if(vPWMCnt <= PWM_DUTY)
	{
		PWM = 1;
	}
	else if(vPWMCnt <= 100)
	{
		PWM = 0;
	}
	else 
	{
		vPWMCnt = 0;
	}
	TH1 = (65536 - 1000) % 256;	//重装初值	
	TL1 = (65536 - 1000) / 256;		
	TR1 = 1;

3.调试验证

P3.0输出PWM,周期比时钟源输出的要大一点
在这里插入图片描述
改变占空比,波形改变

#define PWM_DUTY	20	//占空比

在这里插入图片描述

样例2:PWM+外部中断检测频率

1.设计思路:

P3.0输出PWM信号
外部中断INT0+T0结合检测频率
数码管显示频率数值

2.代码设计

1.外部中断INT0初始化

void EX0Init(void)
{
	IT0 = 1;	//外部中断0触发方式 0:电平触发(低电平有效)1:边沿触发(高->低负跳变)
	EX0 = 1;	//允许外部中断0中断
}

2.外部中断INT0中断服务函数

void Ex0_ISR() interrupt 0
{
	//2.外部中断计数方案
	EX0 = 0;
	vFreqCnt_Ex0++;
	EX0 = 1;	
}

3.T0定时中断服务函数(1ms)

	void Timer0_ISR() interrupt 1
	{
		UI vFreqCnt;
		vFreqCnt++;
		if(vFreqCnt > 1000)
		{
			vFreqCnt = 0;
			EX0 = 0;
			gFreqCnt = vFreqCnt_Ex0;
			vFreqCnt_Ex0 = 0;
			EX0 = 1;
		}
	}

4.频率显示处理

	NumDisSpare(gFreqCnt);

void NumDisSpare(unsigned int vDisNum)
{
	if(vDisNum >= 1000)
	{
		SEG_DisBuf[0]  = vDisNum / 1000;
	}
	else
	{
		SEG_DisBuf[0] = 23;
	}
	if(vDisNum >= 100)
	{
		SEG_DisBuf[1]  = vDisNum / 100 % 10;
	}
	else 
	{
		SEG_DisBuf[1] = 23;
	}
	if(vDisNum >= 10)
	{
		SEG_DisBuf[2]  = vDisNum / 10 % 10;
	}
	else
	{
		SEG_DisBuf[2] = 23;
	}
	SEG_DisBuf[3]  = vDisNum % 10;
}

3.调试验证

1.利用上篇简单频率测试方式,进行检测并显示
在这里插入图片描述

总结

1.原计划一篇讲完再利用PWM实现LED呼吸灯功能,篇幅过长,下篇继续。
2.仿真环境下与实际的的确有偏差,proteus下输出PWM方波,周期偏差3ms左右。实际电路板示波器观测没有这么大偏差。晶振已经排查,具体原因再研究研究。

  • 1
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值