找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6691|回复: 1
打印 上一主题 下一主题
收起左侧

用lcd1602和adc0808设计的数字电压表

[复制链接]
跳转到指定楼层
楼主
ID:317943 发表于 2018-6-4 12:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  • 点名,复习
  • ADC0832的引脚及其功能,以及与单片机的硬件连接
引言:
数字电压表的基本工作原理是利用A/D转换电路将待测的模拟信号转换成数字信号,通过相应换算后将测试结果以数字形式显示出来的一种电压表。较之于一般的模拟电压表,数字电压表具有精度高、测量准确、读数直观、使用方便等优点。数字电压表的核心部件是A/D转换器,由于各种不同的A/D转换原理构成了各种不同类型的DVM。一般说来,A/D转换的方式可分为两类:积分式和逐次逼近式。
积分式A/D转换器是先用积分器将输入的模拟电压转换成时间或频率,再将其数字化。根据转化的中间量不同,它又分为U-T(电压-时间)式和U-F(电压-频率)式两种。
逐次逼近式A/D转换器分为比较式和斜坡电压式,根据不同的工作原理,比较式又分为逐次比较式及零平衡式等。斜坡电压式又分为线性斜坡式和阶梯斜坡式两种。
在高精度数字电压表中,常采用由积分式和比较式相结合起来的复合式A/D转换器。本设计以AT89C51单片机为核心,以逐次比较型A/D转换器ADC0808、液晶显示器LCD1602为主体,构造了一款简易的数字电压表,能够测量1路0~5V直流电压,最小分辨率0.02V。
  • 新课讲授
6.2基于LCD1602和ADC0808设计的数字电压表
逐次逼近型A/D转换器属于直接型A/D转换器,它能把输入的模拟电压直接转换为输出的数字代码,而不需要经过中间变量。主要由比较器、环形分配器、控制门、寄存器与D/A转换器组成。
6.2.1 ADC0808简介
1、主要技术指标和特性
(1)分辨率: 8位。
(2)总的不可调误差: ADC0808为±LSB,ADC 0809为±1LSB。
(3)转换时间: 取决于芯片时钟频率,如CLK=500kHz时,TCONV=128μs。
(4)单一电源: +5V。
(5)模拟输入电压范围: 单极性0~5V;双极性±5V,±10V(需外加一定电路)。
(6)具有可控三态输出缓存器。
(7)启动转换控制为脉冲式(正脉冲),上升沿使所有内部寄存器清零,下降沿使A/D转换开始。
(8)使用时不需进行零点和满刻度调节。
2、ADC0808引脚功能
                         图6-2-1 ADC0808引脚图
(1)IN0~IN7——8路模拟输入,通过3根地址译码线ADDA、ADDB、ADDC来选通一路。
(2)D7~D0——A/D转换后的数据输出端,为三态可控输出,故可直接和微处理器数据线连接。8位排列顺序是D7为最高位,D0为最低位。
(3)ADDA、ADDB、ADDC——模拟通道选择地址信号,ADDA为低位,ADDC为高位。地址信号与选中通道对应关系如表11.3所示。
(4)VR(+)、VR(-)——正、负参考电压输入端,用于提供片内DAC电阻网络的基准电压。在单极性输入时,VR(+)=5V,VR(-)=0V;双极性输入时,VR(+)、VR(-)分别接正、负极性的参考电压。
表6-1-1  地址信号与选中通道的关系
地    址
选中通道
ADDC
ADDB
ADDA
0
0
0
0
1
1
1
1
0
0
1
1
0
0
1
1
0
1
0
1
0
1
0
1
IN0
IN1
IN2
IN3
IN4
IN5
IN6
IN7

(5)ALE——地址锁存允许信号,高电平有效。当此信号有效时,A、B、C三位地址信号被锁存,译码选通对应模拟通道。在使用时,该信号常和START信号连在一起,以便同时锁存通道地址和启动A/D转换。
(6)START——A/D转换启动信号,正脉冲有效。加于该端的脉冲的上升沿使逐次逼近寄存器清零,下降沿开始A/D转换。如正在进行转换时又接到新的启动脉冲,则原来的转换进程被中止,重新从头开始转换。
(7)EOC——转换结束信号,高电平有效。该信号在A/D转换过程中为低电平,其余时间为高电平。该信号可作为被CPU查询的状态信号,也可作为对CPU的中断请求信号。在需要对某个模拟量不断采样、转换的情况下,EOC也可作为启动信号反馈接到START端,但在刚加电时需由外电路第一次启动。
(8)OE——输出允许信号,高电平有效。当微处理器送出该信号时,ADC0808/0809的输出三态门被打开,使转换结果通过数据总线被读走。在中断工作方式下,该信号往往是CPU发出的中断请求响应信号。
3、ADC0808内部结构图
逐次逼近型A/D转换器ADC0808由八路模拟开关、地址锁存与译码器、比较器、D/A转换器、寄存器、控制电路和三态输出锁存器等组成。其内部结构如图4所示。

