找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机AD转换 PCF8591数显电压表代码Proteus仿真原理图

[复制链接]
跳转到指定楼层
楼主
以单片机为核心器件,组成一个简单数字电压表。
(1)采用1路模拟量输入,能够测量0-10V(20v、30v、40v)之间的直流电压值。
(2)电压显示可采用LCD1602显示,能够显示两位小数。
简易数字电压表的制作,主要涉及数据(电压)测量、A/D转换及控制显示方面的知识。
(1)A/D转换采用PCF8591实现。
(2)电压显示采用LCD1602。
(3)单片机选用AT89C5.

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


单片机源程序如下:
  1. #include <reg52.h>   
  2. #include <intrins.h>   //包含函数_nop_()定义的头文件
  3. #define u8 unsigned char
  4. #define u16 unsigned int
  5.         
  6. #define AddWr 0x90   //PCF8591写地址
  7. #define AddRd 0x91   //PCF8591读地址
  8. #define w_com P0
  9.         
  10. sbit RS=P2^2;
  11. sbit RW=P2^3;
  12. sbit E=P2^4;
  13. sbit Sda=P1^2;        //定义IIC总线引脚
  14. sbit Scl=P1^1;
  15. u8 datetab[10];    //存入电压值
  16. u8 ADtemp;   //通道转换后存入的数值
  17. float V_1602;
  18. u16 num=0;

  19. unsigned long num_pow(u8 m,u8 n)          //指数运算
  20. {
  21.         unsigned long result=1;
  22.         while(n--) result*=m;
  23.         return result;
  24. }

  25. void float2str(u8 str[],double floa,u8 len1,u8 len2)         //浮点型转字符型数组
  26. {
  27.         u8 i=0,j=0;
  28.         u16 zhengshu=floa;
  29.         u16 xiaoshu=(floa-zhengshu)*num_pow(10,len2);
  30.         while(len1--)
  31.         {
  32.                 str[len1]=zhengshu%10+0x30;
  33.                 zhengshu=zhengshu /10;
  34.                 i++;
  35.         }
  36.         str[i]='.';
  37.         while(len2--)
  38.         {
  39.                 str[i+len2+1]=xiaoshu%10+0x30;
  40.                 xiaoshu=xiaoshu/10;
  41.                 j++;
  42.         }
  43.         str[i+j+1]='\0';
  44. }


  45. /*------------------------------------------------
  46. 启动IIC总线
  47. ------------------------------------------------*/
  48.   void Start(void)
  49.   {
  50.    Sda=1;
  51.    _nop_();
  52.    Scl=1;
  53.    _nop_();
  54.    Sda=0;        //sda负跳变
  55.    _nop_();
  56.    Scl=0;
  57.   }
  58. /*------------------------------------------------
  59. 停止IIC总线
  60. ------------------------------------------------*/
  61.   void Stop(void)
  62.   {
  63.    Sda=0;
  64.    _nop_();
  65.    Scl=1;
  66.    _nop_();
  67.    Sda=1;        //sda正跳变
  68.    _nop_();
  69.    Scl=0;
  70.    }
  71. /*------------------------------------------------
  72.    IIC总线应答
  73. ------------------------------------------------*/
  74.    void Ack(void)
  75.    {
  76.     Sda=0;         //scl高电平期间sda输出低电平
  77.                 _nop_();
  78.                 Scl=1;         
  79.                 _nop_();
  80.                 Scl=0;
  81.                 _nop_();
  82.         }
  83. /*------------------------------------------------
  84. IIC总线非应答
  85. ------------------------------------------------*/
  86.         void NoAck(void)
  87.         {
  88.          Sda=1;          //scl高电平期间sda输出高电平
  89.          _nop_();
  90.          Scl=1;           
  91.          _nop_();
  92.          Scl=0;
  93.          _nop_();
  94.          }
  95. /*------------------------------------------------
  96. 向PCF8591发送1字节数据(/地址/控制命令等)
  97. ------------------------------------------------*/
  98. void Send(u8 Data)
  99. {
  100.           u8 BitCounter=8;   //定义发送位数为8
  101.           do
  102.           {
  103.                  Scl=0;
  104.                  _nop_();
  105.                  if((Data&0x80)==0x80)        //逐位判别1/0后送至SDA
  106.                     Sda=1;        //scl低电平期间数据送至sda线                        
  107.                  else
  108.                     Sda=0;
  109.                   Scl=1;        //scl变高输出数据(写入pcf8591)                        
  110.                   Data=Data<<1;
  111.                   BitCounter--;
  112.           }while(BitCounter);
  113.           Scl=0;
  114. }
  115. /*------------------------------------------------
  116. 从PCF8591读入1字节(例如A/D转换结果)
  117. ------------------------------------------------*/
  118. u8 Read(void)
  119. {
  120.                    u8 temp=0;
  121.                    u8 BitCounter=8;
  122.                    Sda=1;                        //拉高数据线
  123.                    do
  124.                    {
  125.                           temp=temp<<1;        //逐位移入temp
  126.                         Scl=0;                        
  127.                   _nop_();
  128.                           Scl=1;         //scl变高采样sda线
  129.                           _nop_();
  130.                           if(Sda)                        //判别SDA线上为1/0
  131.                      temp=temp|0x01;
  132.                           else
  133.                      temp=temp&0xfe;
  134.                           BitCounter--;         
  135.              }while(BitCounter);               
  136.              return(temp);                //返回值为读入的字节
  137. }

  138. void DACconversion(u8 sla,u8 c, u8 Val)    //8591输出一个数据
  139. {
  140.         Start();//启动总线
  141.         Send(sla);//发送器件地址
  142.                  Ack();        
  143.         Send(c);//发送控制字节
  144.                  Ack();        
  145.         Send(Val);//发送DAC的数值
  146.                  Ack();        
  147.         Stop();//结束总线
  148. }


  149. /*----------------------------------------------------------
  150. 启动PCF8591 Chl 通道A/D转换并读取转换结果
  151. --------------------------------------------------------------*/
  152. u8 ReadADC(u8 Chl)
  153.         {
  154.                  u8 Data;
  155.                  Start();                //开始信号
  156.                  Send(AddWr);                   //发写地址(0x90)
  157.                  Ack();                           //等待 PCF8591应答        
  158.                  Send(0x40|Chl);         //写入控制字并启动 Chl通道A/D转换
  159.                  Ack();                           //等待 PCF8591应答
  160.                  Start();                           //重发开始信号
  161.                  Send(AddRd);           //写入读地址
  162.                  Ack();
  163.                  Data=Read();            //读取A/D转换结果(注意是上次的)
  164.                  NoAck();                //发非应答信号
  165.                  Stop();                           //停止总线操作
  166.                  return Data;            //返回A/D转换结果
  167.         }

  168. void delay(u16 i)
  169. {

  170.         while(i--);

  171. }

  172. void LCD_busy(void)
  173. {
  174.     u8 temp;
  175.     do{
  176.         temp =0xff;  
  177.         E = 0;
  178.         RS= 0;   
  179.         RW = 1;
  180.         E =1;
  181.         temp = w_com;  
  182.                         }while(temp&0x80);  // 如果 BF =1 则持续检查
  183.         E = 0;
  184. }


  185. void write_command(u8 com)
  186. {
  187.     LCD_busy();
  188.    E= 0;
  189.    RS =0;
  190.    RW =0;
  191.    w_com = com;
  192.    E =1;  
  193.    delay(100);
  194.    E = 0;

  195. }


  196. void write_data(u8 com)
  197. {
  198.   LCD_busy();
  199.   E=0;   
  200.   RS= 1;
  201.   RW =0;
  202.   w_com = com;
  203.   E=1;
  204.   delay(100);
  205.   E =0;

  206.   }

  207.         
  208.         
  209.         
  210.         
  211.         void lcd_initial(void)
  212. {
  213.         write_command(0x38);    //8位数据接口,双行显示
  214.         delay(100);
  215.   write_command(0x0c);    //开显示屏
  216.         delay(100);
  217.          write_command(0x01);    //清屏
  218.         delay(100);
  219.   write_command(0x06);                 //光标移动
  220.         delay(100);
  221.   
  222.   }

  223.         
  224. void string(u8 y,u8 x, u8 *s)     //x表示行,y表示列
  225. {
  226.          if (x==1)
  227.          {
  228.                 write_command(0xc0|y);          //因为DDRAM寻址指令是 0x80开头。
  229.          }
  230.          else
  231.                 write_command(0x80|y);
  232.          
  233.          while(*s != '\0')
  234.         {
  235.           write_data(*s++);
  236.         }
  237. }

  238. void string_word(u8 y,u8 x,u8 num)     
  239. {
  240.          if (x==1)
  241.          {
  242.                 write_command(0xc0|y);          //因为DDRAM寻址指令是 0x80开头。
  243.          }
  244.          else
  245.                 write_command(0x80|y);
  246.          
  247.                 write_data(num);

  248. }        
  249.         

  250. void main()
  251. {
  252.         lcd_initial();
  253.                 while(1)
  254.                 {
  255.                 ADtemp=ReadADC(1);              //读取通道1 A/D转换结果                        
  256.                 V_1602=ADtemp*(10.0/256);          //计算电压值     10.0 20.0  30.0 40.0
  257.                 float2str(datetab,V_1602,2,2);   //显示整数位与小数位的个数
  258.                 string(5,0,datetab);                        //显示的位置和内容
  259.                 string_word(10,0,'V');            //显示单位
  260.                 delay(10000);
  261.                 }
  262. }
  263.         
复制代码

Keil代码与Proteus8.13版本的仿真下载(注意不能兼容其他版本 只能用8.13打开):
程序+Proteus8.13仿真图.7z (74.12 KB, 下载次数: 77)

评分

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

查看全部评分

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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