51单片机课程设计AD转换.docx
- 文档编号:23694241
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:22
- 大小:289.69KB
51单片机课程设计AD转换.docx
《51单片机课程设计AD转换.docx》由会员分享,可在线阅读,更多相关《51单片机课程设计AD转换.docx(22页珍藏版)》请在冰豆网上搜索。
51单片机课程设计AD转换
51-单片机课程设计
题 目:
用PCF8591P芯片对电位器上的电压进行AD采样,将采到的数据用1602LCD进行显示。
姓名:
学 号:
学 院:
专业:
指导教师:
目 录
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)典型值为5V,CMOS 工艺PCF8591有4路8位A/D输入,属逐次比较型,内含采样保持电路;1路8 位 D/A 输出,内含有DAC的数据寄存器A/DD/A的最大转换速率约为11kHz,但是转换的基准电源需由外部提供PCF8591的引脚功能如图1所示
图1PCF8591引脚功能
2。
2片内可编程功能设置
在PCF8591 内部的可编程功能控制字有两个,一个为地址选择字,另一个为转换控制字PCF8591采用典型的I2C总线接口的器件寻址方法,即总线地址由器件地址引脚地址和方向位组成 Philips(飞利浦)公司规定A/D器件高四位地址为1001,低三位地址为引脚地址A0A1A2,由硬件电路决定,地址选择字格式具体描述如表2所示因此I2C 系统中最多可接23=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进行写读操作后便立即启动A/D转换,并读出A/D转换结果 在每个应答信号的后沿触发 转换周期,采样模拟电压并读出前一次转换后的结果。
A/D转换中,一旦 A/D采样周期被触发,所选择通道的采样电压便保存在采样,保持电路中,并转换成8位二进制码(单端输入)或二进制补码(差分输入)存放在ADC数据寄存器中等待器件读出。
如果控制字节中自动增量选择位置1,则一次A/D转换完毕后自动选择下一通道。
读周期中读出的第一个字节为前一个周期的转换结果。
上电复位后读出的第一字节为80H。
PCF8591的A/D转换亦使用的是I2C总线的读方式操作完成的。
其数据操作格式如图4所示。
图4A/D转换数据操作格式
其中data0~datan为A/D的转换结果,分别对应于前一个数据读取期间所采样的模拟电压.A/D 转换结束后,先发送一个非应答信号位A再发送结束信号位P.灰底位由主机发出,白底位是由PCF8591产生。
上电复位后控制字节状态为00H,在A/D转换时须设置控制字,即须在读操作之前进行控制字节的写入操作。
逻辑操作波形时序图如图5所示。
图5A/D转换逻辑操作波形时序图
4、A/D转换程序设计流程如下图6所示
图6
5、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
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极
图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的指令说明及时序
1602液晶模块内部的控制器共有11条控制指令,如图8
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
11
从CGRAM或DDRAM读数
1
1
读出的数据内容
图8
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的.(说明:
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。
31602LCD的一般初始化(复位)过程
延时15mS
写指令38H(不检测忙信号)
延时5mS
写指令38H(不检测忙信号)
延时5mS
写指令38H(不检测忙信号)
以后每次写指令、读/写数据操作均需要检测忙信号
写指令38H:
显示模式设置
写指令08H:
显示关闭
写指令01H:
显示清屏
写指令06H:
显示光标移动设置
写指令0CH:
显示开及光标设置
6、仿真原理图如下所示
7、C语言程序
#include #include h> #define uchar unsigned char #define uintunsigned int #defineDelay4us(){_nop_();_nop_();_nop_();_nop_();} sbitLCD_RS=P2^6; sbitLCD_RW=P2^5; sbitLCD_EN=P2^7; sbitSCL=P2^0; //I2C时钟引脚 sbitSDA=P2^1; //I2C数据输入输出引脚 ucharRecv_Buffer[4]; //数据接收缓冲 uintVoltage[]={'0','0','0','0'}; //数据分解为电压x。 xx bitbdataIIC_ERROR; //I2C错误标志位 ucharLCD_Line_1[]={” 。 V "}; //延时 voiddelay(intms) { uchari; while(ms--)for(i=0;i<250;i++) Delay4us(); } //LCD忙检测 bit LCD_Busy_Check() { bitResult; LCD_RS=0;LCD_RW=1; LCD_EN=1;Delay4us();Result=(bit)(P0&0x80); LCD_EN=0; return Result; } //写指令 voidLCD_Write_Command(ucharcmd) { 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; } //写数据 voidLCD_Write_Data(uchardat) { while(LCD_Busy_Check()); LCD_RS=1;LCD_RW=0;LCD_EN=0;P0=dat;Delay4us(); LCD_EN=1;Delay4us();LCD_EN=0; } //初始化 voidLCD_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); } //设置显示位置 voidLCD_Set_Position(ucharpos) { LCD_Write_Command(pos|0x80); } //显示一行 voidLCD_Display_A_Line(ucharLine_Addr,uchars[]) { uchari; LCD_Set_Position(Line_Addr); for(i=0;i<16;i++)LCD_Write_Data(s[i]); } // 将模数转换后得到的值分解存入缓存 voidConvert_To_Voltage(ucharval) { ucharTmp; //最大值为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’; } /********************************************************** 函数名称: iic_start() 函数功能: 启动I2C总线子程序 时钟保持高,数据线从高到低一次跳变,I2C通信开始 **********************************************************/ voidiic_start(void) { SDA= 1; SCL =1; Delay4us();//延时5us SDA=0; Delay4us(); SCL =0; } /********************************************************** 函数名称: iic_stop() 函数功能: 停止I2C总线数据传送子程序 时钟保持高,数据线从低到高一次跳变,I2C通信停止 **********************************************************/ voidiic_stop(void) { SDA=0; SCL=1; Delay4us(); SDA=1; Delay4us(); SCL= 0; } /********************************************************** 函数名称: iicInit_() 函数功能: 初始化I2C总线子程序 **********************************************************/ voidiicInit(void) { SCL=0; iic_stop(); } /********************************************************** 函数名称: slave_ACK 函数功能: 从机发送应答位子程序 **********************************************************/ voidslave_ACK(void) { SDA=0; SCL= 1; Delay4us(); SCL= 0; SDA= 1; } /********************************************************** 函数名称: slave_NOACK 函数功能: 从机发送非应答位子程序,迫使数据传输过程结束 **********************************************************/ voidslave_NOACK(void) { SDA= 1; SCL= 1; Delay4us(); SDA=0; SCL=0; SDA =0; } /********************************************************** 函数名称: check_ACK 函数功能: 主机应答位检查子程序,迫使数据传输过程结束 **********************************************************/ voidcheck_ACK(void) { SDA=1;//置成输入 SCL=1; F0=0; Delay4us(); if(SDA==1) //若SDA=1表明非应答 F0=1; //置位非应答标志F0 SCL= 0; } /********************************************************** 函数名称: IICSendByte 入口参数: indata 函数功能: 发送一个字节 **********************************************************/ voidIICSendByte(unsignedcharindata) { unsignedcharn=8;//发送一字节数据,共八bit while (n--) { SDA=(bit)(indata&0x80); SCL=1; Delay4us(); SCL=0; indata=indata<〈 1;//数据左移一位 } } /********************************************************** 函数名称: IICreceiveByte 返回接收的数据tdata 函数功能: 接收一字节子程序 **********************************************************/ unsigned charIICreceiveByte(void) { unsignedcharn =8;//读取一字节数据,共八bit unsignedchartdata=0; while(n-—) { SDA=1; SCL =1; tdata= tdata 〈<1;//左移一位 if(SDA==1) tdata =tdata| 0x01; //若接收到的位为1,则数据的最后一位置1 else tdata= tdata &0xfe; //否则数据的最后一位置0 SCL=0; } return (tdata); } /********************************************************** 函数名称: ADC_PCF8591 函数功能: A/D转换,结果存入receivebuf **********************************************************/ void ADC_PCF8591(unsignedcharcontrolbyte) { unsignedchari=0; iic_start(); IICSendByte(0x90);//控制字0x90 check_ACK(); IICSendByte(controlbyte);//通道控制字 check_ACK(); iic_start(); //重新发送开始命令 IICSendByte(0x91);//控制字0x91 check_ACK(); IICreceiveByte();//空读一次 slave_ACK();//收到一个字节后发送一个应答位 while (i〈 3) //采集0,1,2通道 { Recv_Buffer[i++]=IICreceiveByte(); slave_ACK(); } Recv_Buffer[3] =IICreceiveByte();//采集第3通道 slave_NOACK();//收到最后一个字节后发送一个非应答位 iic_stop(); } //主程序 voidmain() { LCD_Initialise(); while (1) { 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等软件。 期间遇到过LCD显示数据会抖动的问题,检查了相关的IIC总线程序,延长了延时程序,修改了LCD查忙时程序与AD转换程序中的控制字写入检查模块,在主程序中增加了一个模块: 若控制字写入有问题则重新启动IIC总线重新开始转换电压与数据传送.问题解决! 9、参考文献 单片机原理及应用(c语言版)周国运
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 51 单片机 课程设计 AD 转换