基于51单片机的AD/DA转换的串口通信proteus仿真(附源码)

news2024/12/23 17:34:51

文章目录

  • 一、前言
  • 二、PCF8591
    • 1.介绍
    • 2.原理图
    • 3.引脚介绍
  • 三、仿真图
    • 1.未仿真时
    • 2.仿真时
  • 四、仿真程序
    • main.c
    • IIC.c
  • 五、总结


一、前言

`AT89C52是一款经典的8051系列单片机,它通常不包含内置的模数转换器(ADC)或数字模拟转换器(DAC)功能。如果你需要使用ADC功能来进行模拟信号的采集,你可以通过外部连接ADC芯片来实现。ADC芯片将模拟信号转换为数字信号,然后可以通过AT89C52的GPIO端口进行读取和处理。


二、PCF8591

1.介绍

PCF8591是一个单片集成、单独供电、低功耗、8bit CMOS的AD/DA芯片。它具有4个模拟输入、1个模拟输出和1个串行IIC总线接口。PCF8591的3个地址引脚A0,A1和A2可以用于硬件地址编程,允许在同个IIC总线上接入8个PCF8591器件,而无需额外的硬件。

主要性能指标:

  1. 单电源供电,工作电压:2.5V-6V
  2. 通过IiC总线串行输入/输出
  3. PCF8591通过3个硬件地址引脚寻址
  4. PCF8591的采样率由IIC总线速率决定
  5. 4个模拟输入可编程为单端型或差分输入
  6. 自动增量频道选择
  7. PCF8591的模拟电压范围从VSS到VDD
  8. PCF8591内置跟踪保持电路 8-bit 逐次逼近A/D转换器
  9. 通过1路模拟输出实现DAC增益

2.原理图

这里的原理图用的是YL-40 AD模块的原理图。

  1. 模块支持外部4路电压输入采集(电压输入范围0-5V)
  2. 模块集成光敏电阻,可以通过AD采集环境光强精确数值
  3. 模块集成热敏电阻,可以通过AD采集环境温度精确数值
  4. 模块集成1路0-5V电压输入采集(通过蓝色电位器调节接入电压)
  5. 模块带电源指示灯(对模块供电后指示灯会亮)
  6. 模块带DA输出指示灯,当模块DA输出接口电压达到一定值,会点亮板上DA输出指示灯,电压越大,指示灯亮度越明显

在这里插入图片描述

3.引脚介绍

左边:
AOUT:芯片DA输出接口
AIN0:芯片模拟输入接口0,地址0x40
AIN1:芯片模拟输入接口1,地址0x41
AIN2 :芯片模拟输入接口2,地址0x42
AIN3 :芯片模拟输入接口3,地址0x43

右边:
SCL:IIC时钟接口,接单片机IO口
SDA:IIC数据接口,接单片机IO口
GND:模拟地 ,外接地
VCC:电源接口,外接3.3V-5V

三、仿真图

1.未仿真时

注意:这里的AT89C52的晶振为11.0592MHZ

在这里插入图片描述

2.仿真时

这里上电一段时间,AD才能正确采集出来数值,然后DAC也是一段时间过后才有电压输出。

4路ADC换算公式如图所示:ADC数值 = 2^8 * (Vacc / Vcc ) = 255 * (电阻分压 / 3.3V)
(255是因为是8bit)

在这里插入图片描述

四、仿真程序

main.c

void main(void)
{  
	UsartInit();  //	串口初始化
	printf("Uart Test OK\r\n");
	while(1)
	{		
	/********以下AD-DA处理*************/  
	
	    switch(AD_CHANNEL)
		{
			case 0: ISendByte(PCF8591,0x41); 
			     D[0]=IRcvByte(PCF8591); 	 //ADC0 模数转换1      光敏电阻
				 break;  
			
			case 1: ISendByte(PCF8591,0x42); 
			     D[1]=IRcvByte(PCF8591); 	 	//ADC1  模数转换2	  热敏电阻
				 break;  
			
			case 2: ISendByte(PCF8591,0x43); 
			     D[2]=IRcvByte(PCF8591); 	 	 //ADC2	模数转换3	   悬空
				 break;  
			
			case 3: ISendByte(PCF8591,0x40);
			     D[3]=IRcvByte(PCF8591); 	  //ADC3   模数转换4	   可调0-5v
				 break;  
			
			case 4: DACconversion(PCF8591,0x40, 150); 		//DAC	  数模转换
			     break;
		 
		}
			
	   if(++AD_CHANNEL>4) AD_CHANNEL=0;
	
	   /********以下将AD的值通过串口发送出去*************/	
	 printf("D[0]=%d\r\n",D[0]);		   	   
	 delay(20);		  
	 printf("D[1]=%d\r\n",D[1]);				   
	 delay(20);	
	 printf("D[2]=%d\r\n",D[2]);	
	 delay(20);
	 printf("D[3]=%d\r\n",D[3]);	
	 delay(20);
   }
}

void delay(uchar i)
{
  uchar j,k; 
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}

/*******************************************************************
DAC 变换, 转化函数               
*******************************************************************/
bit DACconversion(unsigned char sla,unsigned char c,  unsigned char Val)
{
   Start_I2c();              //启动总线
   SendByte(sla);            //发送器件地址
   if(ack==0)return(0);
   SendByte(c);              //发送控制字节
   if(ack==0)return(0);
   SendByte(Val);            //发送DAC的数值  
   if(ack==0)return(0);
   Stop_I2c();               //结束总线
   return(1);
}

/*******************************************************************
ADC发送字节[命令]数据函数               
*******************************************************************/
bit ISendByte(unsigned char sla,unsigned char c)
{
   Start_I2c();              //启动总线
   SendByte(sla);            //发送器件地址
   if(ack==0)return(0);
   SendByte(c);              //发送数据
   if(ack==0)return(0);
   Stop_I2c();               //结束总线
   return(1);
}

/*******************************************************************
ADC读字节数据函数               
*******************************************************************/
unsigned char IRcvByte(unsigned char sla)
{  unsigned char c;

   Start_I2c();          //启动总线
   SendByte(sla+1);      //发送器件地址
   if(ack==0)return(0);
   c=RcvByte();          //读取数据0

   Ack_I2c(1);           //发送非就答位
   Stop_I2c();           //结束总线
   return(c);
}

/*******************************************************************************
* 函数名         :UsartInit()
* 函数功能		   :设置串口
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void UsartInit()
{
    TMOD=0x20;     //即0010 0000,定时器/计数器1,工作方式2
    TH1=0xfd;      //设置波特率为9600
    TL1=0xfd;
    TR1=1;         //启动定时器/计数器1
        
    SCON=0x50;     //SM0=0;SM1=1;REN=1;0101 0000.串口工作方式1,允许串行控制
    PCON=0x00;     //设置SMOD=0
    IE=0x90;       //EA=1;ES=1;CPU允许中断,串行允许中断
        
    TI=1;          //中断请求标志位,直接使用printf必须加入此句才能实现发送
}

/*******************************************************************************
* 函数名         : Usart() interrupt 4
* 函数功能		  : 串口通信中断函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void Usart() interrupt 4
{
  if (RI) //接收到新字节
  {
			RI = 0; //清零接收中断标志位
			rx_buf = SBUF;
   }
}

IIC.c

#define  NOP()   _nop_()   /* 定义空指令 */
#define  _Nop()  _nop_()   /*定义空指令*/

sbit     SCL=P2^0;       //I2C  时钟 
sbit     SDA=P2^1;       //I2C  数据 
bit      ack;            /*应答标志位*/
/*******************************************************************
                     起动总线函数               
函数原型: void  Start_I2c();  
功能:     启动I2C总线,即发送I2C起始条件.  
********************************************************************/
void Start_I2c()
{
  SDA=1;         /*发送起始条件的数据信号*/
  _Nop();
  SCL=1;
  _Nop();        /*起始条件建立时间大于4.7us,延时*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();    
  SDA=0;         /*发送起始信号*/
  _Nop();        /* 起始条件锁定时间大于4μs*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();       
  SCL=0;       /*钳住I2C总线,准备发送或接收数据 */
  _Nop();
  _Nop();
}

/*******************************************************************
                      结束总线函数               
函数原型: void  Stop_I2c();  
功能:     结束I2C总线,即发送I2C结束条件.  
********************************************************************/
void Stop_I2c()
{
  SDA=0;      /*发送结束条件的数据信号*/
  _Nop();       /*发送结束条件的时钟信号*/
  SCL=1;      /*结束条件建立时间大于4μs*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  SDA=1;      /*发送I2C总线结束信号*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();
}

/*******************************************************************
                 字节数据发送函数               
函数原型: void  SendByte(UCHAR c);
功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
          此状态位进行操作.(不应答或非应答都使ack=0)     
           发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void  SendByte(unsigned char  c)
{
 unsigned char  BitCnt;
 
 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
    {
     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/
       else  SDA=0;                
     _Nop();
     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
      _Nop(); 
      _Nop();             /*保证时钟高电平周期大于4μs*/
      _Nop();
      _Nop();
      _Nop();         
     SCL=0; 
    }
    
    _Nop();
    _Nop();
    SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
    _Nop();
    _Nop();   
    SCL=1;
    _Nop();
    _Nop();
    _Nop();
    if(SDA==1)ack=0;     
       else ack=1;        /*判断是否接收到应答信号*/
    SCL=0;
    _Nop();
    _Nop();
}

/*******************************************************************
                 字节数据接收函数               
函数原型: UCHAR  RcvByte();
功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),
          发完后请用应答函数应答从机。  
********************************************************************/    
unsigned char   RcvByte()
{
  unsigned char  retc;
  unsigned char  BitCnt;
  
  retc=0; 
  SDA=1;                     /*置数据线为输入方式*/
  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        _Nop();           
        SCL=0;                  /*置时钟线为低,准备接收数据位*/
        _Nop();
        _Nop();                 /*时钟低电平周期大于4.7μs*/
        _Nop();
        _Nop();
        _Nop();
        SCL=1;                  /*置时钟线为高使数据线上数据有效*/
        _Nop();
        _Nop();
        retc=retc<<1;
        if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
        _Nop();
        _Nop(); 
      }
  SCL=0;    
  _Nop();
  _Nop();
  return(retc);
}

/********************************************************************
                     应答子函数
函数原型:  void Ack_I2c(bit a);
功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack_I2c(bit a)
{
  
  if(a==0)SDA=0;              /*在此发出应答或非应答信号 */
  else SDA=1;
  _Nop();
  _Nop();
  _Nop();      
  SCL=1;
  _Nop();
  _Nop();                    /*时钟低电平周期大于4μs*/
  _Nop();
  _Nop();
  _Nop();  
  SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  _Nop();
  _Nop();    
}

五、总结

今天主要讲了基于51单片机的AD/DA转换的串口通信proteus仿真。

感谢你的观看!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模版方法详解

模板方法模式 1 概述 在面向对象程序设计过程中&#xff0c;程序员常常会遇到这种情况&#xff1a;设计一个系统时知道了算法所需的关键步骤&#xff0c;而且确定了这些步骤的执行顺序&#xff0c;但某些步骤的具体实现还未知&#xff0c;或者说某些步骤的实现与具体的环境相…

DS高阶:跳表

一、skiplist 1.1 skiplist的概念 skiplist本质上也是一种查找结构&#xff0c;用于解决算法中的查找问题&#xff0c;跟平衡搜索树和哈希表的价值是一样的&#xff0c;可以作为key或者key/value的查找模型。skiplist是由William Pugh发明的&#xff0c;最早出现于他在1990年发…

SOLIDWORKS科研版的优势

随着科技的不断进步&#xff0c;科研领域对于快捷、准确和可视化的需求也在不断增长。在这个背景下&#xff0c;SOLIDWORKS科研版应运而生&#xff0c;为科研人员提供了一款强大的工具&#xff0c;帮助他们解决复杂的问题&#xff0c;提高研究效率。 首先&#xff0c;SOLIDWOR…

贷款借钱平台 贷款源码 小额贷款系统 卡卡贷源码 小额贷款源码 贷款平台

贷款平台源码/卡卡贷源码/小贷源码/完美版 &#xff0c; 数据库替换application/database.php 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89268533 更多资源下载&#xff1a;关注我。

镜像抑制和镜像衰减有什么不同

在很多无线产品接收机手册中&#xff0c;我们会看到两个参数&#xff0c;一个是镜像抑制&#xff08;Image Rejection&#xff09;&#xff0c;另一个是镜像衰减&#xff08;Image Attention&#xff09;&#xff0c;但这两者究竟有什么不同&#xff0c;一直比较疑惑&#xff0…

Microsoft 安全Copilot:适时而生的得力工具

随着数字化转型的加速&#xff0c;网络安全威胁日益增多&#xff0c;Microsoft Copilot for Security的出现恰逢其时&#xff0c;它将帮助我们更好地应对这些挑战&#xff0c;保护我们的数据和系统免受攻击。 ✦什么是Microsoft 安全Copilot✦ 概述 Microsoft 安全 Copilot 是…

Docker 的 RHEL 操作系统镜像

CentOS 和 Fedora 都是和 RHEL 同源衍生版本的 Linux&#xff0c;因为 CentOS 不需要向 RHEL 支付企业级的版权和费用&#xff0c;但是又具有和 RHEL 相同的稳定性和资源库。 所以 CentOS 在服务器上被广泛的部署和使用&#xff0c;但是 CentOS 目前已经停止技术支持和结束了生…

Nerf基础学习记录

笔记 什么是nerf一些值得注意的理论点 什么是nerf Nerf 是可以理解成是一种隐式的3D表达方式。 隐式表达可以理解成是用一个条件或者方程来表示一个3D几何&#xff0c;没有实实在在的几何形状。相反&#xff0c;显式表达就诸如mesh, 点云&#xff0c;体素这类的&#xff0c;能…

【if条件、for循环、数据框连接、表达矩阵画箱线图】

编程能力&#xff0c;就是解决问题的能力&#xff0c;也是变优秀的能力 From 生物技能树 R语言基础第七节 文章目录 1.长脚本管理方式if(F){....}分成多个脚本&#xff0c;每个脚本最后保存Rdata&#xff0c;下一个脚本开头清空再加载 2.实战项目的组织方式方法&#xff08;一&…

CTFshow misc

第一题1 打开图片直接就是flag 第二题0 放入010发现文件头有png 更换后缀 获得flag 第三题1 下载之后发现是bpg后缀 用在线工具转换为png获得flag 第四题 0 把六个文件后缀都改为png即可获得flag

springboot005学生心理咨询评估系统

springboot005学生心理咨询评估系统 亲测完美运行带论文&#xff1a;获取源码&#xff0c;私信评论或者v:niliuapp 运行视频 包含的文件列表&#xff08;含论文&#xff09; 数据库脚本&#xff1a;db.sql其他文件&#xff1a;ppt.ppt论文&#xff1a;开题.doc论文&#xf…

二.使用PgAdmin连接Postgresql

二.使用PgAdmin连接Postgresql PostgreSQL是一种开源的对象关系型数据库管理系统(ORDBMS),它支持大部分SQL标准并提供了许多高级功能,例如事务、外键、视图、触发器等。PostgreSQL由PostgreSQL全球开发组维护和开发,它是一种高度可扩展的数据库系统,可以在各种操作系统…

Java | Leetcode Java题解之第91题解码方法

题目&#xff1a; 题解&#xff1a; class Solution {public int numDecodings(String s) {int n s.length();// a f[i-2], b f[i-1], cf[i]int a 0, b 1, c 0;for (int i 1; i < n; i) {c 0;if (s.charAt(i - 1) ! 0) {c b;}if (i > 1 && s.charAt(i …

49-Qt控件详解:ltemViewsltemWidgets

1.List View:清单视图 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QListView> //字符串列表模型 #include <QStringListModel> #include <QMessageBox> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEcl…

Flutter+Getx仿小米商城项目实战教程又新增了Flutter调用原生地图

FlutterGetx仿小米商城项目实战教程基于Flutter3.x录制&#xff0c;课程紧贴企业需求&#xff0c;目前已完结176讲。教程所讲内容支持Android、Ios、华为鸿蒙OS&#xff0c;教程更新于2024年4月09日新增 Flutter 调用百度地图、新增Flutter充电桩项目地图实战。支持2024年3月29…

RAW转换和图像编辑工具:Capture One 23 Pro (win/mac)中文专业版

Capture One 23是一款功能强大的桌面版照片编辑软件&#xff0c;由丹麦PHASE ONE飞思数码公司开发。 以下是该软件的一些主要特点&#xff1a; 强大的RAW处理功能&#xff1a;Capture One 23支持多种品牌的相机和镜头&#xff0c;提供了丰富的RAW处理工具&#xff0c;包括曝光、…

适合建站的香港服务器有哪些,企业和个人建站的

香港服务器适合外贸建站、个人和企业建站&#xff0c;尤其是中小企业官网非常适合放在香港服务器上&#xff0c;因为香港服务器在国内外的访问速度都很快&#xff0c;也就意味着全球客户都能访问到你的网站。 对于很多新手小白来说不知道怎么才能买到靠谱稳定的香港服务器&…

C语言 | Leetcode C语言题解之第91题解码方法

题目&#xff1a; 题解&#xff1a; int numDecodings(char* s) {int n strlen(s);// a f[i-2], b f[i-1], c f[i]int a 0, b 1, c;for (int i 1; i < n; i) {c 0;if (s[i - 1] ! 0) {c b;}if (i > 1 && s[i - 2] ! 0 && ((s[i - 2] - 0) * 10…

C++进阶:哈希(2)位图与布隆过滤器

目录 1. 位图&#xff08;bitset&#xff09;1.1 引子&#xff1a;海量整形数据的处理1.2 结构描述1.3 位图实现1.4 位图相关题目练习 2. 布隆过滤器&#xff08;BloomFilter&#xff09;2.1 引子&#xff1a;海量非int类型数据处理&#xff08;string&#xff09;2.2 结构描述…

【Linux:环境变量】

环境变量一般是指在操作系统中用来指定操作系统环境的一些参数 常见的环境变量&#xff1a; PATH 指定可执行程序的搜索路径 系统级的文件&#xff1a;/etc/bashrc 用户级文件&#xff1a;~/.bashrc ~/.bash_profile HOME 指定用户的主要工作目录&#xff08;当前用…