单片机介绍:
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增益
电路图:
PCF8591的ADC电路:
PCB图:
2维
3维
部分代码:
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[]字符串}