图6-2-2  ADC0808内部结构

4、工作时序与使用说明

                      图6-2-3  ADC0808工作时序

ADC 0808/0809的工作时序如图11.21所示。当通道选择地址有效时,ALE信号一出现,地址便马上被锁存,这时转换启动信号紧随ALE之后(或与ALE同时)出现。START的上升沿将逐次逼近寄存器SAR复位,在该上升沿之后的2μs加8个时钟周期内(不定),EOC信号将变低电平,以指示转换操作正在进行中,直到转换完成后EOC再变高电平。微处理器收到变为高电平的EOC信号后,便立即送出OE信号,打开三态门,读取转换结果。
6.2.2 系统硬件设计
从以上分析可知。ADC0808有8个模拟通道,本文的模拟量从0通道输入,由ADC0808的模拟通道地址表可知,电路中应当把ADDC、ADDB、ADDA三个引脚全部接地。
根据ADC0808的工作时序图可知,START引脚在一个高电平后启动A/D转换,当EOC引脚出现一个低电平时转换结束,然后由OE引脚控制,从并行输出端读取一个字节的转换结果。转换后的结果为0x00-0xFF,转换过程中芯片所需的时钟信号由单片机定时器中断子程序提供。具体硬件结构图如图6-2-4所示:
图6-2-4 系统硬件连接图
6.2.3 系统软件设计
根据需要,可将系统软件按照功能划分为4个模块,分别是主程序模块、A/D转换模块、液晶显示模块、中断服务程序模块(改变显示的小数点位置)。编写系统软件时,可首先编写各模块的底层驱动程序,而后是系统联机调试,最后编写上层主程序。
1、  主程序设计
主程序主要负责初始化工作:设置定时器、寄存器的初值,启动A/D转换,读取转换结果,处理量程转换响应,控制液晶实时显示等,其流程图如图6-2-5所示。

图6-2-5主程序流程图

2、A/D转换程序

图6-2-6 A/D转换程序流程图

A/D转换程序的功能是采集数据,在整个系统设计中占有很高的地位。当系统设置好后,单片机扫描转换结束管脚P1.7的输入电平状态,当输入为高电平则转换完成,将转换的数值转换并显示输出。若输入为低电平,则继续扫描。程序流程图如图6-2-6所示。
      程序如下:
#include<reg52.h>
#include <intrins.h>
unsigned long dat_adc0808;
uint adc0808_init()      // AD初始化
{
  START=0;
  OE=0;
  START=1;
  START=0;
  while(EOC==0);
   OE=1;
   dat_adc0808=P1;
   OE=0;
  return dat_adc0808;
}
   得到ADC0808的转换结果后,应当及时处理成LCD1602能够显示的数字字符。以下函数实现此功能,为ADC0808显示刷新子程序:
        void Refresh_show()                            //刷新显示
{
   uint t=dat_adc0808*500.0/255;              //
   display_buffer[1][7] = t/100+'0';              //整数位
   display_buffer[1][9] = t/10%10+'0';              //两个小数位
   display_buffer[1][10] = t%10+'0';
}
  • 课堂小结
本节课我们主要学习了如何应用ADC0808设计一个数字电压表。知道了在硬件上ADC0808芯片和单片机的连接,在软件方面,我们着重介绍了如何获取A/D转换结果函数的设计,这需要我们从ADC0808芯片的技术资料中获得设计程序的方法。通过和前面一个项目的对比可知,对于模数转换芯片的使用,关键的一点就是我们必需明白A/D芯片的转换机制,ADC0808转换时和时钟引脚的频率有很大的关系,频率设置不当,ADC0808就不能转换,这一点同学们要特别注意。
  • 完整程序代码
