51单片机使用8位重装定时器实现PWM输出同时实现DAC转换

51单片机使用八位重装定时器实现PWM输出同时实现DAC转换

  最近想要做一个数控电源,打算使用51单片机实现电压和电流的闭环,但是手头上的51单片机为STC89C51系列的单片机,没有ADC采样功能,同时这款单片机也不具备可编程输出的PWM功能。
  经过思考对于ADC采样可以使用外扩芯片XPT2046,不仅廉价而且可以实现4路的ADC采样通道,支持SPI通讯使用起来比较方便。对于PWM输出,51单片机虽然可以使用定时器中断来实现较精准的PWM输出,但是在输出高频的PWM信号时(需要实现的开关频率为65KHZ-100KHZ),其占空比分辨率非常小,不能满足要求。然后又想到可以使用51单片机产生低频的PWM信号,然后经过有源低通滤波器实现DAC输出模拟电压,再经高频锯齿波发生器和电压比较器实现高频PWM输出。高频锯齿波发生器使用手头上现有的NE555芯片实现,电压比较器可以使用LM393,有源低通滤波器也使用手头现有的LM358实现。
  可能有人说我这么做是多此一举,使用带ADC和PWM输出的单片机或者DSP芯片问题就没有这么复杂了,考虑到我手头现有的材料以及通过思考去解决一些实际问题想必更有收获。

一、使用八位重装定时器实现PWM输出

  STC89C51单片机具有两个16位的定时/计数器,每个定时器拥有八位自动重装载定时功能,采用八位自动重装载定时功能可以免去在中断函数内的手动定时初值装载,实现更精准的PWM输出。

(1)实现思路

  下图为采用两个定时器实现PWM输出的基本原理图,定时器T1的定时周期控制PWM的周期,定时器T0的定时周期控制PWM的占空比。定时器T1的中断函数始终将IO拉高,定时器T0的中断函数始终将IO拉低,两个定时器的中断函数交替执行就可以实现较为精准的PWM输出。这里需要注意的是定时器T0在达到一个PWM周期的高电平的延时时间后,会溢出进入中断拉低对应IO,这时还要在定时器T0的中断中暂停定时器T0,等到定时器T1进入中断再开启T0。

在这里插入图片描述

(2)程序

程序实现1:

#include"reg52.h"
sbit PWM0=P0^0;
unsigned char duty_high=(256-128);//这里占空比为50%
void main()
{
    PWM0=1;//初始为高电平
	TMOD=0x22;	//定时器0和定时器1,都为工作方式2,定时器0和1仅用TR1打开启动。
	TH0=duty_high;//定时器0调节占空比计时高电平时间然后进入中断拉低PWM0
	TL0=duty_high;
	TH1=0x00;  //定时器1产生周期信号,定时周期为256us
	TL1=0x00;
		
	ET0=1;//打开定时器0中断允许
	ET1=1;//打开定时器1中断允许
	EA=1;//打开总中断 
	 	

	TR1=1;//打开定时器1
	TR0=1;//打开定时器0
	 
  while(1)
  {
  }

}

void Timer0() interrupt 1
{
   TR0=0;//停止定时器T0
   PWM0=0;//拉低IO口  
}
void Timer1() interrupt 3 
{
   TR0=1; //开启定时器T0
   PWM0=1;//拉高IO口
 
}

  考虑到在中断中关断T0和开启T0还是会造成最少1us的延时输出,想到采用第二种方法来实现定时器T0的自动关断和起动,原理如下。下图为定时器的工作方式控制寄存器,GATE为门控位,当GATE置一时定时器的起动不仅需要TR0/1的控制还要求外部中断引脚INT0/1为高电平。
图1
在这里插入图片描述
下图所示当把外部中断0引脚和PWM0输出引脚连接,同时由于P0口内部没有上拉电阻,所以加一个10K的上拉电阻。这样当定时器T0产生中断拉低PWM0,同时INT0口也被拉低(INT0初始化为高电平),由于门控位GATE的作用定时器T0自动关断,而当定时器T1产生中断拉高PWM0,同时INT0恢复高电平,定时器T0自动打开开始计时。

