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

2023-05-16

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倍频模式或者更换更高频率的晶振。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 快速幂取模(C/C++)

    快速幂取模的思路 快速幂实现的最基本的理论就是我们离散课上或者数论中学过的一条公式推出的引理 引理 xff1a 积的取余等于取余的积的取余 再在这条引理的基础之上 xff0c 对指数型数据进行拆分以及合并 xff0c 从而得到我们用的快速幂
  • 5.Linux系统中解压缩详解

    文章目录 前言1 打包 归档 和压缩2 tar命令详解 xff08 打包和解包 xff09 3 tar命令详解 xff08 解压缩 xff09 4 zip命令详解5 unzip命令6 gzip命令7 gunzip命令8 bzip29 bun
  • 3.Shell位置变量和参数用法详解,位置参数变量作用,$,#,*,$1,$2等详解和例子

    位置变量 参数用法详解 位置参数变量作用 1 2等详解和例子 文章目录 前言位置参数变量作用例子 64 示例 和 64 的区别 总结友情链接 前言 位置变量 xff1a 在bash shell中内置的变量 在脚本代码中调用通过命令行传递给脚
  • 代码手写UI,xib和StoryBoard间的博弈,以及Interface Builder的一些小技巧

    代码手写UI 这种方法经常被学院派的极客或者依赖多人合作的大型项目大规模使用 Geek们喜欢用代码构建UI xff0c 是因为代码是键盘敲出来的 xff0c 这样可以做到不开IB xff0c 手不离开键盘就完成工作 xff0c 可以专注于编
  • Python:if 语句的基本使用

    今天 xff0c 我们将学习Python中if语句的基本使用 if 在Python中用作某个条件或值的判断 xff0c 格式为 xff1a span class token keyword if span 条件 span class tok
  • Python模块介绍使用:zmail模块读取邮箱内邮件信息

    hello xff0c 大家好 xff0c 我是wangzirui32 xff0c 今天来教大家如何使用zmail模块读取邮箱内邮件信息 xff0c 开始学习吧 xff01 1 zmail安装 在命令行中输入以下命令即可安装 xff1a p
  • Python模块介绍使用:Python-Markdown解析Markdown文本

    博文作者 wangzirui32 x1f496 喜欢的可以 点赞 收藏 关注哦 x1f44f 我的第155篇原创作品 x1f449 本文首发于CSDN xff0c 未经许可禁止转载 x1f60e hello xff0c 大家好 xff0c
  • 【python学习】——字符串

    字符串 一 字符串的驻留机制 xff08 1 xff09 在python中它是基本数据类型 xff0c 是一个不可变的字符序列 xff08 2 xff09 字符串的驻留机制 xff1a 仅保存一份相同且不可变字符串的方法 xff0c 不用的
  • Linux安装部署SonarQube9.9 代码审查工具

    Linux安装部署SonarQube9 9 代码审查工具 1 SonarQube 简介 2 SonarQube安装与配置 2 1 官方软件包版本要求 2 2 基础环境配置 2 3 安装SonarQube 2 4 安装并配置PostgreSQ
  • 【数据库】Postgresql 与 MySQL 比较

    目录 Postgresql 与 MySQL 比较历史支持平台二者底层特性库存储引擎对数据的管理表连接算法 应用场景面向开发使用 Postgresql 与 MySQL 比较 二者都是比较强大的数据库 xff0c 选择使用哪一个数据库需要结合实
  • H5的离线缓存技术

    离线存储可以将站点的一些文件存储在本地 xff0c 它是浏览器自己的一种机制 xff0c 将需要的文件缓存下来 在没有网络的时候可以访问到缓存的对应的站点页面 xff0c 包括html xff0c js xff0c css xff0c im
  • QEMU虚拟机怎么配置网络才能主机和虚拟机都通

    当打开QEMU虚拟机配置界面的时候 xff0c 可以看到多种网络模型 而其中默认使用的是NAT xff0c 你会发现 xff0c 当你创建完虚拟机直接去配置网络之后 xff0c 网络是不通的 然后切换为其他模式之后 xff0c 你会发现 x
  • 虚拟机设置开机启动自动运行脚本

    首先设置虚拟机开机免密码自动启动 2 设置好开机免密码之后 xff0c 在配置开机自动启动脚本 编写一个bat文件作为脚本 xff0c 并将它放入到如下目录中 C ProgramData Microsoft Windows Start Me
  • QEMU虚拟机怎么配置网络

    当打开QEMU虚拟机配置界面的时候 xff0c 可以看到多种网络模型 而其中默认使用的是NAT xff0c 你会发现 xff0c 当你创建完虚拟机直接去配置网络之后 xff0c 网络是不通的 然后切换为其他模式之后 xff0c 你会发现 x
  • 关于VMware上的VAAI特性详解

    一般来说我们的存储在适配VMware的时候 xff0c 会牵涉搭配VAAI特性 xff0c 经常听到VAAI这到底是什么呢 xff1f VAAI的全称是VMware s Storage APIs for Array Integration
  • Python2.7版本安装报错

    python E S m sysconfig generate posix vars Could not find platform dependent libraries lt exec prefix gt Consider settin
  • oracle的安装(Oracle11G release2)

    一 xff1a 准备工作 1 关闭selinux 永久关闭 设置SELINUX 61 disabled xff1a vim etc selinux config 2 关闭firewalld 安装iptables systemctl stop
  • openstack kilo单击版本安装-最简单的安装方式

    由于K版本已经比较老了 xff0c 甚至连源都已经不怎么找得到了 xff0c 但是有时候为了一些特定的需求 xff0c 需要安装K版本 xff0c 这就比较麻烦 xff0c 本文找了一个较为简单的方法来安装 xff0c 并且是单机安装 准备
  • 本地显示远程服务器图形界面

    解决方案 序号方案简单区别方案一Xmanager1 VNC连接时及时突然中断 xff08 比如断网 xff09 xff0c 不影响操作进行 xff1b 2 不需要在服务器上装软件 xff0c 需要在你的电脑上装相应软件 xff0c 使用SS
  • SQL解析json(包含单层解析、多层解析)解析的数据可直接存到表中

    单层json解析 声明变量 declare 64 JsonData nvarchar max 61 39 34 BillName 34 34 12345765 34 34 SendDate 34 34 2022 11 10T00 00 00

