摘 要
A/D转换器是模拟信号源和CPU之间联系的接口,它的任务是将连续变化的模拟信号转换为数字信号,以便计算机和数字系统进行处理、存储、控制和显示。在工业控制和数据采集及许多其他领域中,A/D转换是不可缺少的。能把输入模拟电压或电流变成与它成正比的数字量,即能把被控对象的各种模拟信息变成计算机可以识别的数字信息。实验中采集0~5V范围的电压信号(以电位器模拟被测信号),使用4位串行数码管显示0~5V数值,小数点保留三位,实现简易电压表功能。本次实验电路主要由AD转换器,AT89C52单片机组成,其中AD转换器器由ADC0809集成芯片组成。AD转换器要将时间和幅值都连续的模拟量,转换为时间、幅值都离散的数字量,一般要经过取样、保持和量化、编码几个过程。
关键词:AD转换 ADC0809 单片机
目录
1.实验内容与要求................................................... 1
1.1 实验内容.................................................... 1
1.2实验要求.................................................... 1
2.实验目的......................................................... 1
3 实验原理......................................................... 1
3.1 A/D转化原理图.............................................. 1
3.2 A/D转换芯片ADC0809简介.................................... 2
3.2.1 简介.................................................. 2
3.2.2 ADC0809内部逻辑结构................................... 2
3.2.3 ADC0809引脚结构....................................... 3
4 实验器材与仪器................................................... 4
5 实验步骤......................................................... 4
6 实验程序......................................................... 6
7 实验运行结果..................................................... 9
8 总结............................................................ 10
参考文献.......................................................... 11
1.实验内容与要求
1.1 实验内容
1、采用查询法或中断法编程进行A/D采集;
2、采集0~5V范围的电压信号(以电位器模拟被测信号),使用4位串行数码管显示0~5V数值,小数点保留三位,实现简易电压表功能。
1.2实验要求
1、用AD转换器完成模拟量到数字量的转换;
2、通过AD0808采集八路电压,用LCD液晶屏显示;
3、每屏显示四路电压值,时间间隔一秒。
2.实验目的
在理论学习的基础上,通过完成一个具有综合功能的小系统,使学生将课堂上学到的理论知识与实际应用结合起来,对电子电路、电子元器件等方面的知识进一步加深认识,同时在软件编程、调试、相关仪器设备的使用技能等方面得到较全面的锻炼和提高,为今后能够独立设计单片机应用系统的开发设计工作打下一定的基础。
本次实验是在前三次实验的基础上进行的,算是对本学期实验课的一次总结,其主要的实验目的有:
1、掌握A/D转换与单片机的接口方法
2、了解A/D芯片ADC0809转换性能及编程方法
3、通过实验了解单片机如何进行数据采集
3 实验原理
3.1 A/D转化原理图
本实验的电路连接如下图所示
图一(实验原理图)
3.2 A/D转换芯片ADC0809简介
3.2.1 简介
在工业控制和智能化仪表中,常由单片机进行实时控制及实时数据处理,被控制或测量对象的有关参量往往是连续变化的模拟量,如温度、速度、压力等,单片机要处理这些信号,先将模拟量转换成数字量,这一过程为模/数(A/D)转换。A/D转换器大致有三类:一是双积分A/D转换器,优点是精度高,抗干扰性好,价格便宜,但速度慢;二是逐次逼近A/D转换器,精度、速度、价格适中;三是并行A/D转换器,速度快,价格也昂贵。
本实验用的ADC0809属第二类,是八位A/D转换器。每采集一次一般需100μs,A/D转换结束后会自动产生EOC信号。本程序实例是以查询方式读入A/D转换结果。实验系统具有8路A/ D通道(模拟量输入端为IN0、IN1……IN7),地址分别为CFA0~ CFA7H,当有EOC信号,A/D转换器转换完毕,可以读入转换好的数据了。
3.2.2 ADC0809内部逻辑结构
由下图可知,ADC0809由一个8路模拟开关、一个地址锁存与译码器、一个A/D转换器和一个三态输出锁存器组成。多路开关可选通8个模拟通道,允许8路模拟量分时输入,共用A/D转换器进行转换。三态输出锁器用于锁存A/D转换完的数字量,当OE端为高电平时,才可以从三态输出锁存器取走转换完的数据。
图二(ADC0809结构)
3.2.3 ADC0809引脚结构
ADC0809各脚功能如下:
D7-D0:8位数字量输出引脚。
IN0-IN7:8位模拟量输入引脚。
VCC:+5V工作电压。
GND:地。
REF(+):参考电压正端。
REF(-):参考电压负端。
START:A/D转换启动信号输入端。
ALE:地址锁存允许信号输入端。
(以上两种信号用于启动A/D转换)
EOC:转换结束信号输出引脚,开始转换时为低电平,当转换结束时为高电平。
OE:输出允许控制端,用以打开三态数据输出锁存器。
CLK:时钟信号输入端(一般为500KHz)。
A、B、C:地址输入线。
ADC0809对输入模拟量要求:信号单极性,电压范围是0-5V,若信号太小,必须进行放大;输入的模拟量在转换过程中应该保持不变,如若模拟量变化太快,则需在输入前增加采样保持电路。ST为转换启动信号。当ST上跳沿时,所有内部寄存器清零;下跳沿时,开始进行A/D转换;在转换期间,ST应保持低电平。EOC为转换结束信号。当EOC为高电平时,表明转换结束;否则,表明正在进行A/D转换。OE为输出允许信号,用于控制三条输出锁存器向单片机输出转换得到的数据。OE=1,输出转换得到的数据;OE=0,输出数据线呈高阻状态。D7-D0为数字量输出线。
图三(引脚结构)
4 实验器材与仪器
1、PC机一台;
2、Keil uVision2 软件一套;
3、Proteus7.4 软件一套。
5 实验步骤
1、在Proteus软件中绘制单片机实验电路;
(1)注意连接电路线时不能使线缠在一;
(2)在选择芯片器材时一定要注意选择的型号是否与原理图上是相同的;
(3)在电阻和电容选择后要把其阻值和电容值改成与实验书上相同的大小。
2、在Keil C软件中编制汇编或C程序,软件调试;
(1)要新建工程文件,并选择好合适的芯片。
图四
(2)建立新的文件用来编写程序代码
图五
(3)写好代码后进行编译调试直至无误。
图六
3、在Proteus中加载实验程序,观察并记录实验结果;
4、分析实验结果并做出总结。
6 实验程序
#include <reg52.h>
//*******************引脚定义********************//
sbit dis_ab=P3^0;
sbit dis_clk=P3^1;
sbit CLK=P3^4;
sbit ST=P3^5;
sbit EOC=P3^6;
sbit OE=P3^7;
//*****************7SEG-LED段码表****************//
Unsigned char code LedTab[21]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,
0x7c,0x39,0x5e,0x79,0x71,0x76,0x73,0x3e,0x00, 0x40};
//************************************************//
unsigned char data num_1; //存储十六进制转化为两个单十六进制数的值
unsigned char data num_2;
unsigned char data num_3;
unsigned char data num_4;
void Delay(unsigned int x);
void DispClk(void);
void DisplaySerial(unsigned char x);
void ClearLed(unsigned char x);
void HexToDec(unsigned int x);
void main()
{
unsigned long num;
ST=0;
OE=0;
while(1)
{
ST=1; //发高脉冲启动采样信号
ST=0;
do{CLK=!CLK;}//提供采样时钟信号,直到采样结束为止
while(!EOC);
OE=1;
num=P1; //读取采样值
num=5000*num/255; //将0~#FFH采样值转化为0~5V数值(0~5000)
HexToDec(num); //将16进制数据,转换为10进制数据,以便于数码管显示
ClearLed(4);
DisplaySerial(num_4); //依次从高位到低为显示采样电压值
DisplaySerial(num_3);
DisplaySerial(num_2);
DisplaySerial(num_1);
Delay(30000); //采样延时间隔,决定采样频率
}
}
//********************延时子程序********************//
void Delay(unsigned int x)
{
unsigned int j;
for(j=0;j<x;j++){};
}
//********************************//
功能:串行模拟时钟
注意事项:用到delay.h中的延时子程序
形参:无
//********************************//
void DispClk(void)
{
dis_clk=1;Delay(1);
dis_clk=0;Delay(1);
}
//********************************//
功能:发送一个数字到串行LED上
形参:unsigned char x:0-20
//********************************//
void DisplaySerial(unsigned char x)
{
unsigned char i;
unsigned char num_serial=LedTab[x];
for(i=0;i<8;i++)
{
dis_ab=(bit)(num_serial&0x80);
num_serial<<=1;
DispClk();
}
}
//********************************//
功能:清串行LED显示
形参:unsigned char x = 需要清显示的LED数
//********************************//
void ClearLed(unsigned char x)
{
unsigned char i;
for(i=0;i<(x<<3);i++)
{
DispClk();
dis_ab=0;
}
}
void HexToDec(unsigned int x) //十六进制转十进制
{
num_1=x%10; //个位
x=x/10;
num_2=x%10; //十位
x=x/10;
num_3=x%10;
x=x/10;
num_4=x%10;
}
7 实验运行结果
通过改变POT-LIN原件滑片的位置即可调整输入的物理模拟量,可以发现输出的数字信号即观察LED的显示效果的不同。
通过实验,会发现:
1、当POT-LIN原件上的滑片位置位于参考图的上方时,LED会全亮;
2、当POT-LIN原件上的滑片位于最下方时,LED全暗;
3、当POT-LIN原件上的滑片位于上下之间的位置时,则会有其对应的LED显示效果。
部分运行显示效果如下图示:
图七(运行结果)
8 总结
通过实验,掌握ADC0809模数转换芯片与计算机的连接方法;了解ADC0809芯片的功能及编程方法;了解计算机如何进行数据采集。实验中,连接电路,利用代码控制实验电路,深对课本理论的理解。通过这几次在单片机课堂上所学知识的及前几次实验积累的经验,结合模拟电子技术和数字电子技术的知识,最终完成了这份报告。这也为自己今后进一步深化学习,积累了一定的宝贵经验,还对电子电路、电子元器件等方面的知识进一步加深认识,同时在软件编程、调试、相关仪器设备的使用技能等方面得到较全面的锻炼和提高,培养了我运用所学知识解决实际问题的能力。
参考文献
[1]郭天祥.新概念51单片机C语言教程[M].电子工业出版,2009.01
[2]赵亮,国锐.单片机C语言编程与实例[M].人民邮电出版社,2003.09
[3]倪志莲.单片机应用技术[M]北京理工大学出版社,2007.06
第二篇:单片机综合实验报告
一、实验内容:
设计一个数字时钟,显示范围为00:00:00~23:59:59。通过5个开关进行控制,其中开关K1用于切换时间设置(调节时钟)和时钟运行(正常运行)状态;开关K2用于切换修改时、分、秒数值;开关K3用于使相应数值加1调节;开关K4用于减1调节;开关K5用于设定闹钟,闹钟同样可以设定初值,并且设定好后到时间通过实验箱音频放出一段乐曲作为闹铃。
选做增加项目:还可增加秒表功能(精确到0.01s)或年月日设定功能。电路:(只连粗实线部分)
二、实验电路及功能说明
数码LED显示器电路(不需接线)
电子音响电路
按键说明:
三、实验程序流程图:
本实验设计了基于单片机的多功能数字钟的总体方案,对装置软、硬件的设计作了详细研究,并进行了相应的软件和硬件调试。该数字钟采用AT89C51单片机作为核心控制芯片,完成整点报时、显示、定时功能。整个系统分为几个小的电路,分别实现各自的功能。晶振电路,12MHZ晶振和两个30pF电容构成并连谐振接到X1和X2口。复位电路,在RST复位输入引脚上接一10uF电容至VCC端,下接一个51K电阻到地。控制电路,4个按键控制,进行调时,定时,复位操作。显示电路,用6位7段数码管进行时,分,秒的显示。 装置中软件设计部分包括一个主程序、四个模块程序和二个子程序,各自执行自己的功能,完成定时,调时等设操作。本文从整体到部分详细介绍了数字钟的设计,在比较重要的部分进行了详细的论述,并且给出了程序框图及说明。
软件程序整个流程图如下:
四、实验结果分析
定时程序设计:
单片机的定时功能也是通过计数器的计数来实现的,此时的计数脉冲来自单片机的内部,即每个机器周期产生一个计数脉冲,也就是每经过1个机器周期的时间,计数器加1。如果MCS-51采用的12MHz晶体,则计数频率为1MHz,即每过1us的时间计数器加1。这样可以根据计数值计算出定时时间,也可以根据定时时间的要求计算出计数器的初值。MCS-51单片机的定时器/计数器具有4种工作方式,其控制字均在相应的特殊功能寄存器中,通过对特殊功能寄存器的编程,可以方便的选择定时器/计数器两种工作模式和4种工作方式。
定时器/计数器工作在方式0时,为13位的计数器,由TLX(X=0、1)的低5位和THX的高8位所构成。TLX低5位溢出则向THX进位,THX计数溢出则置位TCON中的溢出标志位TFX.
当定时器/计数器工作于方式1,为16位的计数器。本设计师单片机多功能定时器,所以MCS-51内部的定时器/计数器被选定为定时器工作模式,计数输入信号是内部时钟脉冲,每个机器周期产生一个脉冲使计数器增1。
实时时钟实现的基本方法:
时钟的最小计时单位是秒,但使用定时器的方式1,最大的定时时间也只能达到131ms。我们可把定时器的定时时间定为50ms。这样,计数溢出20次即可得到时钟的最小计时单位:秒。而计数20次可以用软件实现。
秒计时是采用中断方式进行溢出次数的累积,计满20次,即得到秒计时。从秒到分,从分到时是通过软件累加并进行比较的方法来实现的。要求每满1秒,则“秒”单元中的内容加1;“秒”单元满60,则“分”单元中的内容加1;“分”单元满60,则“时”单元中的内容加1;“时”单元满24,则将时、分、秒的内容全部清零。
实时时钟程序设计步骤:
(1)选择工作方式,计算初值;
(2)采用中断方式进行溢出次数累计;
(3)从秒——分——时的计时是通过累加和数值比较实现的;
(4)时钟显示缓冲区:时钟时间在方位数码管上进行显示,为此在内部RAM中要设置显示缓冲
区,共6个地址单元。显示缓冲区从左到右依次存放时、分、秒数值;
(5)主程序:主要进行定时器/计数器的初始化编程,然后反复调用显示子程序的方法等待中断
的到来;
(6)中断服务程序:进行计时操作;
(7)加1子程序:用于完成对时、分、秒的加操作,中断服务程序在秒、分、时加1时共有三种
条调用加1子程序,包括三项内容:合字、加1并进行十进制调整、分字。
程序说明:
在整个系统中,在单片机的30H、31H和32H中存储当前时间的小时、分钟和秒。由于要用数码管显示当前的时间,必须用到分字和合字,因此在33H、34H、35H、36H、37H和38H中存储当前时间的时十位、时个位、分十位、分个位、秒十位和秒个位,方便显示。
本设计有由四个轻触按键组成的小键盘,这些按键可以任意改变当前的状态。按功能移位键一次,表示当前要校对小时的十位;按第二次,表示当前校对的是小时的个位;按第三次,则表示校对的是分钟的十位;第四次,表示的校对的是分钟的个位。按下数字“+” 键和数字“-”键可在当前校对的数字上相应加上1或者减去1。
本设计采用查表方式,在程序里预先存储两个表格,即日常作息时间表和考试时间表,可以通过手动按键来选择所要执行的时间表。并且用红、绿发光二极管来区别当前所执行的时间表。系统开机后,按功能移位键就可以调整当前的时间,整个系统操作简单,功能明确。
显示数据时,先把要显示的数据送到数据缓冲区SBUF中,再从SBUF中显示。串行口缓冲寄存器SBUF器是可直接寻址的专用寄存器。在物理上,它对应着两个寄存器,一个发送寄存器,一个接收寄存器。CPU写SBUF,就是修改发送寄存器;读SBUF,就是读接收寄存器。接收器是双缓冲的,以避免在接收下一帧数据之前,CPU未能及时响应接收器的中断,没有把上一帧数据读走,而产生两帧数据重叠的问题。对于发送器,为了保持最大的传输速率,一般不需要双缓冲,因为发送时CPU是主动的,不会产生写重叠的问题。
五、心得体会
通过本次多功能数字钟设计实验,真正的感受到了理论联系实际的重要性,以及这之间莫大区别,到最后看着自己的结果心里还是感到很欣慰的。
首先摆在我们面前的是要先弄懂所要设计实验的原理,于是最开始我在网上查找了大量的相关的资料,再结合课本的内容以及充分利用了网络资源和在图书馆借了相关的书籍资料,在仔细分析了本次实验所要达到的目的之后,我初步确定了思路。接下来的是进一步的分析其原理, 最后则编写出本次实验的程序。
在这次多功能数字钟设计实验过程中,我留下了很深的印象。由于以前都没有接触过,开始编写程序时很费力,但到后来就好了。在每次的实验中,遇到问题,最好的办法就是问别人,因为每个人掌握情况不一样,不可能做到处处都懂,发挥群众的力量,复杂的事情就会变得很简单。这一点我深有体会,在很多时候,我遇到的困难或许别人之前就已遇到,向他们请教远比自己在那冥思苦想来得快。
经过这些天的学习我深刻的体会到实际与理论有很大的区别。在我们学习的过程中不仅考验了我们对知识的吸收和掌握,而且也考验了我们的细心和耐心。特别是在编写程序过程中,我深有体会。所以,这次的实验不仅仅学习了程序的编写,还掌握了Proteus的一些功能,同时还提高了我们的专业素质。
总之,进过两次的实验心得体会,我总结了以下几条:首先,多动手写程序、调试,只有自己亲自动手编写了,才会让你印象深刻,收益更大。其次, 善于向别人学习,在你解决一个问题后,你可能会发现别人有更简便的方法解决,这时就是你向别人学习的时候。
六、程序清单
#include"reg51.h" //晶振为6MHZ
#include"absacc.h"
#define uchar unsigned char
#define uint unsigned int
#define DATA XBYTE[0XFFDC] //段选
#define SEL XBYTE[0XFFDD] //位选
sbit P1_0 = P1^0;
sbit P1_1 = P1^1;
sbit P1_2 = P1^2;
sbit Speak = P1^3;
uchar code table[2][13]={{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0xf7},
{0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf,0xf7}};
int count=0; //定时器计数,以记到1S
uchar sec=0; //秒
uchar hou=0; //小时
uchar min=0; //分
uchar flag=0; //显示时间还是闹钟时间,为0时显示时间
uchar al_clk1=11; //显示闹钟小时
uchar al_clk2=11; //显示闹钟分
uchar al_clk3=0; //显示闹钟秒
uchar disp1; // 显示时间或者闹钟时间
uchar disp2;
uchar disp3;
uchar dot_sel=0; //小数点选择标准位
uchar dot_hou; //小时的小数点显示
uchar dot_min; //分钟的小数点显示
uchar clk_f=0; //闹钟标志位
void init()
{
TMOD = 0x02; //定时器0,方式2自动重装
TH0 = 0x06;
TL0 = 0x06;
EA = 1;
ET0 = 1;
TR0 = 1;
IT0 = 1; //外部中断0边沿触发
EX0 = 1; //外部中断0允许
IT1 = 1; //外部中断1边沿触发
EX1 = 1; //外部中断1允许
}
void Delay_1ms(uint i) //延时n*ms
{
uchar x,j;
for(j=0;j
for(x=0;x<=148;x++);
}
void dot_choice() //选择小数点显示的位置
{
if(!P1_1)
{
Delay_1ms(25);
if(!P1_1)
{
dot_sel = ~dot_sel;
if(dot_sel)
{
dot_hou=1;
dot_min=0;
}
else
{
dot_hou=0;
dot_min=1;
}
}
}
}
void al_clk_seting() //闹钟设定
{
if(clk_f)
{
if((al_clk1==hou)&(al_clk2==min))
{
Speak = ~Speak;
Delay_1ms(38);
}
}
}
void display() //显示程序
{
if(!P1_0)
{
Delay_1ms(19); //闹钟和时间切换
if(!P1_0) flag = ~flag;
}
if(flag) //显示时间或者闹钟时间
{
disp1 = al_clk1;
disp2 = al_clk2;
disp3 = al_clk3;
}
else
{
disp1 = hou;
disp2 = min;
disp3 = sec;
}
if(!P1_2)
{
Delay_1ms(25);
if(!P1_2)
{
dot_hou=0;
dot_min=0;
clk_f = !clk_f; //clk_f为1是闹钟为设定状态。
}
}
dot_choice(); //选择小数点显示的位置
SEL=0x80;
DATA=table[0][disp1/10] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x40;
DATA=table[dot_hou][disp1%10] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x20; //显示-
DATA=table[0][11] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x10;
DATA=table[0][disp2/10] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x08;
DATA=table[dot_min][disp2%10] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x04; //显示-
DATA=table[0][11] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x02;
DATA=table[0][disp3/10] ;
Delay_1ms(1);
DATA=table[0][10] ;
SEL=0x01;
DATA=table[clk_f][disp3%10] ; //clk_f为1是闹钟设定最后一位小数点显示
Delay_1ms(1);
DATA=table[0][10] ;
}
void time() //时间计数部分
{
if(sec==60)
{
min++;
sec=0;
if(min==60)
{
hou++;
min=0;
if(hou==24)
hou=0;
}
}
}
void main() //主函数
{
init();
while(1)
{
display(); //显示
time(); //时钟
al_clk_seting(); //闹钟设定
}
}
void timer_0() interrupt 1 //定时器0时钟计数单元
{
count++;
if(count==2000)
{
sec++;
count=0;
}
}
void inter_ex_0() interrupt 0 //外部中断0进行闹钟或者时间的加1
{
if(flag&dot_sel) al_clk1++;
if(flag&(~dot_sel)) al_clk2++;
if((~flag)&dot_sel) hou++;
if((~flag)&(~dot_sel)) min++;
if(min == 60) min = 0;
if(hou == 24) hou = 0;
if(al_clk2 == 60) al_clk2 = 0;
if(al_clk1 == 24) al_clk1 = 0;
}
void inter_ex_1() interrupt 2 //外部中断1进行闹钟或者时间的减1
{
if(flag&dot_sel)
{
if(al_clk1 == 0) al_clk1 =24;
al_clk1--;
}
if(flag&(~dot_sel))
{
if(al_clk2 == 0) al_clk2 =60;
al_clk2--;
}
if((~flag)&(~dot_sel))
{
if(min == 0) min = 60;
min--;
}
if((~flag)&dot_sel)
{
if(hou == 0) hou = 24;
hou--;
}
}