我是靠谱客的博主 粗心小蜜蜂,最近开发中收集的这篇文章主要介绍基于51单片机的AD转换,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

A/D转换

选用芯片AT89S52
函数功能:如下代码

/*******************************************************************
此函数功能为:PCF8591芯片的使用,A/D转换,四路通道。通道一为可调电阻,
通道二为热敏电阻,通道三为光敏电阻,通道四接地。分别转换出它们的对应
电压,显示在液晶LCD1602上。
作者:Crazy Wind      
日期:2020.11.2
version:1.0.0
********************************************************************/
#include"reg52.h"
#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
sbit SCL=P3^4;	  	//模拟时钟口
sbit SDA=P3^5;      //模拟数据口
bit askflag;
#define disdata  P0   //显示数据码输出口
sbit LCD_RS=P2^0;    //寄存器选择位RS为P2.0
sbit LCD_RW=P2^1;    //读写选择位RW为P2.1
sbit LCD_E=P2^2;     //使能信号位E为P2.2
uint data dis[4]={0x00,0x00,0x00,0x00}; 	//定义3个显示数据单元和1个数据存储单元
uchar code dis4[] = {"1- .  V  2- .  V"};
uchar code dis5[] = {"3- .  V  4- .  V"};
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();_nop_();};  //延时5个机器周期
bit bdata SystemError;      //从机错误标志位

/*********************** PCF8591专用变量定义 ***********************/

#define	PCF8591_WRITE	0x90 
#define	PCF8591_READ 	0x91
#define  NUM  4 	            //接收和发送缓存区的深度
uchar idata receivebuf[NUM];    //数据接收缓冲区

/*****************************************************
函数功能:ms延时
******************************************************/
void delayms(uint ms)       //毫秒延时
{
	uint i,j;
    for(i=0;i<ms;i++)
    {
        for(j=115;j>0;j--);
    }
}

/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:busy。busy=1,忙碌;busy=0,不忙
******************************************************/
bit BusyTest(void)
{
    bit busy;
    LCD_RS=0;    //RS为低电平,RW为高电平时,可以读状态
    LCD_RW=1;
    LCD_E=1;     //E=1,才允许读写
    _nop_();    //空操作四个机器周期,给硬件反应时间
    _nop_();
    _nop_();
    _nop_();
    busy=(bit)(P0&0x80);    //将忙碌标志电平赋给busy(通过按位“与”运算将最高位赋给busy)
    LCD_E=0;
    return busy;   //将忙碌标志电平赋给busy
}

/*****************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:z
******************************************************/
void Write_zl(uchar z)
{
    while(BusyTest()==1);   //如果忙就等待
    LCD_RS=0;    //RS和RW同时为低电平时,可以写入指令
    LCD_RW=0;
    LCD_E=0;     //使能信号E置低电平(写指令前先赋低电平0)
    _nop_();
    _nop_();    //空操作两个机器周期,给硬件反应时间
    P0=z;   //将数据送入P0口(数据总线line),即写入指令或地址
    _nop_();
    _nop_();
    _nop_();
    _nop_();    //空操作四个机器周期,给硬件反应时间
    LCD_E=1;    //使能信号E上升沿(0到1)时读取信息
    _nop_();
    _nop_();
    _nop_();
    _nop_();    //空操作四个机器周期,给硬件反应时间 
    LCD_E=0;    //使能信号E下降沿(1到0)时执行指令
}

/*****************************************************
函数功能:指定字符显示的实际地址
入口参数:x
******************************************************/
void WriteAddress(uchar x)
{
    Write_zl(x|0x80);   //显示位置的确定方法规定为"地址码x+80H"                    
}

/*****************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
******************************************************/
void WriteData(uchar y)
{
    while(BusyTest()==1);   //如果忙就等待
    LCD_RS=1;   //RS为高电平,RW为低电平时,可以写入数据
    LCD_RW=0;
    LCD_E=0;    //使能信号E置低电平(写数据前先赋低电平0)
    _nop_();
    _nop_();    //空操作两个机器周期,给硬件反应时间
    P0=y;   //将数据送入P0口(数据总线line),即将数据写入液晶模块
    _nop_();
    _nop_();
    _nop_();
    _nop_();    //空操作四个机器周期,给硬件反应时间
    LCD_E=1;    //使能信号E上升沿(0到1)时读取信息
    _nop_();
    _nop_();
    _nop_();
    _nop_();    //空操作四个机器周期,给硬件反应时间
    LCD_E=0;    //使能信号E下降沿(1到0)时执行指令    
}

