欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于51单片机及PCF8591芯片的ADC电压检测

程序员文章站 2024-02-24 10:24:16
...

前述:
QQ:3177227373
这个是一个简易课设作品。

资源链接:
链接:https://pan.baidu.com/s/1tLS-Wpq3awp7Asr0XCV94w
提取码:z284

单片机介绍:

8位CPU·4kbytes程序存储器(ROM) (52为8K)
128bytes的数据存储器(RAM) (52有256bytes的RAM)
32条I/O口线,111条指令,大部分为单字节指令
21个专用寄存器
2个可编程定时/计数器·5个中断源,2个优先级(52有6个)
一个全双工串行通信口
I/O口:四个8位,并行I/O口,既可用作输入,也可用作输出
两个定时器,两个外部中断,一个全双工串口。
5V供电

其余资料参考芯片手册
芯片手册:百度网盘链接  (点击蓝色字体即可跳转)
提取码:u0po

PCF8591芯片:

注意

       如果采用其中一个通道的话是直接读取该通道的数据,如果是采用两个通道的话需要交换读取数据通道口,比如用通道一和二,那么读取实际电路通道一的数据需要在程序中写Dat1=Read(2);Dat2=Read(1); 这是因为在读取PCF8591的通道口数据的时候是上一次通道口转换的的数据。
       PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。

【1】单独供电

【2】PCF8591的操作电压范围2.5V-6V

【3】低待机电流

【4】通过I2C总线串行输入/输出

【5】PCF8591通过3个硬件地址引脚寻址

【6】PCF8591的采样率由I2C总线速率决定

【7】4个模拟输入可编程为单端型或差分输入

【8】自动增量频道选择

【9】PCF8591的模拟电压范围从VSS到VDD

【10】PCF8591内置跟踪保持电路

【11】8-bit逐次逼近A/D转换器

【12】通过1路模拟输出实现DAC增益

实验电路图:

基于51单片机及PCF8591芯片的ADC电压检测
PCF8591的ADC电路:
基于51单片机及PCF8591芯片的ADC电压检测
PCB图:
2维
基于51单片机及PCF8591芯片的ADC电压检测
3维
基于51单片机及PCF8591芯片的ADC电压检测
部分代码:
main.c

#include<reg52.h>    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <intrins.h> //包含NOP空指令函数_nop_();
#include<LCD1602.h>

#define AddWr 0x90   //写数据地址
#define AddRd 0x91   //读数据地址

sbit Sda=P2^0;       //定义总线连接端口
sbit Scl=P2^1;

bit ADFlag;          //定义AD采样标志位

void mDelay(unsigned char j);      //延时程序
void Init_Timer1(void);            //初始化定时器1
void Start(void);                  //启动IIC总线   通信方式
void Stop(void);                   //停止IIC总线
void Ack(void);                    //应答IIC总线
void NoAck(void);                  //非应答IIC总线
void Send(unsigned char Data);     //发送一个字节
unsigned char Read(void);          //读入一个字节并返回
unsigned char ReadADC(unsigned char Chl); //读取AD模数转换的值,有返回值
void DAC(unsigned char Data); //DAC输出

void main()
{
	unsigned int ADtemp,ADtemp1;//定义中间变量
	InitLcd();
	mDelay(20);
	Init_Timer1();
	while(1)
	{ 
		DAC(255);  //DA输出0,灯灭
		mDelay(20);     //延时用于清晰看出变化
		if(ADFlag)      //定时采集输入模拟量
		{
			DAC(0);     //输出高,灯亮
			ADFlag=0;   //标志位置0
			
			ADtemp1=ReadADC(0); //读取通道1
			TempData[0]=(2*ADtemp1)/50;   //处理0通道电压显示
			TempData[1]=(2*ADtemp1)%50/10;
		
			ADtemp=ReadADC(1); //读取通道2
			TempData[2]=(ReadADC(1)*2)/50;//处理1通道电压显示
			TempData[3]=((ReadADC(1)*2)%50)/10;

			ADtemp=ReadADC(2); //读取通道3
			TempData[4]=(ReadADC(2))/50;//处理1通道电压显示
			TempData[5]=((ReadADC(2))%50)/10;
			
			ADtemp=ReadADC(3); //读取通道4
			TempData[6]=(ReadADC(3))/50;//处理1通道电压显示
			TempData[7]=((ReadADC(4))%50)/10;
  		
			disp();  //显示
		}
	}
}

void DAC(unsigned char Data)
{
	Start();
	Send(AddWr); //写入芯片地址
	Ack();
	Send(0x40);  //写入控制位,使能DAC输出
	Ack();
	Send(Data);  //写数据
	Ack();
	Stop();
		 
}
//延时程序
void mDelay(unsigned char j)
{
	unsigned int i;
	for(;j>0;j--)
     {
	  for(i=0;i<125;i++)
	     {;}
	 }
}

//初始化定时器1
void Init_Timer1(void)
{
	TMOD |= 0x10;			     
	TH1=0xff;  //
	TL1=0x00;
	EA=1;                 
	ET1=1;                  
	TR1=1;  
}

//定时器中断程序
void Timer1_isr(void) interrupt 3
{
	static unsigned int j;  //静态变量,只初始化一次
	TH1=0xfb;		//重新赋值
	TL1=0x00;
	j++;
	if(j==200)
    {
		j=0;
		ADFlag=1;  //定时置位AD采样标志位
	} 
}