在这里插入图片描述
程序实现2:

#include"reg52.h"
sbit PWM0=P0^0;
unsigned char duty_high=(256-128);//占空比50%
void main()
{
    PWM0=1;//初始为高电平
	PWM1=1;
  	TMOD=0x2a;//定时器0和定时器1,都为工作方式2,定时器0的起动受INTO和TR0影响,定时器1仅用TR1打开启动。
	TH0=duty_high;//定时器0调节占空比计时高电平时间然后进入中断拉低PWM0
	TL0=duty_high;
	TH1=0x00;  //定时器1产生周期信号,定时周期为256us
	TL1=0x00;
		
	ET0=1;//打开定时器0中断允许
	ET1=1;//打开定时器1中断允许
	EA=1;//打开总中断 
	 	

	TR1=1;//打开定时器1
	TR0=1;//打开定时器0
  while(1)
  {
  }

}

void Timer0() interrupt 1
{
  PWM0=0; 
}
void Timer1() interrupt 3 
{
 PWM0=1; 
}

使用方式2实现占空比为5%(13/256)
在这里插入图片描述
使用方式2实现占空比为95%(243/256)
在这里插入图片描述
经过仿真测试在占空比为5%-95%时的PWM波形输出较为精准。

二、利用产生的PWM输出信号实现8位DAC转换

  上面已经实现了较为精准的PWM波形输出,将PWM波形经过有源低通滤波即可实现DAC转换。参考这篇文章:怎样利用PWM实现DAC电路设计
  在这篇文章中使用了六阶巴特沃斯有源低通滤波器,这里因为PWM输出波形频率比文章中要高且只需要实现8位DAC,所以只采用三阶巴特沃斯有源低通滤波器。当把PWM周期固定为256us,可实现8位DAC,最小分辨率为1/256。这里因为采用LM358实现有源低通滤波,其不是轨到轨输出的运放,采用5V供电的话并不能实现满量程输出,所以考虑采用电阻分压来实现高电平为3V的PWM输出,然后采用一路运放实现阻抗的匹配实现低阻输出,然后连接后级的三阶巴特沃斯有源低通滤波器。同时需要注意的是图中使用20K和30K电阻想要实现高电平为3V的分压,但实际上P0.0口也连接P3.2口,P3.2口内部有较大的上拉电阻,所以实际的分压电阻要根据测量进行修改。
在这里插入图片描述
测试:

unsigned char duty_high=(256+1-(Uq*256.0/3-0.5));//期望电压Uq,-0.5的目的是四舍五入,256加1的目的是补偿

在这里插入图片描述
  经过测试在0.145V-2.9V的输出范围内其精度能够接受,理论上8位DAC的精度为3*1/256=0.0117V,这里对比下误差虽然不均匀但在精度要求不高的场合还是阔以的。当然这里仅仅是protues的仿真结果,实际做出来的误差还有待考究。
  另外后来思考了一下,如果将51单片机模拟的DAC用于电压或者电流闭环的调制波,其调制频率倒是有点低。以8位DAC为例,PWM的周期为256us,频率就是3.9KHZ,直观考虑DAC建立输出最少需要一个周期,但是接下来还要完成比例和离散积分的运算,这样算下来就不只一个周期,假如完成一次比例和离散积分的运算和占空比更新值的装载需要一个DAC转换周期,那么调节频率就为3.9KHZ/2=1.95KHZ。如果MOSFET管的开关频率做到65KHZ-100KHZ,1.95KHZ的调节频率显然是很低了。可以考虑降低DAC的分辨率采用7位的DAC,这样一个DAC转换周期为7.8KHZ,假如一个调节周期仍然为两个DAC转换周期,这样调节频率为3.9KHZ,而DAC精度降低到了0.0234V。总的来说调节频率还是比较低,只能考虑采用2倍频模式或者更换更高频率的晶振。

  • 12
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值