/*****************************************************
函数功能:对LCD的显示模式进行初始化设置
******************************************************/
void LcdInit(void)
{
    delayms(15);    //延时15ms,首次写指令时应给LCD一段较长的反应时间
    Write_zl(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口
    delayms(5); //延时5ms 
    Write_zl(0x38);
    delayms(5);
    Write_zl(0x38); //3次写 设置模式
    delayms(5);
    Write_zl(0x0c); //显示模式设置:显示开,无光标,光标不闪烁
    delayms(5);
    Write_zl(0x06); //显示模式设置:光标右移,字符不移
    delayms(5);                                           
    Write_zl(0x01); //清屏幕指令,将以前的显示内容清除
    delayms(5);
}

/*****************************************************
函数功能:将采集到的数据进行16进制转ASCLL码
******************************************************/
void Transform(uchar dat)
{
	dis[2]=dat/51;   //AD值转换为3位BCD码(256/5),最大为5.00V。
    dis[2]=dis[2]+0x30;	 //转换为ACSII码
    dis[3]=dat%51;   //余数暂存
    dis[3]=dis[3]*10;    //计算小数第一位
    dis[1]=dis[3]/51;
    dis[1]=dis[1]+0x30;	 //转换为ACSII码
    dis[3]=dis[3]%51;
    dis[3]=dis[3]*10;    //计算小数第二位
    dis[0]=dis[3]/51;                                                                             //
    dis[0]=dis[0]+0x30;  //转换为ACSII码           
} 

/*****************************************************
函数功能:启动I2C总线
******************************************************/
void iic_start(void)
{
	SDA=1;     
	SCL=1;  //时钟保持高,数据线从高到低一次跳变,I2C通信开始
	delayNOP();      // 延时5us 
   	SDA=0;
	delayNOP();
    SCL=0;
}

/*****************************************************
函数功能:停止I2C总线数据传送
******************************************************/
void iic_stop(void)
{  	
	SDA=0;  //时钟保持高,数据线从低到高一次跳变,I2C通信停止
	SCL=1;
	delayNOP();
	SDA=1;
	delayNOP();
    SCL=0;
}

/*****************************************************
函数功能:初始化I2C总线
******************************************************/
void iicInit(void)
{
	SCL=0;
	iic_stop();	
}
 
/*****************************************************
函数功能:从机发送应答位
******************************************************/
void slave_ACK(void)
{
	SDA=0;  
	SCL=1;
	delayNOP();	
	SCL=0;
}

/*****************************************************
函数功能:从机发送非应答位,迫使数据传输过程结束
******************************************************/
void slave_NOACK(void)
{ 
	SDA=1;
	SCL=1;
	delayNOP();
	SDA=0;
    SCL=0;  
}

/*****************************************************
函数功能:主机应答位检查,迫使数据传输过程结束
******************************************************/
void check_ACK(void)
{ 	    
    SDA=1;        //将p1.1设置成输入,必须先向端口写1
	SCL=1;
	askflag=0;
	delayNOP();   
	if(SDA==1)    //若SDA=1表明非应答,置位非应答标志askflag
    askflag=1;
   	SCL=0;
}

/*****************************************************
函数功能:发送一个字节
入口参数:ch
******************************************************/
void IICSendByte(uchar ch) 
{
  	unsigned char idata n=8;  //向SDA上发送一位数据字节,共八位
	while(n--)
	{ 
	if((ch&0x80)==0x80)   //若要发送的数据最高位为1则发送位1
	   {
	 		SDA=1;    	//传送位1
			SCL=1;
		    delayNOP();
		//	SDA=0;	
			SCL=0; 
	   }
		else
		{  
			SDA=0;    //否则传送位0
			SCL=1;
			delayNOP();
		  	SCL=0;
		}
		ch=ch<<1;    //数据左移一位
	}
}

/*****************************************************
函数功能:接收一个字节
******************************************************/
uchar IICreceiveByte(void)
{
	uchar idata n=8;     //从SDA线上读取一位数据字节,共八位
	uchar tdata=0;
	while(n--)
	{
		SDA=1;
	    SCL=1;
	    tdata=tdata<<1;		  //左移一位
	   	if(SDA==1)
			tdata=tdata|0x01;   //若接收到的位为1,则数据的最后一位置1(按位”或“)
		else 
		    tdata=tdata&0xfe;   //否则数据的最后一位置0(按位“与”)
	    SCL=0;
	}
	 return(tdata);
}

/*****************************************************
函数功能:发送n位数据子程序
入口参数:slave_add从机地址,n要发送的数据个数
******************************************************/
void DAC_PCF8591(uchar controlbyte,uchar w_data)
{
	iic_start();	//启动I2C
	delayNOP();
	IICSendByte(PCF8591_WRITE);     // 发送地址位
	check_ACK();
	if(askflag==1)
	{
		SystemError=1;
		return;		//若非应答,置错误标志位
	}
	IICSendByte(controlbyte&0x77);	//Control byte 
	check_ACK();                    //检查应答位
    if(askflag==1)
	{ 
		SystemError=1;
		return;                    // 若非应答,置错误标志位
	}
    IICSendByte(w_data);	       //data byte
	check_ACK();                   // 检查应答位
    if(askflag==1)
	{ 
		SystemError=1;
    	return;   // 若非应答表明器件错误或已坏,置错误标志位SystemError
	}
	iic_stop();         // 全部发完则停止
	delayNOP();
	delayNOP();
	delayNOP();
	delayNOP();		
}

/*****************************************************
函数功能:连续读入4路通道的A/D转换结果到receivebuf
入口参数:controlbyte控制字
******************************************************/
void ADC_PCF8591(uchar controlbyte)
{ 
    uchar idata receive_da,i=0;
	iic_start();
	IICSendByte(PCF8591_WRITE);	//控制字
	check_ACK();
	if(askflag==1)
	{
		SystemError=1;
		return;
	}

	IICSendByte(controlbyte);	//控制字
	check_ACK();
	if(askflag==1)
	{
		SystemError=1;
		return;
	}

    iic_start();                //重新发送开始命令
   	IICSendByte(PCF8591_READ);	//控制字
	check_ACK();
	if(askflag==1)
	{
		SystemError=1;
		return;
	}
	 
    IICreceiveByte();   //空读一次,调整读顺序
    slave_ACK();        //收到一个字节后发送一个应答位

	while(i<4)
	{  
	  receive_da=IICreceiveByte();
	  receivebuf[i++]=receive_da;
	  slave_ACK();       //收到一个字节后发送一个应答位
	}
	slave_NOACK();       //收到最后一个字节后发送一个非应答位
	iic_stop();
}

/*****************************************************
函数功能:主程序
******************************************************/
main()
{
	uchar i,l;
	delayms(10);
	LcdInit();		//初始化LCD
	WriteAddress(0);	//设置显示位置为第一行的第1个字符
	i=0;
	while(dis4[i]!='')
	{
		WriteData(dis4[i]);
		i++;	
	}
	WriteAddress(0x40);	//设置显示位置为第二行的第1个字符
	i=0;
	while(dis5[i]!='')
	{
		WriteData(dis5[i]);
		i++;	
	}
	while(1)
	{
		iicInit();		//初始化I2C总线
		ADC_PCF8591(0x04);
		if(SystemError==1)	  //有错误,重新来
	    {
	  		iicInit();				  //I2C总线初始化
	   		ADC_PCF8591(0x04);
	    }
		for(l=0;l<4;l++)	
	 	{
	  		Transform(receivebuf[0]); //显示通道0       
	    	WriteAddress(0x02);             
        	WriteData(dis[2]);        //整数位显示
        	WriteAddress(0x04);             
       	 	WriteData(dis[1]);        //第一位小数显示 
        	WriteAddress(0x05);             
        	WriteData(dis[0]);        //第二位小数显示

	      	Transform(receivebuf[1]); //显示通道1	 
		    WriteAddress(0x0b);             
	        WriteData(dis[2]);        //整数位显示
	        WriteAddress(0x0d);             
	        WriteData(dis[1]);        //第一位小数显示 
	        WriteAddress(0x0e);             
	        WriteData(dis[0]);        //第二位小数显示
	
		  	Transform(receivebuf[2]); //显示通道2         	 
		    WriteAddress(0x42);             
	        WriteData(dis[2]);        //整数位显示
	        WriteAddress(0x44);             
	        WriteData(dis[1]);        //第一位小数显示 
	        WriteAddress(0x45);             
	        WriteData(dis[0]);        //第二位小数显示
	
	      	Transform(receivebuf[3]); //显示通道3	 
		    WriteAddress(0x4b);             
	        WriteData(dis[2]);        //整数位显示
	        WriteAddress(0x4d);              
	        WriteData(dis[1]);        //第一位小数显示 
	        WriteAddress(0x4e);             
	        WriteData(dis[0]);        //第二位小数显示
	
		  	iicInit();	       	      //I2C总线初始化  
	        DAC_PCF8591(0x40,receivebuf[0]); //D/A输出

	   		if(SystemError == 1)	  //有错误,重新来
	    	{
	  	 		iicInit();				  //I2C总线初始化
			    DAC_PCF8591(0x40,receivebuf[0]); //D/A输出
	    	}	        
	 	}
	}
}

最后

以上就是粗心小蜜蜂为你收集整理的基于51单片机的AD转换的全部内容,希望文章能够帮你解决基于51单片机的AD转换所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(76)

评论列表共有 0 条评论

立即
投稿
返回
顶部