//读取AD模数转换的值,有返回值
unsigned char ReadADC(unsigned char Chl)
{
	unsigned char Data;
	Start();        //写入芯片地址
	Send(AddWr);
	Ack();
	Send(0x40|Chl);//写入选择的通道,Chl的值分别为0、1、2、3,分别代表1-4通道
	Ack();
	Start();
	Send(AddRd);    //读入地址
	Ack();
	Data=Read();    //读数据
	Scl=0;
	NoAck();
	Stop();
	return Data;   //返回值
}


//读入一个字节并返回
unsigned char Read(void)
{
	unsigned char temp=0;
	unsigned char temp1=0;
	unsigned char BitCounter=8;

	Sda=1;
	do
	{
		Scl=0;
		_nop_();
		Scl=1;
		_nop_();
		if(Sda)
			temp=temp|0x01;
		else
		    temp=temp&0xfe;

	if(BitCounter-1)
	{
	temp1=temp<<1;
	temp=temp1;
	}
	BitCounter--;
	}
	while(BitCounter);
	return(temp);
}

//启动IIC总线
void Start(void)
{
   Sda=1;
   _nop_();
   Scl=1;
   _nop_();
   Sda=0;
   _nop_();
   Scl=0;
}

//停止IIC总线
void Stop(void)
{
	   Sda=0;
	   _nop_();
	   Scl=1;
	   _nop_();
	   Sda=1;
	   _nop_();
	   Scl=0;
}

//应答IIC总线
void Ack(void)
{
		Sda=0;
		_nop_();
		Scl=1;
		_nop_();
		Scl=0;
		_nop_();
}

//非应答IIC总线
void NoAck(void)
{
		 Sda=1;
		 _nop_();
		 Scl=1;
		 _nop_();
		 Scl=0;
		 _nop_();
}

//发送一个字节
void Send(unsigned char Data)
{ 
	  unsigned char BitCounter=8;
	  unsigned char temp;

	  do
	    {
		 temp=Data;
		 Scl=0;
		 _nop_();
		 if((temp&0x80)==0x80)
		    Sda=1;
		 else
		    Sda=0;

			Scl=1;
			temp=Data<<1;
			Data=temp;
			BitCounter--;
		  }
	  while(BitCounter);
	      Scl=0;
}

1602.h

#include<reg52.h>
#include<stdio.h>
#include<intrins.h>

//1602引脚
sbit RS = P1^0; //Pin4
sbit RW = P1^1; //Pin5
sbit E  = P2^5; //Pin6

#define Data  P0    //数据1602数据传送端口

unsigned char TempData[8];

unsigned char  SecondLine[]="                ";//初始化位空的字符串,在读取回来AD值以后填充
unsigned char  FirstLine[] ="                ";//初始化位空的字符串,在读取回来AD值以后填充

void DelayUs(unsigned char us)//delay us
{
 unsigned char uscnt;
 uscnt=us>>1;
 while(--uscnt);
}
/******************************************************************/
void DelayMs(unsigned char ms)//delay Ms
{
 while(--ms)
   {
     DelayUs(250);
     DelayUs(250);
	 DelayUs(250);
	 DelayUs(250);
   }
}
void WriteCommand(unsigned char c)
{
	 DelayMs(5);//short delay before operation
	 E=0;
	 RS=0;
	 RW=0;
	 _nop_();
	 E=1;
	 Data=c;
	 E=0;
}
void WriteData(unsigned char c)
{
	 DelayMs(5);   //short delay before operation
	 E=0;
	 RS=1;
	 RW=0;
	 _nop_();
	 E=1;
	 Data=c;
	 E=0;
	 RS=0;
}

void ShowChar(unsigned char pos,unsigned char c)
{
	 unsigned char p;
	 if (pos>=0x10)
		p=pos+0xb0; //是第二行则命令代码高4位为0xc
	 else 
		p=pos+0x80; //是第二行则命令代码高4位为0x8
	 WriteCommand (p);//write command
	 WriteData (c);   //write data
}

//显示变量
void ShowString (unsigned char line,char *ptr)//显示变量
{
 unsigned char l,i;
 l=line<<4;
 for (i=0;i<16;i++)
  ShowChar (l++,*(ptr+i));//循环显示16个字符
}

//LCD初始化
void InitLcd()
{
	 DelayMs(15);
	 WriteCommand(0x38); //display mode
	 WriteCommand(0x38); //display mode
	 WriteCommand(0x38); //display mode
	 WriteCommand(0x06); //显示光标移动位置
	 WriteCommand(0x0c); //显示开及光标设置
	 WriteCommand(0x01); //显示清屏
}

//1602显示
void disp(void)
{
	//第一行
	FirstLine[2]='0'+TempData[0]; //把通道1电压的整数部分存入FirstLine[]数组
	FirstLine[3]='.';             //存入 .
	FirstLine[4]='0'+TempData[1]; //把通道1电压的小数部分存入FirstLine[]数组
	FirstLine[6]='V';             //存入 V 符号

	FirstLine[9] ='0'+TempData[2];
	FirstLine[10]='.';
	FirstLine[11]='0'+TempData[3];
	FirstLine[13]='V';

	 //第二行
	 SecondLine[2]='0'+TempData[4];
	 SecondLine[4]='0'+TempData[5];
	 SecondLine[3]='.';
	 SecondLine[6]='V';

	 SecondLine[9]='0'+TempData[6];
	 SecondLine[11]='0'+TempData[7];
	 SecondLine[10]='.';
	 SecondLine[13]='V';

     //显示字符串
	 ShowString(0,FirstLine);  //第一行显示FirstLine[]字符串
	 ShowString(1,SecondLine); //第二行显示SecondLine[]字符串
}

相关标签: 单片机 c语言