找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6995|回复: 5
收起左侧

基于单片机AT89C52+ADC0832的数字电压表仿真设计

[复制链接]
ID:442669 发表于 2018-12-26 18:19 | 显示全部楼层 |阅读模式
基于单片机AT89C52的数字电压表设计
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png

单片机源程序如下:
  1. #include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  2. #include "intrins.h"                                                                                          

  3. #define     uchar                  unsigned char
  4. #define     uint                   unsigned int





  5. #define   SMG_NUM   4
  6. uchar code DisplayNum[16]={
  7. 0xc0,                //0
  8. 0xf9,                //1
  9. 0xa4,                //2
  10. 0xb0,                //3
  11. 0x99,                //4
  12. 0x92,                //5
  13. 0x82,                //6
  14. 0xf8,                //7
  15. 0x80,                //8
  16. 0x90,                //9
  17. 0x88,                //A
  18. 0x83,                //b
  19. 0xc6,                //C
  20. 0xa1,                //d
  21. 0x86,                //E
  22. 0x8e                //F
  23. };
  24. //对应关系取字:        dp g f e    d c b a
  25. //例如  U             1  1 0 0    0 0 0 1
  26. uchar code DisplayOther[]={
  27. 0xff,                 //0                空
  28. 0x7f,                 //1                "."
  29. 0xbf,                        //2                "-"
  30. 0xa7,                        //3                c
  31. 0xC1                        //3                U  1100 0001
  32. };

  33. /***********************************************************************************************************
  34. 数码管显示相关函数
  35. ***********************************************************************************************************/

  36. //数码管位选定义
  37. sbit smg_we1 = P2^0;            //数码管1
  38. sbit smg_we2 = P2^1;                        //数码管2
  39. sbit smg_we3 = P2^2;                        //数码管3
  40. sbit smg_we4 = P2^3;                        //数码管4


  41. /***********************数码位选函数*****************************/

  42. void smg_we_switch(uchar i)
  43. {
  44.         smg_we1 = 1;
  45.   smg_we2 = 1;
  46.         smg_we3 = 1;
  47.   smg_we4 = 1;
  48.         switch(i)
  49.         {
  50.                 case 0: smg_we1 = 0;   break;
  51.                 case 1: smg_we2 = 0;   break;
  52.                 case 2: smg_we3 = 0;   break;
  53.                 case 3: smg_we4 = 0;   break;
  54.         }       
  55. }



  56. /********************************************************************
  57. * 名称 : uchar ChangeFor(uchar dat)
  58. * 功能 : 交换一个字节位的位置,用于数码管显示
  59. * 输入 : 需要改变的数
  60. * 输出 : 改变后的数
  61. ***********************************************************************/
  62. #define LED_a                0        //数码管段选的a段接在段选IO口的第0位
  63. #define LED_b                2
  64. #define LED_c                6
  65. #define LED_d                4
  66. #define LED_e                3
  67. #define LED_f                1
  68. #define LED_g                7
  69. #define LED_dp        5

  70. uchar ChangeFor(uchar dat)
  71. {
  72.         uchar temp=0;
  73.         if(dat&0x01)                //判断数据的第一位是否为1
  74.                 temp|=0x01<<LED_a;//如果为1,放到控制数码管a段的位置
  75.         if(dat&0x02)
  76.                 temp|=0x01<<LED_b;
  77.         if(dat&0x04)
  78.                 temp|=0x01<<LED_c;
  79.         if(dat&0x08)
  80.                 temp|=0x01<<LED_d;
  81.         if(dat&0x10)
  82.                 temp|=0x01<<LED_e;
  83.         if(dat&0x20)
  84.                 temp|=0x01<<LED_f;
  85.         if(dat&0x40)
  86.                 temp|=0x01<<LED_g;
  87.         if(dat&0x80)
  88.                 temp|=0x01<<LED_dp;
  89.         return temp;
  90. }
  91. uchar dis_smg[SMG_NUM];                                                //显示缓存数组

  92. /********************************************************************
  93. * 名称 : display()
  94. * 功能 : 数码管显示
  95. * 输入 : 无
  96. * 输出 : 无
  97. ***********************************************************************/
  98. void DisplayScan()
  99. {
  100.         static uchar i;
  101.         P0 = 0xff;                  //消隐
  102.                 smg_we_switch(i);                                    //位选
  103.         P0 =        ChangeFor(dis_smg[i]);                  //段选          
  104.         i++;
  105.         if(i>=SMG_NUM)
  106.                 i=0;
  107. }
  108. /***********************************************************************************************************
  109. ADC0832相关函数
  110. ***********************************************************************************************************/
  111. sbit AD0832_CS   = P1^2 ;   //片选信号
  112. sbit AD0832_CLK  = P1^0;    //时钟接口
  113. sbit AD0832_DI   = P1^1;    //数据接口  /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上*/
  114. uchar GetAD0832(bit Channel)
  115. {     
  116.         uchar  i=0 , Data1 =0 , Data2 = 0 ;     
  117.         AD0832_CLK = 0 ;        //时钟置低平//时钟12Mhz, 整个转换时间为224us  
  118.         //使用芯片准备(参考PDF时序图)      
  119.         AD0832_DI  = 1 ;        //开始信号为高电平     
  120.         AD0832_CS  = 0 ;        //片选信号置低,启动AD转换芯片            
  121.         AD0832_CLK = 1 ;        //输入开始信号(构成一个正脉冲),时钟上升沿,输入开始信号     
  122.         AD0832_CLK = 0 ;        //时钟下降沿   
  123.         //模拟信号输入模式选择(1:单模信号,0:双模差分信号)   
  124.         AD0832_DI  = 1 ;     
  125.         AD0832_CLK = 1 ;        //时钟上升沿,输入开始信号     
  126.         AD0832_CLK = 0 ;        //时钟下降沿     
  127.         //模拟信号输入通道选择(1:通道CH1,0:通道CH0)   
  128.         AD0832_DI  = Channel ;  //选择通道0     
  129.         AD0832_CLK = 1;         //时钟上升沿,输入开始信号
  130.         AD0832_CLK = 0;         //时钟下降沿         
  131.         AD0832_DI  = 1;                      //数据线置高,准备接收数据  
  132.         for(i=0;i<8;i++)                          //从高位移入数据   
  133.         {      
  134.                 AD0832_CLK = 1 ;              
  135.                 AD0832_CLK = 0 ;      //时钟下降沿,AD0832输出数据,高位(MSB)先         
  136.                 Data1 = Data1<<1;     //数据左移位,补0     
  137.                 if(AD0832_DI ==1)      
  138.                 {
  139.                         Data1 = Data1 | 0x01;
  140.                 }                                                    //如果数据为“1”,移入1,   
  141.         }                              //如果数据为“0”,移入0,        
  142.         for(i=0;i<8;i++)                     //从低位移入数据  
  143.         {      
  144.                 Data2 = Data2>>1;   //数据左移位,补0     
  145.                 if(AD0832_DI ==1)        
  146.                 {
  147.                         Data2 = Data2 | 0x80;
  148.                 }   //如果数据为“1”,移入1如果数据为“0”,移入0,         
  149.                 AD0832_CLK = 1;            
  150.                 AD0832_CLK = 0;          //时钟下降沿,AD0832输出数据,高位(MSB)先  
  151.         }     
  152.         //数据线置高,释放总线,完成一次转换     
  153.         AD0832_CLK = 1 ;            
  154.         AD0832_DI  = 1;              
  155.         AD0832_CS  = 1;                     
  156.         if(Data1==Data2)     //输出   
  157.         {
  158.                 return Data2;
  159.         }  
  160.         return 0;
  161. }


  162. /***********************************************************************************************************
  163. 主函数
  164. ***********************************************************************************************************/
  165. void main (void)
  166. {
  167.         uchar Read_AD;        //用于读取ADC数据
  168.         uint VIN;                        //电压值变量
  169.         while (1)                                      //主循环
  170.         {               
  171.                 Read_AD=GetAD0832(0);                                //读取AD值
  172.                 //电压模式
  173.                 VIN=Read_AD*7.84;                                                                                //换算出电压值
  174.                 dis_smg[0]=DisplayNum[VIN/1000%10];                        //显示电压标志
  175.                 dis_smg[1]=DisplayNum[VIN/100%10]&0x7f;                        //电压十位
  176.                 dis_smg[2]=DisplayNum[VIN/10%10];        //电压个位
  177.                 dis_smg[3]=DisplayNum[VIN%10];                                        //电压十分位
  178.                 DisplayScan();                //数码管动态扫描
  179.         }
  180. }
复制代码
0.png
所有资料51hei提供下载:
数字电压表设计.zip (24.34 KB, 下载次数: 116)
回复

使用道具 举报

ID:407566 发表于 2019-1-4 23:31 | 显示全部楼层
  VIN=Read_AD*7.84;   为什么是乘以7.84?
回复

使用道具 举报

ID:570252 发表于 2019-6-23 20:32 | 显示全部楼层
如果我想对电压进行非线性补偿,请问有办法吗?
回复

使用道具 举报

ID:576039 发表于 2019-7-2 00:17 | 显示全部楼层
ok,收藏了
回复

使用道具 举报

ID:56665 发表于 2019-7-2 08:44 | 显示全部楼层
过过过儿 发表于 2019-1-4 23:31
VIN=Read_AD*7.84;   为什么是乘以7.84?

没有人回复,我认为这个值是输入电压的比值,输入电压一般不会直接到IO端口,要通过电阻分压后才进入单片机IO端口,这样可以扩大测量的量程,如果没有分压VIN = Read_AD*5/256
回复

使用道具 举报

ID:704637 发表于 2020-4-11 10:23 | 显示全部楼层
最近也在研究如何应用ADC0832,谢谢楼主的分享啦
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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