1、LCD1602.c源程序
  1. //液晶控制与显示驱动程序
  2. #include <reg52.h>
  3. #include <intrins.h>
  4. #include <string.h>
  5. #include "LCD1602.h"
  6. #include "ADC0808.h"
  7. //---------------忙检查-------------------//
  8. uchar LCD_Busy_Check()
  9. {
  10.               uchar LCD_Status;
  11.               RS = 0;
  12.               RW = 1;
  13.               E = 1;
  14.               delay4us();
  15.               LCD_Status = P0;
  16.               E = 0;
  17.               return LCD_Status;
  18. }
  19. //--------------向LCD写入命令--------------------//
  20. void Write_LCD_Command(uchar cmd)
  21. {
  22.               while((LCD_Busy_Check()& 0x80)==0x80);                 //忙等待
  23.               RS = 0;
  24.               RW = 0;
  25.               E  = 0;
  26.               P0 = cmd;
  27.               delay4us();
  28.               E = 1;
  29.               delay4us();
  30.               E = 0;
  31. }
  32. //-----------向LCD写入一个字节的数据函数-----------------*/
  33. void Write_LCD_Data(uchar dat)
  34. {
  35.               while((LCD_Busy_Check()&0x80)==0x80);
  36.               RS = 1;
  37.               RW = 0;
  38.               E  = 0;
  39.               P0 = dat;
  40.               delay4us();
  41.               E = 1;
  42.               delay4us();
  43.               E = 0;
  44. }
  45. //-----------LCD初始化-----------------*/
  46. void Initialize_LCD1602() //液晶初始化函数
  47. {
  48.    Write_LCD_Command(0x38);delay50us(10);              //功能设置,数据长度为8位,双行显示,5×7点阵字体
  49.    Write_LCD_Command(0x0C);delay50us(10); // 显示开,关光标
  50.    Write_LCD_Command(0x06);delay50us(10); //字符进入模式:屏幕不动,字符后移
  51.    Write_LCD_Command(0x01);              delay50us(10);//清屏
  52. }
  53. //-----------在LCD上显示字符串-----------------*/
  54. void LCD_Display(uchar *str)
  55. {
  56.   uchar i;
  57.   for(i=0;i<strlen(str);i++)
  58.     {
  59.                 Write_LCD_Data(str[i]);
  60.                 delay50us(100);
  61.               }
  62. }
  63. 2、lCD1602_H头文件
  64. #ifndef __lCD1602_H__
  65. #define              __LCD1602_H__
  66. #include <reg52.h>

  67. #define dat_port P0
  68. #define uchar unsigned char
  69. #define uint unsigned int
  70. #define delay4us() {_nop_();_nop_();_nop_();_nop_();}
  71. sbit RS=P2^0;//RS=1 数据 RS=0 命令
  72. sbit RW=P2^1;//RW=1 读取 RW=0 写入
  73. sbit E=P2^2;//E 使能信号

  74. uchar LCD_Busy_Check();//忙检查
  75. void Write_LCD_Command(uchar cmd);//向LCD写入命令
  76. void Write_LCD_Data(uchar dat);  //向LCD写入一个字节的数据函数
  77. void Initialize_LCD1602(); //液晶初始化函数
  78. void LCD_Display(uchar *str);//在LCD上显示字符串

  79. #endif
  80. 3、ADC0808.C源程序
  81. #include<reg52.h>
  82. #include <intrins.h>
  83. #include "ADC0808.h"

  84. unsigned long dat_adc0808;
  85. uchar display_buffer[ ][16]={
  86.                              {"Current voltage:"},
  87.                                                                                                   {" (CH) =0.00V"}
  88.                                                                                                   };
  89. void delay50us(uint m)
  90. {
  91.    uint n,k;
  92.    for(n=m;n>0;n--)
  93.     for(k=25;k>0;k--);
  94. }

  95. uint adc0808_init()      // AD初始化
  96. {
  97.   START=0;
  98.   OE=0;
  99.   START=1;
  100.   START=0;
  101.    while(EOC==0);
  102.    OE=1;
  103.    dat_adc0808=P1;
  104.    OE=0;
  105.   return dat_adc0808;
  106. }
  107. void Refresh_show()                            //刷新显示
  108. {
  109.    uint t=dat_adc0808*500.0/255;              //
  110.    display_buffer[1][7] = t/100+'0';              //整数位
  111.    display_buffer[1][9] = t/10%10+'0';              //两个小数位
  112.    display_buffer[1][10] = t%10+'0';
  113. }
  114. 4、ADC0808.h 头文件
  115. #ifndef __ADC0808_H__
  116. #define              __ADC0808_H__
  117. #include <reg52.h>

  118. #define data_port P1
  119. #define uchar unsigned char
  120. #define uint unsigned int

  121. sbit START=P2^3;
  122. sbit EOC=P2^4;
  123. sbit OE=P2^5;

  124. void delay50us(uint m);//  延时
  125. uint adc0808_init();      // AD初始化
  126. void Refresh_show();
  127. #endif
复制代码

5、main.c 主程序
#include<reg52.h>
#include <intrins.h>
#include "LCD1602.h"
#include "ADC0808.h"
sbit CLOCK=P2^6;
extern uchar display_buffer[][16];
void main()
{
   TMOD=0x02;
   TH0=0x14;
   TL0=0x00;
   IE=0x82;
   TR0=1;
  Initialize_LCD1602();
  delay50us(10);
  Write_LCD_Command(0x80);//设置显示的初始位置
  LCD_Display(display_buffer[0]);//显示"The voltage is: "
   while(1)
   {
      adc0808_init();
                Refresh_show();              
                Write_LCD_Command(0xC0);//设置显示的初始位置
                LCD_Display(display_buffer[1]); //显示测得的数据
               
   }
}
void Timer0_INT() interrupt 1
{
   CLOCK=!CLOCK;
}


完整的Word格式文档51黑下载地址(内含清晰图片):
用lcd1602和adc0808设计的数字电压表.doc (334.5 KB, 下载次数: 80)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:465292 发表于 2019-5-16 18:41 | 只看该作者
求代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表