基于51单片机用PCF8591进行AD_DA转换用1602LCD显示的电流采样(DOC)
学51单片机-基于PCF8591的AD采样和DA输出

学51单片机-基于PCF8591的AD采样和DA输出首先思考一个问题,我们的世界是数字的还是模拟的?当然是模拟的了,所有的量都是在一定范围内连续变化的。
我们为了能够更加方便的描述这些量,对它们进行了数字化。
而数字量就不一样了,它是分立的的几个值。
举个例子,我们形容一个人的身高,模拟的说法是一米七到一米七五之间,数字的说法就是一米七三。
接下来说AD转换器,它的出现也是为了让我们能更方便、更直接的描述电压的高低。
AD转换器,英文全称为Analog-to-Digital Converter,是模拟量到数字量的一个转换过程,主要用于电压的采集。
它的出现就如同有了一把尺子,很容易就能量出电压的高低。
在电子设备中,经常要检测各种模拟量:温度、压力、速度、流量、重力加速度等等,这些模拟量都被相应的传感器转换为电压信号,我们只需要测量电压的高低,就能得到相应参数。
AD的主要参数有哪些?1、AD的位数:表明这个AD共有2^n个刻度,8位AD,输出的刻度是0~255.2、分辨率:就是AD能够分辨的最小的模拟量变化,假设5.10V的系统用8位的AD采样,那么它能分辨的最小电压就是5.10/255=0.02V。
3、INL:Interger NONliner积分非线性度,表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。
也就是,输出数值偏离线性最大的距离。
单位是LSB(即最低位所表示的量)。
比如12位ADC:TLC2543,INL值为1LSB。
那么,如果基准4.095V,测某电压得的转换结果是1000,那么,真实电压值可能分布在0.999~1.001V之间。
4、DNL:Differencial NonLiner-差分非线性度,理论上说,模数器件相邻量个数据之间,模拟量的差值都是一样的。
就相一把疏密均匀的尺子。
但实际并不如此。
一把分辨率1毫米的尺子,相邻两刻度之间也不可能都是1毫米整。
那么,ADC相邻两刻度之间最大的差异就叫差分非线性值(Differencial NonLiner)。
基于51单片机的AD和DA

基于51单片机的AD和DA本讲内容:介绍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的控制寄存器:例程: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 0x91sbit 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 0x91sbit 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]; }}}。
基于51单片机的1602LCD显示

标签:单片机LCD基于51单片机的1602LCD显示基于51单片机的1602LCD显示LCD(liquid crystal display)为液晶显示器,它一般不会单独使用,而是将LCD面板、驱动与控制电路组合成LCD模块(1iquid crystal display moulde,简称为LCM)来使用。
LCM是一种很省电的显示设备,常被应用在数字或微处理器控制的系统,做为简易的人机接口,但人们一般还是习惯称之为LCD显示器。
1 硬件设计采用51单片机控制1602LCD显示器的电路如下所示。
在桌面上双击图标,打开ISIS 7 Professional窗口(本人使用的是v7.4 SP3中文版)。
单击菜单命令“文件”→“新建设计”,选择DEFAULT 模板,保存文件名为“LCD.DSN”。
在器件选择按钮中单击“P”按钮,或执行菜单命令“库”→“拾取元件/符号”,添加如下表所示的元件。
51单片机AT89C51 一片晶体CRYSTAL 12MHz 一只瓷片电容CAP 22pF 二只电解电容CAP-ELEC 10uF 一只电阻RES 10K 一只排阻RESPAC-8 10K 一只1602液晶显示器LM016L 一只若用Proteus软件进行仿真,则上图中的晶振和复位电路以及U1的31脚,都可以不画,它们都是默认的。
在ISIS原理图编辑窗口中放置元件,再单击工具箱中元件终端图标,在对象选择器中单击POWER和GROUND放置电源和地。
放置好元件后,布好线。
左键双击各元件,设置相应元件参数,完成电路图的设计。
2 软件设计用1602LCD显示两行字符的流程图如下所示。
用1602LCD显示“Welcom to China”和“Hi!Good morning!”的详细C51程序如下。
//用LCD循环显示"Welcome to China"和"Hi!Good morning!"#include<reg51.h> //包含单片机的头文件#include<intrins.h> //包含_nop_()函数定义的头文件sbit RS="P2"^0; //寄存器选择位,将RS位定义为P2.0引脚sbit RW="P2"^1; //读写选择位,将RW位定义为P2.1引脚sbit E="P2"^2; //使能信号位,将E位定义为P2.2引脚sbit BF="P0"^7; //忙碌标志位,,将BF位定义为P0.7引脚unsigned char code string[ ]={"Welcome to China"};unsigned char code string1[ ]={"Hi!Good morning!"};/*************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒*************************************************/void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++);}/*****************************函数功能:延时若干毫秒入口参数:n******************************/void delay(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/*******************************************函数功能:判断液晶模块的忙碌状态返回值:result。
基于51单片机的1602LCD显示

标签:单片机LCD基于51单片机的1602LCD显示基于51单片机的1602LCD显示LCD(liquid crystal display)为液晶显示器,它一般不会单独使用,而是将LCD面板、驱动与控制电路组合成LCD模块(1iquid crystal display moulde,简称为LCM)来使用。
LCM是一种很省电的显示设备,常被应用在数字或微处理器控制的系统,做为简易的人机接口,但人们一般还是习惯称之为LCD显示器。
1 硬件设计采用51单片机控制1602LCD显示器的电路如下所示。
在桌面上双击图标,打开ISIS 7 Professional窗口(本人使用的是v7.4 SP3中文版)。
单击菜单命令“文件”→“新建设计”,选择DEFAULT 模板,保存文件名为“LCD.DSN”。
在器件选择按钮中单击“P”按钮,或执行菜单命令“库”→“拾取元件/符号”,添加如下表51单片机AT89C51 一片晶体CRYSTAL 12MHz 一只瓷片电容CAP 22pF 二只电解电容CAP-ELEC 10uF 一只电阻RES 10K 一只排阻 RESPAC-8 10K 一只1602液晶显示器 LM016L 一只若用Proteus软件进行仿真,则上图中的晶振和复位电路以及U1的31脚,都可以不画,它们都是默认的。
在ISIS原理图编辑窗口中放置元件,再单击工具箱中元件终端图标,在对象选择器中单击POWER和GROUND放置电源和地。
放置好元件后,布好线。
左键双击各元件,设置相应元件参数,完成电路图的设计。
2 软件设计用1602LCD显示两行字符的流程图如下所示。
用1602LCD显示“Welcom to China”和“Hi!Good morning!”的详细C51程序如下。
//用LCD循环显示"Welcome to China"和"Hi!Good morning!"#include<reg51.h> //包含单片机的头文件#include<intrins.h> //包含_nop_()函数定义的头文件sbit RS="P2"^0; //寄存器选择位,将RS位定义为P2.0引脚sbit RW="P2"^1; //读写选择位,将RW位定义为P2.1引脚sbit E="P2"^2; //使能信号位,将E位定义为P2.2引脚sbit BF="P0"^7; //忙碌标志位,,将BF位定义为P0.7引脚unsigned char code string[ ]={"Welcome to China"};unsigned char code string1[ ]={"Hi!Good morning!"};/*************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒*************************************************/void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++);}/*****************************函数功能:延时若干毫秒入口参数:n******************************/void delay(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/*******************************************函数功能:判断液晶模块的忙碌状态返回值:result。
基于51单片机的AD pcf8951 C程序

sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
k=(k<<1)|sda;
scl=0;
delay();
}
return k;
}
void ad_zhuan()//初始化AD转换
{
start();//启动信号
write_byte(0x90);//寻pcf8591址
respons();
stop();
return temp;
}
void main()
{
uchar a,A1,A2,A3,adval;
init();//初始化
//write_add(23,0xaa);向EEPROM写
delay1(100);
//P1=read_add(23);读EEPROM中数据
while(1)
scl=1;
delay();
TMOD=0x21; //定时器1的工作方式2;8位初值自动重装定时器
SCON=0x50;//8位数据允许串行接受
TH1= 0xfd;//产生波特率
TL1= 0xfd;
EA=1;
TR0=1;
}
void write_byte(uchar date)//写一个字节
{
uchar i,temp;
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
void respons() //应答
{
uchar i;
scl=1;
delay();
单片机代码-AD转换电压在1602中显示

#include<reg52.h>#include<intrins.h>//为了使用这个头文件中的_nop_()延时函数sbit sda=P2^0;//SDA线sbit scl=P2^1;//SCL线sbit rst=P2^4; //关掉时钟芯片输出sbit hc573_sg_le=P2^6; //对用于锁存段数据的573锁存LE端进行定义sbit hc573_bit_le=P2^7;//对用于锁存位选通数据的573锁存LE端进行定义sbit lcd_rs=P1^0; //1602数据/命令选择端,高电平执行数据操作,低电平执行命令操作sbit lcd_rw=P1^1;//1602读/写控制端高电平读,低电平写sbit lcd_en=P2^5;//1602读写控制使能信号,它为高脉冲信号才可执行读写操作sbit sta7=P0^7;//1602忙信号检测位,为1则忙,需等待,为0表示空闲void delay_ms(unsigned int t) //tms的延时函数{unsigned int a,b;for(a=0;a<t;a++){for(b=0;b<113;b++){;}}}void _nop5_()//5个机器周期的延时,大约延时5us{_nop_();_nop_();_nop_();_nop_();_nop_();}void iic_start()//主机发送开始信号的函数{scl=0;//SCL线拉低,以便让SDA线准备变化sda=1;//SDA线拉高,准备产生开始信号scl=1;//SCL线拉高_nop5_(); //SDA线高电平持续5us,以符合开始信号定义的要求(>4.7us)sda=0;//SDA线拉低,产生开始信号_nop5_();//SDA线低电平持续5us,以符合开始信号定义的要求(>4us)}void iic_stop()//主机发送停止信号的函数{scl=0;//SCL线拉低,以便让SDA线准备变化sda=0;//SDA线拉低,准备产生停止信号scl=1;//SCL线拉高_nop5_(); //SDA线低电平持续5us,以符合停止信号定义的要求(>4us)sda=1;//SDA线拉高,产生停止信号_nop5_(); //SDA线的高电平持续5us,以符合停止信号定义的要求(>4.7us)}void iic_ack()//检测从机应答信号的函数{unsigned char i;i=255;scl=0;//SCL线拉低,以便让SDA线准备变化sda=1;//SDA线拉高,准备检测从机的应答信号while(sda==1)//当SDA为高电平时,则等待从机的应答将SDA拉低{if(i>0)i--;else return; //如果i自减到0了,从机还没响应,则不再等待,返回}//这种情况极少发生,一般是从机器件出问题了才会发生scl=1;//从机已经应答,将SDA线拉低了_nop5_();//SDA线的低电平持续5us,以符合应答信号定义的要求(>4us)scl=0;//SCL线拉低,以便让从机把SDA线释放}void send_ack()//主机给从机发送应答信号{scl=0;//SCL线拉低,以便让SDA线准备变化sda=0;//SDA线拉低,即将发送应答信号给从机scl=1;//SCL线拉高,将应答信号发送过去_nop5_();//SDA线的低电平持续5us,以符合应答信号定义的要求(>4us)scl=0;//SCL线拉低,以便让SDA线准备变化sda=1;//释放SDA线}void iic_send_no_ack()//主机给从机发送非应答信号{scl=0;//SCL线拉低,以便让SDA线准备变化sda=1;//SDA线拉高,即将发送非应答信号给从机scl=1;//SCL线拉高,将应答信号发送过去_nop5_();//SDA线的高电平持续5us,以符合非应答信号定义的要求(>4us)}void iic_write(unsigned char dat)//主机向从机写操作函数{unsigned char i;for(i=0;i<8;i++){scl=0;//SCL线拉低,以便让SDA线准备变化sda=(bit)(0x80&dat); //取字节数据的最高位,发送到SDA线dat=dat<<1;//发送的数据都是由高位到低位顺序发送的,所以要将所//需发送的那位移到数据的最高位,以发送到SDA线上scl=1;//SCL线拉高,数据被发送过去}}unsigned char iic_read()//主机向从机读操作的函数{unsigned char i;unsigned char dat; //定义一个字节变量,用来存储读出的从机数据dat=0;for(i=0;i<8;i++){dat=dat<<1;//将位数据不断地往高位移动,将接收到的位数据转换为字节数据scl=0;//SCL线拉低,以便让SDA线准备变化dat=dat|(unsigned char)sda;//将接收到的位数据强制转换成字节数据,并存到dat 中scl=1;//SCL线拉高,接收下一位数据}return dat;//数据接收完毕,带数据返回}void lcd_busy_check(void)//1602忙信号检测,忙则等待{P0=0xff;do{lcd_rs=0;//读状态操作,为0lcd_rw=1;//读操作为1lcd_en=0;lcd_en=1;//读状态,需为高电平}while (sta7==1);//如果为1则忙,等待...直到为0lcd_en=0;}void lcd_write_cmd(unsigned char cmd) //液晶写命令函数{lcd_busy_check(); //每次操作之前都要进行忙信号检测lcd_rs=0;//执行命令操作,为0lcd_rw=0;//写操作,为0P0=cmd;//送指令到液晶数据端口P0,准备执行命令_nop_();//这是一个延时函数,可延时一个机器周期,它在“intrins.h”中lcd_en=1;//高电平,指令送入液晶控制器_nop_();//保持一会儿,使指令可靠地送入液晶控制器lcd_en=0;//低电平,执行命令}void lcd_write_data(unsigned char dat) //液晶写数据函数{lcd_busy_check();//每次操作之前都要进行忙信号检测lcd_rs=1;//执行数据操作,为1lcd_rw=0;//写操作,为0P0=dat;//送数据到液晶数据端口P0,准备执行数据操作_nop_();lcd_en=1;//高电平,数据送入液晶液晶数据RAM_nop_();//保持一会儿,使显示数据可靠地送入液晶数据RAMlcd_en=0;//低电平,显示数据}void lcd1602_init()//液晶显示初始化操作{P0=0x00;hc573_sg_le=0;//关闭HC573使数码管不显示hc573_bit_le=0;lcd_en=0;//为0,为实现高脉冲作准备lcd_write_cmd(0x38);//设置为5x7显示lcd_write_cmd(0x0c);// 打开显示-显示光标-光标闪烁lcd_write_cmd(0x6);//地址加一,光标右移,整屏显示不移动lcd_write_cmd(0x01);//清屏}/*--这个函数的作用是:将读到的8591中的数据换算为电压值的个位值,----并转换为对应的ASCII码,用以在液晶中显示*/unsigned char data1_convert(unsigned char dat_temp){unsigned char data1;data1=(unsigned char)(((float)dat_temp/255)*5); //换算为电压值的个位值data1=data1+48; //转换为对应的ASCII码,因为0对应ASCII码的48,以此类推return data1;}/*--这个函数的作用是:将读到的8591中的数据换算为电压值的小数点后第一位的值,----并转换为对应的ASCII码,用以以在液晶中显示*/unsigned char data0_convert(unsigned char dat_temp){unsigned char data0,data1;data1=(unsigned char)(((float)dat_temp/255)*5);//换算为电压值的个位值data0=(unsigned char)((((float)dat_temp/255)*5-data1)*10);//换算为为电压值的小--//--数点后第一位的那个值data0=data0+48;return data0;//转换为对应的ASCII码}void main(){unsigned char dat;//用于接收从8591中读到的数据lcd1602_init();rst=0;//关闭DS1302时钟芯片,避免引起干扰hc573_sg_le=0;hc573_bit_le=0;lcd_write_cmd(0x80);lcd_write_data('C');lcd_write_data('H');lcd_write_data('1');lcd_write_data(':');lcd_write_cmd(0x85);lcd_write_data('.');lcd_write_cmd(0x87);lcd_write_data('V');//上面的这些都是为了在1602中显示"CH1: : V"while(1){iic_start();iic_write(0x90);//对8591进行写操作iic_ack();iic_write(0x01);//设置为4路独立信号输入,并关闭通道自动加1,只用通道1iic_ack();iic_start();//重新开始,为读数据作准备iic_ack();iic_write(0x91);//对8591进行读操作iic_ack();dat=iic_read();//这还只是一个8位的数据(需进一步转换为实际电压值)iic_send_no_ack();iic_stop();lcd_write_cmd(0x84); //将要显示的字符显示在此地址处lcd_write_data(data1_convert(dat));//显示电压的整数部分lcd_write_cmd(0x86);//将要显示的字符显示在此地址处lcd_write_data(data0_convert(dat)); //显示电压的小数部分}}。
1602同时显示PCF8591采集的四路模拟量

1602同时显示PCF8591采集的四路模拟量//LCD1602显示PCF8591四路电压BEEP EQU P3.7;蜂鸣器K1EQU P1.4;K1键K2EQU P1.5;K2键K3EQU P1.6;K3键K4EQU P1.7;K4键SCL EQU P1.0;PCF8591时钟线SDA EQU P1.1;PCF8591数据线LCD_RS BIT P2.0;LCD数据/命令选择端LCD_RW BIT P2.1;LCD读/写选择端LCD_EN BIT P2.2;LCD使能信号BUSY BIT P0.7;忙检测线LCD_X EQU30H;LCD地址变量BUSY_CHECK BIT20H.0;忙标志位DATAPORT EQU P0;LCD数据端口AD_DATA EQU40H;A/D转换值存储单元首地址(用4个单元) DISSTART EQU45H;显示单元首地址(用3个单元)AD_TEMP EQU49H;AD转换值临时存放单元ORG0000HAJMP MAINORG0050HMAIN:MOV SP,#70HMOV P0,#0FFHMOV P2,#0FFHMOV A,#00HMOV AD_DATA,A;A/D转换值存储单元清零MOV AD_DATA+1,AMOV AD_DATA+2,AMOV AD_DATA+3,AACALL LCD_INIT;LCD初始化MOV B,#00HMOV DPTR,#INFO1;指针指到信息1ACALL W_STRING1MOV B,#00HMOV DPTR,#INFO2;指针指到信息2ACALL W_STRING2LOOP:MOV R2,#04H;进行四路转换ACALL PCF_AD;开始A/D转换MOV AD_TEMP,AD_DATA;显示通道0输入电压值ACALL TUNBCDMOV LCD_X,#02H;设置显示位置ACALL LCD_CONV1MOV AD_TEMP,AD_DATA+1;显示通道1输入电压值ACALL TUNBCDMOV LCD_X,#0BH;设置显示位置ACALL LCD_CONV1MOV AD_TEMP,AD_DATA+2;显示通道2输入电压值ACALL TUNBCDMOV LCD_X,#02H;设置显示位置ACALL LCD_CONV2MOV AD_TEMP,AD_DATA+3;显示通道3输入电压值ACALL TUNBCDMOV LCD_X,#0BH;设置显示位置ACALL LCD_CONV2MOV R1,AD_DATA;D/A转换ACALL PCF_DAAJMP LOOP;检查LCD忙状态;busy为1时,忙,等待。
PCF8591单片机AD和DA实验

普中科技
单片机开发仪视频教程
PCF8591的控制寄存器
D1、D0 D2 D5、D4
D6
AD通道选择00通道0,01通道1,10通道2,11 通道3
自动增益选择(有效位为1)
输入模式选择:00四路单数输入;01三路 差分输入;10单端与差分配合输入;11为 模拟输入有效
水落而石出者,山间之四时也。直译法:那太阳一出来,树林里的雾气散开,云雾聚拢,山谷就显得昏暗了,朝则自暗而明,暮则自明而暗,或暗或明,变化不一,这是山间早晚的景色。野花开放,有一股清幽的香味,好的树木枝叶繁茂,形成浓郁的绿荫。天高气爽,霜色洁白,泉水浅了,石底露出水
面,这是山中四季的景色。意译法:太阳升起,山林里雾气开始消散,烟云聚拢,山谷又开始显得昏暗,清晨自暗而明,薄暮又自明而暗,如此暗明变化的,就是山中的朝暮。春天野花绽开并散发出阵阵幽香,夏日佳树繁茂并形成一片浓荫,秋天风高气爽,霜色洁白,冬日水枯而石底上露,如此,就是
* 输入
: channel(转换通道)
* 输出
:无
************************************************************/
void Pcf8591SendByte(unsigned char channel)
{
I2cStart();
I2cSendByte(WRITEADDR);//发送写器件地址 I2cSendByte(0x40|channel);//发送控制寄存器
* 函数名 : Pcf8591DaConversion
* 函数功能 : PCF8591的输出端输出模拟量
* 输入
: value(转换的数值)
* 输出
51单片机基于pcf8591芯片的AD转换

int voltage;
initIIC();
uart_init();
cmg();
while(1)
{
voltage=read(0x43);//跟据芯片,这里可以有四种数据0x40 0x41 0x42 0x43 分别对应着四个通道
UART_Send_Byte('0'+voltage/51); //模拟电压转换
UART_Send_Byte('.');
UART_Send_Byte('0'+voltage/10);
UART_Send_Byte('\n');
Delay1ms(500);
write_byte(PCF8591+1); //把最后一位变成1,读
respons();
date=read_byte();
stop();
return date;
}
void main()
{
;
;
}
/**
* UART初始化
* 波特率:9600
*/
void uart_init(void) //串口初始化
{
TMOD = 0x21; // 定时器1工作在方式2(自动重装)
SCON = 0x50; // 10位uart,允许串行接受
delay();
}
uchar read_byte()
{
uchar i,k;
SCL=0;
delay();
SDA=1;
delay();
for(i=0;i<8;i++)
基于51单片机用PCF8591进行AD,DA转换用1602LCD显示的电流采样

基于51单片机用PCF8591进行AD,DA转换用1602LCD显示的电流采样福州大学至诚学院本科生课程设计题目: 可编程序控制器实训姓名: 学号:系别:专业:年级: 指导教师:目录1、PCF8591概述 .....................................................3 2、芯片介绍.........................................................3 3、PCF8591的A/D 转换...............................................4 4、A/D转换程序设计流程 .............................................5 5、1602LCD主要技术参数 .............................................7 6、Proteus仿真原理图 . (10)7、程序代码........................................................108、结语............................................................17 9、参考文献.. (17)21、PCF8591 概述PCF8591 是一种具有 I2C 总线接口的 8 位 A/D D/A 转换芯片,在与 CPU的信息传输过程中仅靠时钟线 SCL 和数据线 SDA 就可以实现。
I2C 总线是Philips (飞利浦)公司推出的串行总线,它与传统的通信方式相比具有读写方便,结构简单,可维护性好,易实现系统扩展,易实现模块化标准化设计,可靠性高等优点。
2、芯片介绍2.1内部结构及引脚功能描述PCF8591 为单一电源供电(2.5 6 V)典型值为 5 V,CMOS 工艺 PCF8591 有 4 路 8 位 A/D 输入,属逐次比较型,内含采样保持电路; 1 路 8 位 D/A 输出,内含有 DAC的数据寄存器 A/D D/A 的最大转换速率约为 11 kHz,但是转换的基准电源需由外部提供 PCF8591 的引脚功能如图1所示图1 PCF8591引脚功能2.2片内可编程功能设置在 PCF8591 内部的可编程功能控制字有两个,一个为地址选择字,另一个为转换控制字 PCF8591 采用典型的I2C总线接口的器件寻址方法,即总线地址由器件地址引脚地址和方向位组成 Philips (飞利浦)公司规定 A/D器件高四位地址为1001,低三位地址为引脚地址A0A1A2,由硬件电路决定,地址选择字格式具体描述如表2 所示因此 I2C 系统中最多可接 23=8 个具有总线接口的 A/D 器件地址的最后一位为方向位 R/W,当主控器对 A/D 器件进行读操作时为 1,进行写操作时为 0 总线。
PCF8591模数转换及1602LCD显示应用程序

#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define Delay4us() {_nop_();_nop_();_nop_();_nop_();}//引脚定义sbit LCD_RS=P2^0;sbit LCD_RW=P2^1;sbit LCD_EN=P2^2;//延时子程序void DelayMS(int ms) {uchar t;while(ms--) for(t=0;t<120;t++);}//LCD忙状态检测bit LCD_Busy_Check() {bit Result;LCD_RS=0;LCD_RW=1;LCD_EN=1; Delay4us(); Result=(bit)(P0 & 0x80);LCD_EN=0;return Result;}//写LCD命令void LCD_Write_Command(uchar cmd) {// while(LCD_Busy_Check());DelayMS(5);LCD_RS=0; LCD_RW=0;LCD_EN=0; _nop_();_nop_();P0=cmd;Delay4us();LCD_EN=1;Delay4us();LCD_EN=0;}//写LCD数据void LCD_Write_Data(uchar dat) {// while(LCD_Busy_Check()); //LCD是否忙?DelayMS(5);LCD_RS=1; LCD_RW=0; LCD_EN=0; P0=dat; Delay4us();LCD_EN=1;Delay4us();LCD_EN=0;}//LCD初始化void LCD_Initialise(){LCD_Write_Command(0x38);DelayMS(5); //设置16*2行显示,5*7点阵,8位数据接口LCD_Write_Command(0x0C);DelayMS(5); //开显示LCD_Write_Command(0x06);DelayMS(5); //地址指针加1,光标加1,整屏显示不移动LCD_Write_Command(0x01);DelayMS(5); //指针清零,显示清零}sbit SCL=P1^0;sbit SDA=P1^1;uchar Recv_Buffer[4]; //数据接收缓冲(每通道1字节)uint Voltage[]={'0','0','0'}; //数据分解为电压x.xxbit bdata IIC_ERROR; //设置I2C错误标志位uchar LCD_Line_1[]={"1- . V 2- . V"};uchar LCD_Line_2[]={"3- . V 4- . V"};void LCD_Set_Position(uchar pos) { //设置LCD显示位置LCD_Write_Command(pos|0x80);}void LCD_Display_A_Line(uchar Line_Addr,uchar s[]) { //显示一行uchar i;LCD_Set_Position(Line_Addr);for(i=0;i<16;i++); LCD_Write_Data(s[i]);}//将模数转换后的值分解存入缓冲void Convert_To_Voltage(uchar val) {uchar tmp;V oltage[2]=val/51+'0'; //最大值为255,对应5伏电压,分度为255/5=51,一位整数tmp=val%51*10;V oltage[1]=tmp/51+'0'; //第一位小数tmp=tmp%51+'0';V oltage[0]=tmp/51+'0'; //第二位小数}//启动I2C总线void IIC_Start() {SDA=1; SCL=1; Delay4us(); SDA=0; Delay4us(); SCL=0;}//停止I2C总线void IIC_Stop() {SDA=0; SCL=1; Delay4us(); SDA=1; Delay4us(); SCL=0;}//从机发送应答void Slave_Ark() {SDA=0; SCL=1; Delay4us(); SCL=0; SDA=1;}//从机发送非应答void Slave_NOArk() {SDA=1; SCL=1; Delay4us(); SCL=0; SDA=0;}//发送一个字节void IIC_SendByte(uchar wd) {uchar i;for(i=0;i<8;i++) //循环移入8位{SDA=(bit)(wd&0x80); _nop_();_nop_();SCL=1; Delay4us(); SCL=0; wd<<1;}Delay4us();SDA=1; SCL=1; Delay4us(); //释放总线并准备读取应答IIC_ERROR=SDA; SCL=0; Delay4us();}//接收一个字节uchar IIC_ReceiveByte() {uchar i, rd=0x00;for(i=0;i<8;i++) { //循环移入8位SCL=1; rd<<1; rd |= SDA; Delay4us(); SCL=0; Delay4us();}SCL=0; Delay4us();return rd;}void ADC_PCF8591(uchar CtrlByte) { //连续读入4路通道的转换结果并保存到Recv_Bufferuchar i;IIC_Start();IIC_SendByte(0x90);if(IIC_ERROR==1) return;//IIC_SendByte(CtrlByte);//if(IIC_ERROR==1) return;IIC_Start();IIC_SendByte(0x91);if(IIC_ERROR==1) return;IIC_ReceiveByte();Slave_Ark();for(i=0;i<4;i++) {Recv_Buffer[i++] = IIC_ReceiveByte();Slave_Ark();}Slave_NOArk();IIC_Stop();}//向PCF8591发送1字节,进行D/A转换void DAC_PCF8591(uchar CtrlByte,uchar dat) {IIC_Start(); Delay4us();IIC_SendByte(0x90);if(IIC_ERROR==1) return;IIC_SendByte(CtrlByte);if(IIC_ERROR==1) return;IIC_SendByte(dat);if(IIC_ERROR==1) return;IIC_Stop(); Delay4us(); Delay4us();}//主程序void main(){LCD_Initialise();while(1){ADC_PCF8591(0x04);Convert_To_V oltage(Recv_Buffer[0]); // 将4个转换通道的转换结果放入LCD 显示缓冲LCD_Line_1,LCD_Line_2LCD_Line_1[2]=V oltage[2];LCD_Line_1[4]=V oltage[1];LCD_Line_1[5]=V oltage[0];Convert_To_V oltage(Recv_Buffer[1]);LCD_Line_1[11]=V oltage[2];LCD_Line_1[13]=V oltage[1];LCD_Line_1[14]=V oltage[0];Convert_To_V oltage(Recv_Buffer[2]);LCD_Line_2[2]=V oltage[2];LCD_Line_2[4]=V oltage[1];LCD_Line_2[5]=V oltage[0];Convert_To_V oltage(Recv_Buffer[3]);LCD_Line_2[11]=V oltage[2];LCD_Line_2[13]=V oltage[1];LCD_Line_2[14]=V oltage[0];LCD_Display_A_Line(0x00,LCD_Line_1); //2行显示4通道的转换结果LCD_Display_A_Line(0x40,LCD_Line_2);DAC_PCF8591(0x40,Recv_Buffer[0]); //模拟量输出的转换结果,在proteus中看不到,只有在真实硬件中才能看到}}/*include<reg52.h>#include <intrins.h>#define uint unsigned int#define uchar unsigned charsbit CS=P1^0; //ADC0832引脚定义sbit CLK=P1^1;sbit DIO=P1^2;sbit lcd_rs=P2^0; //LCD1602引脚定义sbit lcd_rw=P2^1;sbit lcd_en=P2^2;void DelayMS(uint ms) { //延时子程序uint t;while(ms--) for(t=0;t<120;t++);}bit LCD_Busy_Check() { //LCD忙状态检测bit result;lcd_rs=0; lcd_rw=1; lcd_en=1;DelayMS(5);lcd_en=0;DelayMS(5);result=P0^7; //result=(bit)(P0&0x80);return result;}void write_com(uchar com){ //写命令//while(LCD_Busy_Check()); //LCD是否忙?lcd_rs=0; lcd_rw=0; P0=com;lcd_en=1; DelayMS(2);lcd_en=0;}void write_data(uchar date) { //写数据//while(LCD_Busy_Check()); //LCD是否忙?lcd_rs=1; lcd_rw=0; P0=date;lcd_en=1; DelayMS(2);lcd_en=0;}void lcd_disp(uchar *s) { //显示子函数while(*s>0) {write_data(*s);s++;}}void lcd_init() { //lcd初始化函数write_com(0x38);write_com(0x0c);write_com(0x06);write_com(0x01);}uchar Display_Buffer[]="0.000V"; //1位整数、3位小数的数字电压显示缓冲uchar Get_AD_Result() {uchar i, dat1=0, dat2=0; //起始控制位CS=0; CLK=0; DIO=1;_nop_();_nop_();CLK=1;_nop_();_nop_();CLK=0; //第一个下降沿之前,设DI=1/0,选择单端/差分(SGL/DIF)模式中的单端输入模式DIO=1;_nop_();_nop_();CLK=1;_nop_();_nop_();CLK=0;DIO=0;_nop_();_nop_(); //第二个下降沿之前,设DI=1/0,选择CH0/CH1 CLK=1;DIO=1;_nop_();_nop_();CLK=0;DIO=1;_nop_();_nop_(); //第三个下降沿之前,设DI=0for(i=0;i<8;i++) //第4-11,共8个下降沿读取数据(MSB->LSB){CLK=1;_nop_();_nop_();CLK=0;_nop_();_nop_();dat1=dat1<<1|DIO;}for(i=0;i<8;i++) { //第11-18,共8个下降沿读取数据(LSB->MSB)dat2=dat2 | ((uchar)(DIO)<<i);CLK=1;_nop_();_nop_();CLK=0;_nop_();_nop_();}CS=1;return (dat1==dat2) ? dat1 : 0; //如果两次读取的结果相同,则返回读取的结果,否则返回0}void main(){uchar i;uint d;lcd_init();DelayMS(3);write_com(0x80|0x00);lcd_disp("Current V oltage:");while(1) {d=Get_AD_Result()*5000.0/255;Display_Buffer[0]=d/1000+'0';Display_Buffer[2]=(d%1000)/100+'0';Display_Buffer[3]=d%1000%100/10+'0';Display_Buffer[4]=d%1000%100%10+'0';write_com(0x80|0x46); //设置第二行显示位置i=0;while (Display_Buffer[i] != '\0')write_data(Display_Buffer[i++]);}}*/。
单片机LCD1602显示AD转换值

目录1.硬件设计任务1.1设计题目 (2)1.2设计背景及发展 (2)1.3设计内容 (2)1.3.1设计内容 (2)1.3.2设计目的 (2)1.4 使用说明 (2)2.设计原理2.1基本原理 (3)3.设计步骤3.1硬件设计 (3)3.1.1 确定所用的硬件 (3)3.1.2 熟悉所用的硬件 (3)(1) 8051单片机(2) 74LS138(3) ADC0809(4) 8255A(5)1602LCD3.1.3 硬件框图 (9)3.1.4 最小系统图 (10)(1)连线说明(2)配套地址3.2 软件设计 (11)3.2.1 流程框图 (12)3.2.2 程序清单 (16)3.3 调试过程与结果 (21)3.3.1 调试过程 (21)3.3.2 调试结果 (21)4. 设计心得4.1 设计心得 (22)5. 参考文献5.1 参考文献出处 (22)1.硬件设计任务1.1设计题目LCD显示设计(显示A/D转换值)1.2设计背景液晶显示器,简称LCD(Liquid Crystal Display)。
世界上第一台液晶显示设备出现在20世纪70年代初,被称之为TN-LCD(扭曲向列)液晶显示器。
尽管是单色显示,它仍被推广到了电子表、计算器等领域。
80年代,STN-LCD(超扭曲向列)液晶显示器出现,同时TFT-LCD(薄膜晶体管)液晶显示器技术被研发出来,但液晶技术仍未成熟,难以普及。
80年代末90年代初,日本掌握了STN-LCD及TFT-LCD 生产技术,LCD工业开始高速发展。
LCD发展过程:1888~1968年为液晶材料性能和应用研究时期。
1973~1985年为TN-LCD获得广泛应用时期。
1985~1993年为STN-LCD推广应用时期。
1993~2000年是TFT-LCD大发展时期,这个时期TFT-LCD的性能已可以与CRT 媲美。
LCD发展大大扩展了显示器的应用范围,使个人使用移动型手持显示器成为可能,因此,2000年以后将进入LCD与CRT争夺显示器主流市场的时代。
基于51单片机的PCF8591芯片电压表设计

摘要
数字电压表简称 DVM,它是采用数字化测量技术设计的电压表。从 性能来看:数字电压表的发展从一九五二年美国 NLS 公司由四位电 子管数字电压表精度千分之一到现在已经出现 8 位数字电压表。参数 可测量直流电压、交流电压、电流、阻抗等。测量自动化程度不断提 高,可以和计算机配合显示、计算结果、然后打印出来。从发展过程 来看:数字电压表自 1952 年问世以来,已有 50 年多年的发展史,大 致经历了五代产品。第一代产品是 20 世纪 50 年代问世的电子管数字 电压表,第二代产品属于 20 世纪 60 年代出现的晶体管数字电压表, 第三带产品为 20 世纪 70 年代研制的中、小规模集成电路的数字电压 表。今年来,国内外相继推出有大规模集成电路(LSI)或超大规模 集成电路(VLSI)构成的数字电压表、智能数字电压表,分别属于 第四代、第五代产品。它们不仅开创了电子测量的先河,更以高准确 度、高可靠性、高分辨力、高性价比等优良特性而受到人民的青睐。
1.2 软件总体设计............................................................................. 10 第二章 硬件系统设计............................................................................. 11
2.1 硬件电路分析和设计报告......................................................... 11 2.1.1 单片机最小系统电路..................................................... 11 2.1.2 键盘电路......................................................................... 16 2.1.3 数码管显示电路............................................................. 16 2.1.4 外部电压采集部分电路.................................................17 2.1.5 PCF8591 芯片 AD 转换部分..........................................18
基于51单片机的8路电压采集与液晶显示

此程序分三部分,一是主程序,二是1602显示程序,三是ad08采样程序,附protues仿真图。
//**************************************************************** *********************************//**<程序名>:多路数字电压表采集//**<功能>:使用LCD1602显示被检测电压,精度为0.05V,范围是0~5V。
//**<版本说明>:这是第3版,使用LCD显示。
//**<作者>:xx//**<修改>:xx//**<完成时间>:2011年11月18日//**************************************************************** *********************************//*头文件及宏定义#include "includes.h"#include <at89x51.h>#define TIME0H 0x3C#define TIME0L 0xB0//#define abc P1//****************************全局变量******************************//************************************** *************************************unsigned char uc_Clock=0;//定时器0中断计数bit b_DATransform=0;//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>//把电压显示在LCD//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>void vShowVoltage(unsigned int uiNumber){unsigned char ucaNumber[3],ucCount;if(uiNumber>999)uiNumber=999;ucaNumber[0]=uiNumber/100;//把计算数字的每个位存入数组。
PCF8591AD及DA转换

PCF8591_writebyte(0x40); //D6=1:模拟输出使能,即DA使能
ack(); //等待从机应答响应 这里不用停止IIC,下面仍然是写模式; 数字量变为模拟量,及DA功能
PCF8591作为AD时的初始化流程
void init_pcf8591AD(void)
{
start(); //启动IIC
PCF8591_writebyte(0x90); //总线寻址,进入写模式
return temp; //返回一个0~255之间的AD结果
}
PCF8591作为DA时的初始化流程及DA转换
void init_pcf8591DA(void)
{
start(); //启动IIC
PCF8591_writebyte(0x90); //总线寻址,进入写模式
stop(); //停止IIC
delay(10);
}
读转换结果
unsigned char adc_pcf8591(void)
{
unsigned char temp;
start(); //启动IIC PCF8591_writebyte(0x91); //总线寻址,进入读模式 ack(); pcf8591_writebyte(0x91);
ack(); //等待从机应答响应
temp = PCF8591_readbyte(); //读一个字节
noack(); //主机向从机作出非应答响应,释放SDA
stop(); //停止IIC
}
PCF8591_writebyte(table[i]); //模拟电压从AOUT引脚(15号)输出
摘要本课程设计设计了一个基于51系列单片机控制数据采

摘要:本课程设计设计了一个基于51系列单片机控制的数据采集系统。
51单片机控制AD 转换器循环采集8路数据,并对所采集的数据进行处理。
处理好的数据再由单片机控制1602液晶显示器显示出来。
此外,单片机还控制八个按键实现了单独一路采集和显示功能。
单片机控制程序由C语言完成。
关键字:单片机;AD转换;液晶显示一、概述本课程设计涉及51系列单片机,AD模数转换器,液晶显示器等器件的运用,同时还设计了C语言在51单片机上的应用。
这些器件的综合运用对于深刻掌握51系列单片机原理和AD转换原理具有很大理论意义,同时本课程设计设计出的数据采集电路能满足简单的数据采集环境,具有一定的实用价值。
本课程设计设计了一个能够采集八路数据并进行实时显示的系统,它可以循环显示4路采集数据,也可以根据按键操作进行单路实时显示。
二、工作原理说明图1 工作原理框图工作原理:所要采集的八路数据由AD转化器的八路模拟量输入端输入,AD将八路模拟数据转换成数字量后送给主控单元51单片机,51单片机由C语言程序控制,将所得到的八路数字量处理后由1602液晶显示器显示出来。
同时单片机发出控制信号控制AD循环采集八路数据,控制液晶循环显示八路数据。
按键复制单独一路数据的采集与显示控制。
三、电路设计1.单片机与AD接口电路如图2所示,AD转换器的八路数字输出量OUT1-OUT8由单片机的P1口输入单片机,AD的三路地址输入A、B、C、端分别接单片机的P3.0、P3.1、P3.2。
P3.2、P3.1、P3.0循环输出000-111八个信号来控制AD循环采集转换八路模拟数据。
AD的START、EOC、OE接口分别接单片机的P3.7、P3.3、P3.6口,单片机的P3.7输出一个持续一定时间的脉冲给AD的START口,启动一次AD转换,待转换完毕后,AD的EOC口输出一个高电平,此高电平作为单片机的中断触发信号,中断过程中单片机输出一个高电平给AD的OE口允许AD输出数据给单片机。
PCF8591(AD-DA)芯片-51单片机程序

PCF8591(AD-DA)芯片-51单片机程序
注: PCF8591 是8 位AD-DA 芯片转换数据0---5 对应0--255 通信协议
IIC 模拟量输出值和电压的关系: 输出电压=(参考电压-基点电位)/255//以下
是源码如果在网页上显示格式错乱可以从这里下载:51hei/f/8591c.rar//12MHZ 晶
振#include #include #define uchar unsigned char#define uint unsigned int#include “IIC.h”//i2c库函数code uchar seg[]
={0x28,0x7e,0xa2,0x62,0x74,0x61,0x21,0x7a,0x20,0x60}; //数码管码表code uchar tab[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //数码管位选sbit bz=P3;//喇叭
位uchar outdata;//模拟量输出值sbit k1=P1 ; //模拟量输出者增加sbit k2=P1;//
模拟量输出者减少void delay(uint k) //延时子函数{while(k--);}void key1() //模拟
输出值增加{if(k1==0){delay(1000);if(k1==0)outdata++;}}void key2() //模拟输出
值减少{if(k2==0){delay(1000);if(k2==0)outdata--;}}tips:感谢大家的阅读,本文
由我司收集整编。
仅供参阅!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
福州大学至诚学院本科生课程设计题目:可编程序控制器实训姓名:学号:系别:专业:年级:指导教师:目录1、PCF8591概述 (3)2、芯片介绍 (3)3、PCF8591的A/D 转换 (4)4、A/D转换程序设计流程 (5)5、1602LCD主要技术参数 (7)6、Proteus仿真原理图 (10)7、程序代码 (10)8、结语 (17)9、参考文献 (17)1、PCF8591 概述PCF8591 是一种具有 I2C 总线接口的 8 位 A/D D/A 转换芯片,在与 CPU 的信息传输过程中仅靠时钟线 SCL 和数据线 SDA 就可以实现。
I2C 总线是Philips (飞利浦)公司推出的串行总线,它与传统的通信方式相比具有读写方便,结构简单,可维护性好,易实现系统扩展,易实现模块化标准化设计,可靠性高等优点。
2、芯片介绍2.1内部结构及引脚功能描述PCF8591 为单一电源供电(2.5 6 V)典型值为 5 V,CMOS 工艺 PCF8591 有 4 路 8 位 A/D 输入,属逐次比较型,内含采样保持电路; 1 路 8 位 D/A 输出,内含有 DAC的数据寄存器 A/D D/A 的最大转换速率约为 11 kHz,但是转换的基准电源需由外部提供 PCF8591 的引脚功能如图1所示图1 PCF8591引脚功能2.2片内可编程功能设置在 PCF8591 内部的可编程功能控制字有两个,一个为地址选择字,另一个为转换控制字 PCF8591 采用典型的I2C总线接口的器件寻址方法,即总线地址由器件地址引脚地址和方向位组成 Philips (飞利浦)公司规定 A/D器件高四位地址为 1001,低三位地址为引脚地址A0A1A2,由硬件电路决定,地址选择字格式具体描述如表 2 所示因此 I2C 系统中最多可接 2^3=8 个具有总线接口的A/D 器件地址的最后一位为方向位 R/W,当主控器对 A/D 器件进行读操作时为1,进行写操作时为 0 总线。
操作时,由器件地址引脚地址和方向位组成的从地址为主控器发送的第一字节。
图2 地址选择字格式描述D0:读写控制位,对转换器件进行读操作时为1 ,进行写操作时为0。
D1,D2,D3:引脚硬件地址设置位,由硬件电路设定该PCF8591的物理地址。
D7,D6,D5,D4:器件地址位固定为1001.PCF8591的转换控制字存放在控制寄存器中,用于实现器件的各种功能总线操作时为主控器发送的第二字节转换控制字的格式功能具体描述如图3所示图3 转换控制字格式描述D0,D1:通道选择位。
00 :通道 0; 01:通道1 ; 10:通道2; 11:通道3。
D2:自动增量允许位,为 1时,每对一个通道转换后自动切换到下一通道进行转换,为0 时不自动进行通道转换,可通过软件修改进行通道转换D3:特征位,固定位0。
D4,D5:模拟量输入方式选择位。
00:输入方式0 ,四路单端输入;01 :输入方式 1,三路差分输入;10 :输入方式2,二路单端输入,一路差分输入; 11:输入方式3 ,两路差分输入。
D6:模拟输出允许位,A/D 转换时设置为(地址选择字D0 位此时设置为1 ),D/A 转换时设置为 1(地址选择字位此时设置为)。
D7:特征位,固定为0。
3、PCF8591的A/D 转换PCF8591的A/D 转换为逐次比较型,在 A/D转换周期中借用 DAC及高增益比较器对 PCF8591进行写读操作(R/W)后便立即启动 A/D转换,并读出A/D 转换结果在每个应答信号的后沿触发转换周期,采样模拟电压并读出前一次转换后的结果。
A/D转换中,一旦 A/D采样周期被触发,所选择通道的采样电压便保存在采样,保持电路中,并转换成8 位二进制码(00四路单端输入)或二进制补码(01三鹿差分输入)存放在ADC数据寄存器中等待器件读出。
如果控制字节中自动增量选择位置 1,则一次A/D 转换完毕后自动选择下一通道。
读周期中读出的第一个字节为前一个周期的转换结果。
上电复位后读出的第一字节为80H。
PCF8591的A/D 转换亦使用的是I2C 总线的读方式操作完成的。
其数据操作格式如图 4所示。
图4 A/D转换数据操作格式其中data0~datan 为 A/D的转换结果,分别对应于前一个数据读取期间所采样的模拟电压。
A/D 转换结束后,先发送一个非应答信号位A 再发送结束信号位P。
灰底位由主机发出,白底位是由PCF8591 产生。
上电复位后控制字节状态为00H ,在 A/D转换时须设置控制字,即须在读操作之前进行控制字节的写入操作。
逻辑操作波形时序图如图5所示。
图5 A/D转换逻辑操作波形时序图4、A/D转换程序设计流程如下图6所示图65、1602LCD主要技术参数:显示容量:16×2个字符,芯片工作电压:4.5—5.5V,工作电流:2.0mA(5.0V),模块最佳工作电压:5.0V,字符尺寸:2.95×4.35(W×H)mm。
5.1引脚功能说明1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如图7图7引脚接口说明表第1脚:VSS为地电源。
第2脚:VDD接5V正电源。
第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极。
5.2 1602LCD的指令说明及时序图81602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:1为高电平、0为低电平)指令1:清显示,指令码01H,光标复位到地址00H 位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效。
指令4:显示开关控制。
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM 地址设置。
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
读操作时序写操作时序5.3 1602LCD的一般初始化(复位)过程延时15mS写指令38H(不检测忙信号)延时5mS写指令38H(不检测忙信号)延时5mS写指令38H(不检测忙信号)以后每次写指令、读/写数据操作均需要检测忙信号写指令38H:显示模式设置写指令08H:显示关闭写指令01H:显示清屏写指令06H:显示光标移动设置写指令0CH:显示开及光标设置6、仿真原理图如下所示7、C语言程序#include<reg52.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned int#define Delay4us(){_nop_();_nop_();_nop_();_nop_();}sbit LCD_RS=P2^6;sbit LCD_RW=P2^5;sbit LCD_EN=P2^7;sbit SCL=P2^0; //I2C时钟引脚sbit SDA=P2^1; //I2C数据输入输出引脚uchar Recv_Buffer[4]; //数据接收缓冲uint Voltage[]={'0','0','0','0'}; //数据分解为电压x.xx bit bdata IIC_ERROR; //I2C错误标志位uchar LCD_Line_1[]={" . V "};//延时void delay(int ms){uchar i;while(ms--) for(i=0;i<250;i++) Delay4us();}//LCD忙检测bit LCD_Busy_Check(){bit Result;LCD_RS=0;LCD_RW=1;LCD_EN=1;Delay4us();Result=(bit)(P0&0x80); LCD_EN=0;return Result;}//写指令void LCD_Write_Command(uchar cmd){while(LCD_Busy_Check());LCD_RS=0;LCD_RW=0;LCD_EN=0;_nop_();_nop_(); P0=cmd;Delay4us();LCD_EN=1;Delay4us();LCD_EN=0;}// 写数据void LCD_Write_Data(uchar dat){while(LCD_Busy_Check());LCD_RS=1;LCD_RW=0;LCD_EN=0;P0=dat;Delay4us(); LCD_EN=1;Delay4us();LCD_EN=0;}//初始化void LCD_Initialise(){LCD_Write_Command(0x38);delay(5);LCD_Write_Command(0x0c);delay(5);LCD_Write_Command(0x06);delay(5);LCD_Write_Command(0x01);delay(5);}//设置显示位置void LCD_Set_Position(uchar pos){LCD_Write_Command(pos|0x80);}//显示一行void LCD_Display_A_Line(uchar Line_Addr,uchar s[]){uchar i;LCD_Set_Position(Line_Addr);for(i=0;i<16;i++)LCD_Write_Data(s[i]);}// 将模数转换后得到的值分解存入缓存void Convert_To_Voltage(uchar val){uchar Tmp; //最大值为255,对应5V,255/5=51 Voltage[2]=val/51+'0'; //整数部分Tmp=val%51*10; // 第一位小数Voltage[1]=Tmp/51+'0';Tmp=Tmp%51*10;Voltage[0]=Tmp/51+'0';}//启动I2C总线void IIC_Start(){SDA=1;SCL=1;Delay4us();SDA=0;Delay4us();SCL=0;}//停止I2C总线void IIC_Stop(){SDA=0;SCL=1;Delay4us();SDA=1; Delay4us();SCL=0;}// 从机发送应答位void Slave_ACK(){SDA=0;SCL=1;Delay4us();SCL=0;SDA=1;}// 从机发送非应答位void Slave_NOACK(){SDA=1;SCL=1;Delay4us();SCL=0;SDA=0;}//发送一字节void IIC_SendByte(uchar wd){uchar i;for(i=0;i<8;i++) //循环移入8位{SDA=(bit)(wd&0x80);_nop_();_nop_();SCL=1;Delay4us();SCL=0;wd<<=1;}Delay4us();SDA=1; //释放总线并准备读取应答SCL=1;Delay4us();IIC_ERROR=SDA; //IIC_ERROR=1表示无应答SCL=0;Delay4us();}//接收一字节uchar IIC_ReceiveByte(){uchar i,rd=0x00;for(i=0;i<8;i++){SCL=1;rd<<=1;rd|=SDA;Delay4us();SCL=0;Delay4us();}SCL=0;Delay4us();return rd;}//连续读入4路通道的A/D转换结果并保存到Recv_Buffervoid ADC_PCF8591(uchar CtrlByte){uchar i;IIC_Start();IIC_SendByte(0x90); // 发送写地址if(IIC_ERROR==1)return;// IIC_SendByte(CtrlByte); //发送控制字节//if(IIC_ERROR==1)return;IIC_Start(); //重新发送开始命令IIC_SendByte(0x91); // 发送读地址if(IIC_ERROR==1)return;IIC_ReceiveByte(); //空读一次,调整读顺序Slave_ACK(); //收到一字节后发送一个应答位for(i=0;i<4;i++){Recv_Buffer[i++]=IIC_ReceiveByte();Slave_ACK(); //收到一个字节后发送一个应答位}Slave_NOACK();IIC_Stop(); //收到一个字节后发送一个非应答位}// 向 PCF8591发送1字节进行AD转换//主程序void main(){LCD_Initialise();{ADC_PCF8591(0x04);Convert_To_Voltage(Recv_Buffer[0]);LCD_Line_1[2]=Voltage[2];LCD_Line_1[4]=Voltage[1];LCD_Line_1[5]=Voltage[0];LCD_Display_A_Line(0x00, LCD_Line_1);}}8、结语在这次单片机课设中,通过自己动手查阅资料,不仅知道了芯片PCF8591和LCD1602工作原理、各引脚的功能等,还巩固了C语言程序的编写,对51单片机也有了更深的理解,丰富了很多课外知识,能熟练的运用Keil等软件。