电压越低采集的ad值反而变大_基于51单片机及PCF8591芯片的ADC电压检测

单片机介绍:

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供电

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增益

电路图:

cbfab78971e0ddb1e55823d35a6d2619.png

PCF8591的ADC电路:

04b97744304b7d3fb33ee317939ba1c9.png

PCB图:

2维

dbb245f11ac9116f073ca12f363625dd.png

3维

dd4d1ec2a326970c4a28480c22bb7e43.png

部分代码:

main.c

#include    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义#include  //包含NOP空指令函数_nop_();#include#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);            //初始化定时器1void 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++)       {;}   }}//初始化定时器1void 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#include#include//1602引脚sbit RS = P1^0; //Pin4sbit RW = P1^1; //Pin5sbit 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[]字符串}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于51单片机PCF8591芯片ADC电压检测加LCD1602显示程序: ``` #include<reg51.h> #include<intrins.h> #define uchar unsigned char #define uint unsigned int sbit RS=P2^0; //RS引脚 sbit RW=P2^1; //RW引脚 sbit EN=P2^2; //EN引脚 sbit SDA=P1^1; //IIC数据线 sbit SCL=P1^0; //IIC时钟线 void delay(uint xms) //延时函数 { uint i,j; for(i=xms;i>0;i--) for(j=110;j>0;j--); } void LCD_WriteCom(uchar com) //写命令函数 { RS=0; RW=0; P0=com; EN=1; _nop_(); EN=0; delay(5); } void LCD_WriteData(uchar dat) //写数据函数 { RS=1; RW=0; P0=dat; EN=1; _nop_(); EN=0; delay(5); } void LCD_Init() //LCD初始化函数 { delay(50); LCD_WriteCom(0x38); LCD_WriteCom(0x0c); LCD_WriteCom(0x06); LCD_WriteCom(0x01); delay(5); } void IIC_Start() //IIC开始信号函数 { SDA=1; SCL=1; delay(5); SDA=0; delay(5); SCL=0; } void IIC_Stop() //IIC停止信号函数 { SDA=0; SCL=1; delay(5); SDA=1; delay(5); } void IIC_SendByte(uchar dat) //IIC发送一个字节函数 { uchar i; for(i=0;i<8;i++) { if(dat&0x80) SDA=1; else SDA=0; SCL=1; delay(5); SCL=0; dat<<=1; } SDA=1; SCL=1; delay(5); SCL=0; } uchar IIC_ReadByte() //IIC读一个字节函数 { uchar i,dat=0; SDA=1; for(i=0;i<8;i++) { dat<<=1; SCL=1; delay(5); if(SDA) dat|=0x01; SCL=0; delay(5); } return dat; } void PCF8591_Write(uchar dat) //写DAC函数 { IIC_Start(); IIC_SendByte(0x90); IIC_ReadByte(); IIC_SendByte(dat); IIC_ReadByte(); IIC_Stop(); } uchar PCF8591_Read() //读ADC函数 { uchar dat; IIC_Start(); IIC_SendByte(0x90); IIC_ReadByte(); IIC_SendByte(0x00); IIC_ReadByte(); IIC_Start(); IIC_SendByte(0x91); IIC_ReadByte(); dat=IIC_ReadByte(); IIC_Stop(); return dat; } void main() { uchar dat; LCD_Init(); while(1) { dat=PCF8591_Read(); LCD_WriteCom(0x80); LCD_WriteData('V'); LCD_WriteData(':'); LCD_WriteData(dat/10+'0'); LCD_WriteData(dat%10+'0'); delay(100); } } ``` 该程序主要实现了通过PCF8591芯片实现ADC电压检测,并将检测到的电压显示在LCD1602上。其中,PCF8591_Read函数用于读取ADC芯片电压PCF8591_Write函数用于写入DAC芯片的输出电压,LCD_Init函数用于初始化LCD1602,LCD_WriteCom函数用于向LCD1602发送命令,LCD_WriteData函数用于向LCD1602发送数据。在主函数中,通过调用PCF8591_Read函数获取到电压,然后将其显示在LCD1602上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值