本讲内容:
介绍AD/DA芯片PCF8591,通过例程讲解AD和DA过程。
AD和DA的概念:
AD转换的功能是把模拟量电压转换为数字量电压。
DA转换的功能正好相反,就是讲数字量转换位模拟量。
分辨率的概念:
一位数字量所表示的电压值。对于5V的满量程,采用8位的DAC时,分辨率为5V/256=19.5mV。
PCF8591简介:
PCF8591是单片、单电源低功耗8位CMOS数据采集器件,具有4个模拟输入、一个模拟输出和一个串行IIC总线接口。3个地址引脚A0、A1和A2用于编程硬件地址,允许将最多8个器件连接至IIC总线而不需要额外硬件。
PCF8591管脚图:


PCF8591接口电路图:

PCF8591的控制寄存器:

| D1、D0 | AD通道选择00通道0;01通道1;10通道2;11通道3 |
| D2 | 自动增益选择(有效位为1) |
| D5、D4 | 输入模式选择:00四路单数输入;01三路差分输入;10单端与差分配合输入;11为模拟输入有效 |
| D6 | 模拟输出使能位。(时能为1) |
例程:
AD程序
/**********************AD转换*********************
*单片机型号:STC89C52RC
*开发环境:KEIL
*功能:IIC协议 PCF8591 AD转换
***************************************************/
#include<reg52.h>
#include <intrins.h>
#define LCD_Data P0
#define Busy 0x80
#define uchar unsigned char
#define delay0;_nop_();
#define AddWr 0x90
#define AddRd 0x91
sbit RST=P2^4;
sbit Sda=P2^0;
sbit Scl=P2^1;
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_E =P2^5;
bit ADFlag;
uchar code table0[]={" SL-51A "};
uchar code table1[]={" AD CONVERT "};
uchar code table2[]={"CH1: . V"};
uchar code table3[]={"CH2: . V"};
uchar code table4[]={"CH3: . V"};
uchar code table5[]={"CH4: . V"};
uchar TempData[8];
void Delay5Ms(void);
void delay(int In,int Out);
void WriteDataLCD(unsigned char WDLCD);
void WriteCommandLCD(unsigned char WCLCD,BuysC);
uchar ReadDataLCD(void);
uchar ReadStatusLCD(void);
void LCDInit(void);
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData);
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData);
void Init_Timer1(void);
void Start(void);
void Stop(void);
void Ack(void);
void NoAck(void);
void Send(unsigned char Data);
uchar Read(void);
void DAC(unsigned char Data);
uchar ReadADC(unsigned char Chl);
void info_disp(void);
/**********5ms延时函数***************************/
void Delay5Ms(void)
{unsigned int TempCyc=3552;while(TempCyc--);}
/********************延迟函数********************/
void delay(int In,int Out)
{
int i,j;
for(i=0;i<In;i++)
{for(j=0;j<Out;j++){;}}
}
/*------------------------------------------------
初始化定时器1
------------------------------------------------*/
void Init_Timer1(void)
{TMOD|=0x10;TH1=0xff;TL1=0x00;EA=1;ET1=1;TR1=1;}
/*------------------------------------------------
启动IIC总线
------------------------------------------------*/
void Start(void)
{Sda=1;delay0;Scl=1;delay0;Sda=0;delay0;Scl=0;}
/*------------------------------------------------
停止IIC总线
------------------------------------------------*/
void Stop(void)
{Sda=0;delay0;Scl=1;delay0;Sda=1;delay0;Scl=0;}
/*------------------------------------------------
应答IIC总线
------------------------------------------------*/
void Ack(void)
{Sda=0;delay0;Scl=1;delay0;Scl=0;delay0;}
/*------------------------------------------------
非应答IIC总线
------------------------------------------------*/
void NoAck(void)
{Sda=1;delay0;Scl=1;delay0;Scl=0;delay0;}
/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void Send(unsigned char Data)
{
uchar BitCounter=8;uchar temp;
do
{
temp=Data;
Scl=0;delay0;
if((temp&0x80)==0x80){Sda=1;}
else{Sda=0;}
Scl=1;
temp=Data<<1;
Data=temp;
BitCounter--;
}
while(BitCounter);
Scl=0;
}
/*------------------------------------------------
读入一个字节并返回
------------------------------------------------*/
uchar Read(void)
{
uchar temp=0;uchar temp1=0;uchar BitCounter=8;
Sda=1;
do
{
Scl=0;delay0;
Scl=1;delay0;
if(Sda){temp=temp|0x01;}
else{temp=temp&0xfe;}
if(BitCounter-1)
{
temp1=temp<<1;
temp=temp1;
}
BitCounter--;
}
while(BitCounter);
return(temp);
}
/*------------------------------------------------
写入DA数模转换值
------------------------------------------------*/
void DAC(unsigned char Data)
{
Start();Send(AddWr);
Ack();Send(0x40);
Ack();Send(Data);
Ack();Stop();
}
/*------------------------------------------------
读取AD模数转换的值,有返回值
------------------------------------------------*/
uchar ReadADC(unsigned char Chl)
{
uchar Data;
Start();
Send(AddWr);Ack();
Send(0x40|Chl);Ack();
Start();Send(AddRd);
Ack();Data=Read();
Scl=0;
NoAck();Stop();
return Data;
}
/*******************写数据函数*******************/
void WriteDataLCD(unsigned char WDLCD)
{
ReadStatusLCD();
LCD_Data=WDLCD;
LCD_RS=1;
LCD_RW=0;
LCD_E=0;
LCD_E=0;
LCD_E=1;
}
/*******************写指令函数*******************/
void WriteCommandLCD(unsigned char WCLCD,BuysC)
{
if(BuysC)ReadStatusLCD();
LCD_Data=WCLCD;
LCD_RS=0;
LCD_RW=0;
LCD_E=0;
LCD_E=0;
LCD_E=1;
}
/*******************读数据函数*******************/
unsigned char ReadDataLCD(void)
{
LCD_RS=1;
LCD_RW=1;
LCD_E=0;
LCD_E=0;
LCD_E=1;
return(LCD_Data);
}
/*******************读状态函数*******************/
unsigned char ReadStatusLCD(void)
{
LCD_Data=0xFF;
LCD_RS=0;
LCD_RW=1;
LCD_E=0;
LCD_E=0;
LCD_E=1;
while (LCD_Data&Busy);
return(LCD_Data);
}
/********************LCD初始化*******************/
void LCDInit(void)
{
LCD_Data=0;
WriteCommandLCD(0x38,0);Delay5Ms();
WriteCommandLCD(0x38,0);Delay5Ms();
WriteCommandLCD(0x38,0);Delay5Ms();
WriteCommandLCD(0x38,1);
WriteCommandLCD(0x08,1);
WriteCommandLCD(0x01,1);
WriteCommandLCD(0x06,1);
WriteCommandLCD(0x0C,1);
}
/********************清屏 函数********************/
void LCD_Clear(void){WriteCommandLCD(0x01,1);Delay5Ms();}
/**************按指定位置显示一个字符*************/
void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData)
{
Y&=0x1;X&=0xF;
if(Y)X|=0x40;
X|=0x80;
WriteCommandLCD(X, 0);
WriteDataLCD(DData);
}
/**************按指定位置显示一串字符*************/
void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData)
{
unsigned char ListLength;ListLength=0;
Y&=0x1;X&=0xF;
while(DData[ListLength]>=0x20)
{
if(X<=0xF)
{
DisplayOneChar(X, Y, DData[ListLength]);
ListLength++;
X++;
}
}
}
/********************系统初始化*******************/
void sys_init(void)
{
LCDInit();
delay(5,100);
Init_Timer1();
DisplayListChar(0,0,table0);
DisplayListChar(0,1,table1);
}
/*------------------------------------------------
显示
------------------------------------------------*/
void info_disp(void)
{
DisplayListChar(0,0,table2);
DisplayOneChar(4,0,(0x30+TempData[0]));
DisplayOneChar(6,0,(0x30+TempData[1]));
DisplayListChar(8,0,table3);
DisplayOneChar(12,0,(0x30+TempData[2]));
DisplayOneChar(14,0,(0x30+TempData[3]));
DisplayListChar(0,1,table4);
DisplayOneChar(4,1,(0x30+TempData[4]));
DisplayOneChar(6,1,(0x30+TempData[5]));
DisplayListChar(8,1,table5);
DisplayOneChar(12,1,(0x30+TempData[6]));
DisplayOneChar(14,1,(0x30+TempData[7]));
}
/*------------------------------------------------
主程序
------------------------------------------------*/
void main()
{
uchar num;uchar ADtemp;
sys_init();delay(100,1000);
LCD_Clear();
while(1)
{
DAC(num);num++;delay(5,100);
if(ADFlag)
{
ADFlag=0;
ADtemp=ReadADC(0);
TempData[0]=(ReadADC(0))/50;TempData[1]=((ReadADC(0))%50)/10;
ADtemp=ReadADC(1);
TempData[2]=(ReadADC(1))/50;TempData[3]=((ReadADC(1))%50)/10;
ADtemp=ReadADC(2);
TempData[4]=(ReadADC(2))/50;TempData[5]=((ReadADC(2))%50)/10;
ADtemp=ReadADC(3);
TempData[6]=(ReadADC(3))/50;TempData[7]=((ReadADC(4))%50)/10;
info_disp();
}
}
}
/*------------------------------------------------
定时器中断程序
------------------------------------------------*/
void Timer1_isr(void) interrupt 3 using 1
{
static unsigned int j;
TH1=0xfb;TL1=0x00;
j++;
if(j==200){j=0;ADFlag=1;}
}
DA程序
/******************DA转换LED输出******************
*单片机型号:STC89C52RC
*开发环境:KEIL
*功能:此程序通过IIC协议对DAAD芯片操作, 并输出模拟量,用LED亮度渐变指示
*******************************************************/
#include<reg52.h>
#include <intrins.h>
#define delay0; _nop_();
#define uchar unsigned char
#define AddWr 0x90
#define AddRd 0x91
sbit RST=P2^4;
sbit Sda=P2^0;
sbit Scl=P2^1;
sbit Fm=P2^3;
sbit LE1=P2^6;
sbit LE2=P2^7;
bit ADFlag;
uchar code Datatab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
data uchar Display[8];
/*------------------------------------------------
延时程序
------------------------------------------------*/
void mDelay(uchar 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;}
/*------------------------------------------------
启动IIC总线
------------------------------------------------*/
void Start(void)
{Sda=1;delay0;Scl=1;delay0;Sda=0;delay0;Scl=0;}
/*------------------------------------------------
停止IIC总线
------------------------------------------------*/
void Stop(void)
{Sda=0;delay0;Scl=1;delay0;Sda=1;delay0;Scl=0;}
/*------------------------------------------------
应答IIC总线
------------------------------------------------*/
void Ack(void)
{Sda=0;delay0;Scl=1;delay0;Scl=0;delay0;}
/*------------------------------------------------
非应答IIC总线
------------------------------------------------*/
void NoAck(void)
{Sda=1;delay0;Scl=1;delay0;Scl=0;delay0;}
/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void Send(uchar Data)
{
uchar BitCounter=8;
uchar buffer;
do
{
buffer=Data;
Scl=0;delay0;
if((buffer&0x80)==0x80)Sda=1;
else Sda=0;
Scl=1;
buffer=Data<<1;
Data=buffer;
BitCounter--;
}
while(BitCounter);
Scl=0;
}
/*------------------------------------------------
读入一个字节并返回
------------------------------------------------*/
uchar Read(void)
{
uchar buffer=0;
uchar buffer1=0;
uchar BitCounter=8;
Sda=1;
do
{
Scl=0;delay0;
Scl=1;delay0;
if(Sda)buffer=buffer|0x01;
else buffer=buffer&0xfe;
if(BitCounter-1)
{
buffer1=buffer<<1;
buffer=buffer1;
}
BitCounter--;
}
while(BitCounter);
return(buffer);
}
/*------------------------------------------------
写入DA数模转换值
------------------------------------------------*/
void DAC(uchar Data)
{
Start();Send(AddWr);
Ack();Send(0x40);
Ack();Send(Data);
Ack();Stop();
}
/*------------------------------------------------
读取AD模数转换的值,有返回值
------------------------------------------------*/
uchar ReadADC(uchar Chl)
{
uchar Data;
Start();Send(AddWr);
Ack();Send(0x40|Chl);
Ack();
Start();Send(AddRd);
Ack();Data=Read();
Scl=0;NoAck();
Stop();
return Data;
}
void fmg(void){Fm=1;}
void cmg(void)
{
LE1=1;
P0=0x00;
LE1=0;LE2=1;
P0=0x00;
LE2=0;RST=0;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
void main()
{
uchar num;
uchar ADbuffer;
Init_Timer1();
cmg();
fmg();
while(1)
{
DAC(num);
num++;
mDelay(20);
if(ADFlag)
{
ADFlag=0;
ADbuffer=ReadADC(0);
Display[0]=Datatab[(ReadADC(0))/50]|0x80;
Display[1]=Datatab[((ReadADC(0))%50)/10];
ADbuffer=ReadADC(1);
Display[2]=Datatab[((ReadADC(1))/50)]|0x80;
Display[3]=Datatab[((ReadADC(1))%50)/10];
ADbuffer=ReadADC(2);
Display[4]=Datatab[((ReadADC(2))/50)]|0x80;
Display[5]=Datatab[((ReadADC(2))%50)/10];
ADbuffer=ReadADC(3);
Display[6]=Datatab[((ReadADC(3))/50)]|0x80;
Display[7]=Datatab[((ReadADC(3))%50)/10];
}
}
}
最后,求求看到的此文的小伙伴点赞和关注支持一下下哦。毕竟,码字不容易哦,您的支持是我最大的动力呀!!!呜呜呜~~~
4827