随机推荐

  • MySQL查看当前使用的配置文件my.cnf的方法

    MySQL查看当前使用的配置文件my cnf的方法 MySQL实例在启动时 xff0c 会先读取配置参数文件my cnf my cnf一般会放在MySQL的安装目录中 xff0c 用户也可以放在其他目录加载 安装MySQL后 xff0c 系
  • Latex 之 微分符号d的竖立表达 {\rm d}

    微分符号d竖立表达 rm d
  • Abaqus 导出XYdata的几种方式

    目录 方法一 xff1a 通过Plu ins gt Tools gt Excel Utilities xff0c 将XY Data直接到Excel文件里 xff01 方式二 xff1a Report gt XY xff0c 导出默认 rpt
  • ABAQUS 显示应力/应变场的最大/最小值

    如下图所示 xff0c 可以显示最大最小值 具体数据导出 xff1a Report gt Field Output 导出结果 场输出 xff08 Field output xff09 同一时刻 xff0c 不同位置 xff1b 历史输出 H
  • mac下重装系统,应用程序副本已损坏 的解决办法

    首先需要确定电脑的年份和对应的系统 xff0c 简单的道理是老的电脑硬件是不适配最新系统的 xff0c 我需要安装的是10 12的系统 系统来源 xff1a 黑苹果 年份确定 xff1a 2017年9月之前生产的电脑 我用的是U盘安装的方法
  • mysql查看数据库的容量及表容量

    select table schema sum DATA LENGTH 43 sum INDEX LENGTH from information schema tables group by table schema 在需要备份数据库里面的
  • 【数据结构-栈】借助栈实现回文的判断

    数据结构 栈 借助栈实现回文的判断 最近在学习栈 xff0c 尝试用C实现了一些功能 include lt stdio h gt include lt stdlib h gt typedef struct app char date str
  • C语言实现冒泡排序

    冒泡排序作为学习排序最基本的算法 xff0c 具有稳定性与实用性 下面是C语言冒泡排序的源代码 include lt stdio h gt int main void int a 10 61 6 4 3 2 7 8 9 10 1 5 int
  • C语言实现快速排序算法

    快排作为公认最优秀的排序方法 xff0c 是每一个程序员都应该掌握的 xff0c 那么 xff0c 今天就由我来为大家简单讲解一下快速排序算法的代码 源代码如下 xff1a include lt stdio h gt void quicks
  • C语言实现二分查找

    相较于线性查找 xff0c 二分查找在面对大量数据时的效率更高 xff0c 但它的缺点是只能对有序数组进行查找 源代码如下 xff1a include lt stdio h gt void binarysearch int a int su
  • 约瑟夫环详解

    package newjosephu public class myfinaljosephu 你可能会说crazy 我只想说ez xff01 public static void main String args circlelinkedl
  • ECS弹性云服务器常用端口、安全组

    弹性云服务器常用端口 弹性云服务器常用端口如 表1 所示 您可以通过配置安全组规则放通弹性云服务器对应的端口 xff0c 详情请参见 添加安全组规则 表1 弹性云服务器常用端口 协议 端口 说明 FTP 21 FTP服务上传和下载文件 SS
  • 01背包问题(滚动数组实现的逻辑)

    package tttest public class mybetterbag public static void main String args int weight 61 1 3 4 int bagsize 61 4 int val
  • java递归实现辗转相除法

    public static int getres int a int b if b 61 0 return getres b a b return a
  • java 线索二叉树的构建

    public class test public static void main String args Node root 61 new Node 1 Node node2 61 new Node 2 Node node3 61 new
  • ubuntu下查看文件(夹)大小的命令

    记录下自己常用的查看文件夹和文件大小的命令 查看当前所处的文件夹的整个大小 xff08 不包括具体内容 xff0c 只看当前文件夹大小 xff09 span class token function du span sh 查看当前文件夹中各
  • git stash时出现xxx:needs merge问题

    项目需要git merge其他分支 xff0c 但由于本地也修改过 xff0c 所以希望先git stash后再merge xff0c 这时出现以下问题 xff1a xxx xxx xxx cpp xff1a needs merge 通过g
  • FFMPEG 之视频播放

    先看界面效果 xff0c 虽然有点low xff0c 但是效果实现了 一 实现原理 1 使用ffmpeg解码视频 2 然后使用libyuv播放解码的视频 二 实现 1 先看目录结构 2 ffmpeg编译以及引用 xff0c 在之前的篇章已经
  • 一步一步学CMake 之 VSCode+CMakeLists 调试 C++ 工程

    目录 1 插件推荐 2 文件准备 3 开始调试 一步一步学 CMake 系列文章 1 插件推荐 CMake CMake tools 2 文件准备 新建文件夹 xff1a TEST 新建文件 xff1a CMakeLists txt 内容如下
  • 51单片机使用8位重装定时器实现PWM输出同时实现DAC转换

    51单片机使用八位重装定时器实现PWM输出同时实现DAC转换 最近想要做一个数控电源 xff0c 打算使用51单片机实现电压和电流的闭环 xff0c 但是手头上的51单片机为STC89C51系列的单片机 xff0c 没有ADC采样功能 xf