• 自适应量程数字电压表设计总结


    1. 任务需求

    • 量程:直流电压0~20V
    • 三档:0~200mV,200mV~2V,2V~20V
    • 精度:0.01,显示稳定,无闪烁
    • 误差:0.2V挡位≤10%,2V和20V挡≤1%

    2. 需求分析

    • 直流电压表(0~20V):利用数码管,通过数字方式显示测定直流电压值,其范围为0~20V
    • 自动量程转换:0~20V直流电压分为三档:0~0.2V,0.2V~2V,2V~20V。且能根据0~20V测试电压的具体值来自动切换量程

    3. 设计方案

    3.1. 总概述

    首先,我们了解到测试电压为0~20V的直流电压。现我们使用的ADC0809芯片只能处理0~5V电压。故,我们先需要将0~20V电压5分压至0~4V,即满足了ADC0809芯片处理范围。然后STC89C52接收到数字量后,在程序中判断当前量程是否合适。若是,则将电压值输出到数码管上显示。否,则反馈调节数据选择器的输出口去调节挡位,直到量程合适。总体设计图如3-1

    图3-1

    3.2. 电压放大部分

    这一部分属于信号预处理部分,实际上电压表的误差主要出现在这里。首先,我了解到ADC0809为八位A/D转换芯片,量化模拟电压值范围为0~5V。我们测定电压范围为0~20V,故我首先要将其5分压至0~4V以便满足其需求。而为了精确测定,我需要将5分压后较小的两个量程0~0.2、0.2~2分别放大100倍、10倍。此处,我借助同相比例放大器。三个挡位增益由小到大根据图3-2分别为1、1+R10/R9、1+R11/R9。同时,为了满足自动转换这一需求,我借助74HC4051芯片——八选一数据选择器。将其数据地址口A、B分别与单片机P1.4、P1.5相连。在单片机内部程序中,根据ADC0809送入数字量判断当前量程是否合适,若不合适改变数据选择器的地址输入,即可完成自动量程转换这一需求。

    图3-2

    3.3. 模数转换部分

    主要元器件为ADC0809与74LS74。这一部分属于整个电路中最最为关键的部分,但是实际上设计与操作来说,并不是特别复杂。因为ADC0809芯片集成度很高,我只需要将其启动转换端口,转换完成标志端口等将其与单片机STC89C52相连接,并且在程序内编写相关语句就可以完成对ADC0809芯片的控制,即可完成A/D转换的处理。而74LS74芯片是一个双D触发器。由于ADC0809内部并没有晶振电路,所以,其需要时钟信号,并且要求范围在0~640Khz之间。这次我使用的STC89C52芯片晶振频率为6Mhz,其ALE口输出为1Mhz,故使用D触发器进行二分频可得到500Khz时钟信号,即完成ADC0809芯片的正常运转。

     

    图3-3

    3.4. 数码管显示部分

    在位选部分我选择了P0口,值得注意的一点是:P0口在作为通用I/O使用时,需要接入上拉电阻并且手动先置高电平。并且,我使用了共阴极七段数码管,所以在位选个个端口要接入非门。在段选部分,我使用P2.0~3,使用了4511译码器,即可完成段选数据的输入。小数点则单独使用了P2.7口,在单片机程序内判断是否点亮它。

    图3-4

    4. 仿真

    2~20V:测试用量5V

     

    0.2~2V:测试用量1.5V

     

    0~0.2:测试用量0.1V

    5. 调试与测试

    5.1. 几个问题

    问题一:如何降低同相比例放大器处的误差?(此处误差为电压表误差最主要之处)

    问题二:如何保证数码管处焊接无错误(此处为电路中最难焊接之处)

    问题三:如何确保ADC0809芯片处于正常工作状态

    5.2. 问题分析

    问题一:由于定值电阻并不是完全准确,所以在同相比例放大器处放大倍数并不是在仿真中那样完全理想。故会产生较大的误差。

    问题二:数码管处在段选部分,我们使用单个I/O控制,故此我们需要将每一个数码管对应的引脚并连。线路并不复杂,但极易出现短路、短路、链接错误等情况。

    问题三:ADC0809正常工作有比较多的需求。首先,需要有0~640kHZ的时钟信号,其次,单片机内部程序要对其正确的操作。

    5.3. 解决方法

    问题一:采用电位器,在整个电路焊接好之后,调节电位器来减小误差。

    问题二:编写测试文件,即单片机程序送出一个固定的数字,若数码管显示数字及小数点符合预期要求,即数码管处连接正确。反之,则有错误。

    问题三:实际上来说这个问题并不能直接调试,因为假定写入完整的程序,数码管是固定的数字,并无法保证是其出错。我的方法是:写入完整的程序后,给定1V测试电压。在预期方案中1V属于0.2~2V量程,则此刻4051选择通道2,则此时其数据地址A为高,B为低。若是如此,则ADC0809完成了正常的数据采集操作,因为A之所以为高,B之所以为低是单片机程序作用的结果,而单片机只有接收到了正确的值才会做这个操作。故反推ADC0809是正常工作的。

    6. 参考文献

    汪文、陈林. 单片机原理及应用[M]. 湖北:华中科技大学出版社.

    7. 附录1(测量数据)

    8. 附录2(源码)

      1 #include<reg52.h>
      2 sbit start = P1^0; //启动A/D转换
      3 sbit eoc = P1^1;    //转换结束信号输出端
      4 sbit oe = P1^2;        //输出允许
      5 sbit ale = P1^3;    //地址锁存允许
      6 
      7 //自动挡位选择输入
      8 sbit a = P1^4;
      9 sbit b = P1^5;
     10 
     11 sbit point = P2^7;
     12 
     13 
     14 unsigned int W_temp_data[4] = {0x08, 0x04, 0x02, 0x01};//位选数据
     15 unsigned int D_temp_data[8] = {0,0,0,0,0,0,0,0}; //段选数据
     16 
     17 unsigned long int temp_data = 0; //ADC0809输出数字量
     18 
     19 /*********************
     20  *       软件延时     *
     21  *********************/
     22 void deley(unsigned int x)
     23 {
     24     unsigned int i,j;
     25     for(i=0; i<x; i++)
     26     {
     27         for(j=0; j<100; j++)
     28         {
     29             ;
     30         }
     31     }
     32 }
     33 
     34 /*********************
     35  *       显示函数        *
     36  *********************/
     37 void display(unsigned int x)
     38 {
     39     unsigned int i, j;
     40     for(j = 0; temp_data ; j ++)
     41     //将数字量每一位取出放入D_temp_data数组中
     42     {
     43         D_temp_data[j] = temp_data % 10;
     44         temp_data = temp_data / 10;
     45     }
     46     for(i = 0; i < 4; i ++)
     47     {
     48     
     49         //前导零消除
     50         if(x == 0 && i == 3 && D_temp_data[i] == 0)
     51         {
     52             break;
     53         }
     54         if(x == 2)
     55         {
     56             if(D_temp_data[i] == 0 && i == 2 && D_temp_data[3] == 0)
     57             {
     58                 break;
     59             }
     60             if(D_temp_data[i] == 0 && i == 3)
     61             {
     62                 break;
     63             }
     64         }
     65         P0 = W_temp_data[i];
     66         P2 = D_temp_data[i];
     67         //小数点显示
     68         if(x == 0)
     69         {
     70             if(i == 2)
     71             {
     72                 point = 1;
     73             }
     74         }
     75         else if(x == 1)
     76         {
     77             if(i == 3)
     78             {
     79                 point = 1;
     80             }
     81         }
     82         else if(x == 2)
     83         {
     84             if(i == 1)
     85             {
     86                 point = 1;
     87             }
     88         }
     89         deley(1);
     90     }
     91 }
     92 
     93 /*********************
     94  *       挡位选择       *
     95  *    x: 0 *1挡        *
     96  *       1 *10挡        *
     97  *       2 *100挡        *
     98  *********************/
     99 void choose(unsigned int x)
    100 {
    101     switch(x)
    102     {
    103         case 0:
    104             a = 0;
    105             b = 0;
    106             break;
    107         case 1:
    108             a = 1;
    109             b = 0;
    110             break;
    111         case 2:
    112             a = 0;
    113             b = 1;
    114             break;
    115         default:
    116             ;
    117     }
    118 }
    119 
    120 void main()
    121 {
    122     unsigned int x = 0; //量程控制
    123     while(1)
    124     {
    125         ale = 1;
    126         deley(1);
    127         ale = 0;
    128         choose(x);
    129         start = 1;
    130         deley(1);
    131         start = 0; //下降沿启动A/D转换
    132         while(eoc == 0)
    133         //转换结束
    134         {
    135             ;
    136         }
    137         oe = 1; //输出允许
    138         temp_data = P3;
    139         oe = 0; //输出阻塞
    140         if(x == 0 && temp_data < 21)
    141         //量程过高,切换至0.2-2V
    142         {
    143             x = 1;
    144             continue;
    145         }
    146         if(x == 1 && temp_data < 21)
    147         {
    148         //量程过高,切换至0-0.2V
    149             x = 2;
    150             continue;
    151         }
    152         if(x ==1 && temp_data > 204)
    153         //量程过低,切换至2-20V
    154         {
    155             x = 0;
    156             continue;
    157         }
    158         if(x == 2 && temp_data > 204)
    159         //量程过低,切换至0.2-2V
    160         {
    161             x = 1;
    162             continue;
    163         }
    164         temp_data = temp_data * 100 * 5 /51;
    165         display(x);
    166     }
    167 }
  • 相关阅读:
    给你一个长度为 n 的数组,其中只有一个数字出现了大于等于 n/2 次,问如何使用优秀的 时空复杂度快速找到这个数字。
    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现偶数次。找出那个只出现了一次的元素。
    python虚拟环境配置
    测试环境配置
    使用ELK Stack收集kubernetes集群内的应用日志
    vue 禁止遮罩层下的页面滑动
    vue 把 java 传过来的流文件 转成apk、xls等
    vue 中使用 webSocket 收发数据, 增加 " 心跳机制 " 保持连接.
    webstrom 根据当前编辑文件定位左侧目录
    MySQL 8.0新特性详解(转)
  • 原文地址:https://www.cnblogs.com/iwuqing/p/11737379.html
Copyright © 2020-2023  润新知