单片机+PCF8591实现数字电压表

发布者:创意旅程最新更新时间:2020-09-14 来源: 51hei关键字:单片机  PCF8591  数字电压表 手机看文章 扫描二维码
随时随地手机看文章

制作数字电压表(2学时)

一、实验目的:

1. 了解I2C串行总线工作原理及通信协议

2. 了解ADC0804、DAC0832、PCF8591与AT89S51的接口设计

3. 掌握ADC0804、DAC0832、PCF8591的编程方法

4. 能够熟练运用数模转换模块


二、实验要求:

1. 数字电压表:在AT89C52系统中采用PCF8591芯片,测量0-5V范围内的直流电压,并在2位数码管上显示电压值。


三、实验设备:(PROTEUS元件表)


四、实验报告:

1.描述实验过程(重要步骤用屏幕截图表示)。

2.给出在PROTEUS中设计的单片机系统电路图

3.画出程序流程图

4.给出在KEIL中编写的源程序。

5.描述在proteus中仿真运行程序的实验现象


五、实验总结


单片机源程序如下:

/**********************BST-M51实验开发板例程************************

*  平台:BST-M51 + Keil U4 + STC89C52

*  名称:AD串口读取实验

*  公司:深圳市亚博软件开发有限公司      

*  日期:2015-6

*  晶振:11.0592MHZ

******************************************************************/

#include    //包含单片机寄存器的头文件

#include


#define  AddWr 0x90    //PCF8591 地址


// 变量定义

unsigned char AD_CHANNEL=0;

unsigned char  D[32];

unsigned char code table[10]={0xC0,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};   //共阳极数码管0~9显示的数值表

unsigned int data dis[3]={0x00,0x00,0x00};  //用以计算存储输出电压的3元素数组


sbit scl=P2^0;       //I2C  时钟

sbit sda=P2^1;       //I2C  数据

bit ack;                 /*应答标志位*/

sbit C1=P2^6;//数码管位选

sbit C2=P2^7;//数码管位选

sbit Dp=P2^5;//小数点


unsigned char date;


/*******************************************************************

                     起动总线函数              

函数原型: void  Start_I2c();

功能:     启动I2C总线,即发送I2C起始条件.

********************************************************************/

void Start_I2c()

{

  sda=1;         /*发送起始条件的数据信号*/

  _nop_();

  scl=1;

  _nop_();        /*起始条件建立时间大于4.7us,延时*/

  _nop_();

  _nop_();

  _nop_();

  _nop_();   

  sda=0;         /*发送起始信号*/

  _nop_();        /* 起始条件锁定时间大于4μs*/

  _nop_();

  _nop_();

  _nop_();

  _nop_();      

  scl=0;       /*钳住I2C总线,准备发送或接收数据 */

  _nop_();

  _nop_();

}


/*******************************************************************

                      结束总线函数              

函数原型: void  Stop_I2c();

功能:     结束I2C总线,即发送I2C结束条件.

********************************************************************/

void Stop_I2c()

{

  sda=0;      /*发送结束条件的数据信号*/

  _nop_();       /*发送结束条件的时钟信号*/

  scl=1;      /*结束条件建立时间大于4μs*/

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  _nop_();

  sda=1;      /*发送I2C总线结束信号*/

  _nop_();

  _nop_();

  _nop_();

  _nop_();

}


/*******************************************************************

                 字节数据发送函数              

函数原型: void  I2C_SendByte(UCHAR c);

功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对

          此状态位进行操作.(不应答或非应答都使ack=0)   

           发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

********************************************************************/

void  I2C_SendByte(unsigned char  c)

{

unsigned char  i;


for(i=0;i<8;i++)  /*要传送的数据长度为8位*/

    {

     if((c<       else  sda=0;               

     _nop_();

     scl=1;               /*置时钟线为高,通知被控器开始接收数据位*/

      _nop_();

      _nop_();             /*保证时钟高电平周期大于4μs*/

      _nop_();

      _nop_();

      _nop_();        

     scl=0;

    }


    _nop_();

    _nop_();

    sda=1;                /*8位发送完后释放数据线,准备接收应答位*/

    _nop_();

    _nop_();  

    scl=1;

    _nop_();

    _nop_();

    _nop_();

    if(sda==1)ack=0;   

       else ack=1;        /*判断是否接收到应答信号*/

    scl=0;

    _nop_();

    _nop_();

}


/*******************************************************************

                 字节数据接收函数              

函数原型: UCHAR  I2C_RcvByte();

功能:        用来接收从器件传来的数据,并判断总线错误(不发应答信号),

          发完后请用应答函数应答从机。

********************************************************************/   

unsigned char   I2C_RcvByte()

{

  unsigned char  retc=0,i;

  sda=1;                     /*置数据线为输入方式*/

  for(i=0;i<8;i++)

      {

        _nop_();         

        scl=0;                  /*置时钟线为低,准备接收数据位*/

        _nop_();

        _nop_();                 /*时钟低电平周期大于4.7μs*/

        _nop_();

        _nop_();

        _nop_();

        scl=1;                  /*置时钟线为高使数据线上数据有效*/

        _nop_();

        _nop_();

        retc=retc<<1;

        if(sda==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */

        _nop_();

        _nop_();

      }

  scl=0;   

  _nop_();

  _nop_();

  return(retc);

}


/********************************************************************

                     应答子函数

函数原型:  void Ack_I2c(bit a);

功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)

********************************************************************/

void Ack_I2c(bit a)

{

  if(a==0)sda=0;              /*在此发出应答或非应答信号 */

  else sda=1;                                                          /*0为发出应答,1为非应答信号 */

  _nop_();

  _nop_();

  _nop_();     

  scl=1;

  _nop_();

  _nop_();                    /*时钟低电平周期大于4μs*/

  _nop_();

  _nop_();

  _nop_();

  scl=0;                     /*清时钟线,住I2C总线以便继续接收*/

  _nop_();

  _nop_();   

}


/************************************************************

* 函数名        : Pcf8591_DaConversion

* 函数功能      : PCF8591的输出端输出模拟量

* 输入          : addr(器件地址),channel(转换通道),value(转换的数值)

* 输出                       : 无

******************* *****************************************/

bit Pcf8591_DaConversion(unsigned char addr,unsigned char channel,  unsigned char Val)

{

   Start_I2c();              //启动总线

   I2C_SendByte(addr);            //发送器件地址

   if(ack==0)return(0);

   I2C_SendByte(0x40|channel);              //发送控制字节

   if(ack==0)return(0);

   I2C_SendByte(Val);            //发送DAC的数值

   if(ack==0)return(0);

   Stop_I2c();               //结束总线

   return(1);

}


/************************************************************

* 函数名        : Pcf8591_SendByte

* 函数功能                            : 写入一个控制命令

* 输入          : addr(器件地址),channel(转换通道)

* 输出                       : 无

************************************************************/

bit PCF8591_SendByte(unsigned char addr,unsigned char channel)

{

   Start_I2c();              //启动总线

   I2C_SendByte(addr);            //发送器件地址

   if(ack==0)return(0);

   I2C_SendByte(0x40|channel);              //发送控制字节

   if(ack==0)return(0);

   Stop_I2c();               //结束总线

   return(1);

}


/************************************************************

* 函数名                     : PCF8591_RcvByte

* 函数功能                 : 读取一个转换值

* 输入          :

* 输出          : dat

************************************************************/

unsigned char PCF8591_RcvByte(unsigned char addr)

{

   unsigned char dat;


   Start_I2c();          //启动总线

   I2C_SendByte(addr+1);      //发送器件地址

   if(ack==0)return(0);

   dat=I2C_RcvByte();          //读取数据0


   Ack_I2c(1);           //发送非应答信号

   Stop_I2c();           //结束总线

   return(dat);

}

/*------------------------------------------------

[1] [2]
关键字:单片机  PCF8591  数字电压表 引用地址:单片机+PCF8591实现数字电压表

上一篇:51单片机简易电子称程序
下一篇:基于AT89S52单片机的电子密码锁

推荐阅读最新更新时间:2024-11-10 18:13

自制单片机之十三……时钟IC_DS1302
  在网上看了很久,发现初学者最有兴趣的就是DS1302时钟电路,也很自然,它是个做出来就让你觉得最实用的电路了,但实际上制做上并不简单,首先你要让你的显示部分(不管是数码管还是LCD)调试通过。然后把DS1302接好,调试正确了才能在成功显示时间和日期。下面我们就来说说DS1302的用法。   DS1302的图如下: iframe id="iframe_0.7592839787248522" src="data:text/html;charset=utf8,%3Cimg%20id=%22img%22%20src=%22http://hiphotos.baidu.com/txz01/pic/item/63ea1a54d0ab0a
[单片机]
pic单片机功耗问题的解决
最近一周一直在做pic单片机功耗问题。由于项目使用电池供电,所以功耗问题显得非常重要。根据数据手册以及网络上的资料,影响单片机功耗主要由以下几个因素: 1:所有I/O引脚保持为高阻输入高点平或低电平 2:关闭比较器和CVref(可编程偏上参考电压)、WTD、T1OSC、BOR(欠压复位)等 3:PORTB片内弱上拉 4:所有不用的模块全部关闭,在用到时再打开 5:MCLR引脚必须处于逻辑高电平 PIC单片机在执行SLEEP指令后进入睡眠省电模式。进入SLEEP模式后,主振荡停止,如果看门狗在烧写时打开了,看门狗定时器将被清并保持运行。I/O口,周边模块和内部RAM将保持原来状态,所以如果要求睡眠后有很低功耗,应该在进入
[单片机]
51单片机C语言教程(一) 建立第一个工程
  学习单片机实在不是件易事,一来要购买高价格的编程器,仿真器,二来要学习编程语言,还有众多种类的单片机选择真是件让人头疼的事。在众多单片机中51架构的芯片风行很久,学习资料也相对很多,是初学的较好的选择之一。51的编程语言常用的有二种,一种是汇编语言,一种是C语言。汇编语言的机器代码生成效率很高但可读性却并不强,复杂一点的程序就更是难读懂,而C语言在大多数情况下其机器代码生成效率和汇编语言相当,但可读性和可移植性却远远超过汇编语言,而且C语言还可以嵌入汇编来解决高时效性的代码编写问题。对于开发 周期 来说,中大型的软件编写用C语言的开发周期通常要小于汇编语言很多。综合以上C语言的优点,我在学习时选择了C语言。以后的教程也只是我在
[单片机]
51<font color='red'>单片机</font>C语言教程(一) 建立第一个工程
单片机复位电路
单片机复位电路, 以下是推荐用的几种典型复位电路, 其中图三图四都可作为延时复位电路。在待机状态下由于其它电路干扰引起的死机,可以在芯片没有播放语音时切断芯片电源,参考电路图如下
[模拟电子]
<font color='red'>单片机</font>复位电路
51单片机红外控制解码详解
红外遥控发射芯片采用PPM编码方式,当发射器按键按下后,将发射一组108ms的编码脉冲。遥控编码脉冲由前导码、8位用户码、8位用户码的反码、8位操作码以及8位操作码的反码组成。通过对用户码的检验,每个遥控器只能控制一个设备动作,这样可以有效地防止多个设备之间的干扰。编码后面还要有编码的反码,用来检验编码接收的正确性,防止误操作,增强系统的可靠性。前导码是一个遥控码的起始部分,由一个9ms的低电平(起始码)和一个4. 5ms的高电平(结果码)组成,作为接受数据的准备脉冲。以脉宽为0. 56ms、周期为1. 12ms的组合表示二进制的“0”;以脉宽为1. 68ms、周期为2. 24ms的组合表示二进制的“1”。如果按键按下超过108m
[单片机]
单片机PWM控制舵机由浅入深各模块源代码(单路与8路)
控制一个普通舵机单片机源程序如下: /********************************************************************** 该实验例程还是实现一个舵机在两个角度之间摆动。0度和90度 但定时器中断里的处理与前一节有所区别,目的是让大家更好的 理解下一节分时复用思想产生多路PWM 。是一个过渡实验例程。 ***********************************************************************/ #include STC15Fxxxx.H //STC15系列单片机 void delay(uint16
[单片机]
89C51单片机与1片ADC0809组成的数据采集系统编程实例
在1个由89C51单片机与1片ADC0809组成的数据采集系统中,ADC0809的8个输入通道的地址为7FF8H~7FFFH,试画出有关接口电路图,并编写出每隔1分钟轮流采集1次8个通道数据的程序,共采样50次,其采样值存入内RAM20H单元开始的存储区中。 图片1 参考程序如下: 0~7通道地址:fef8h~feffh ORG 000H LJMP MAIN ORG 0003H LJMP I_INT0 ORG 000BH LJMP I_T0 ORG 050H MAIN: MOV
[单片机]
89C51<font color='red'>单片机</font>与1片ADC0809组成的数据采集系统编程实例
GigaDevice发布多款基于ARM Cortex-M3内核的32位通用MCU
         领先的半导体供应商 GigaDevice ( 兆易创新 ) 日前在中国发布 14 款基于 ARM® Cortex TM -M3 内核的 GD32F103 系列 32 位通用 MCU 产品。目前,该系列产品已经开始提供样片。   GD32 系列 MCU 力争为用户带来优异的系统性能与灵活的应用体验,并在性价比上做得更为出众。为了给用户在研发时有更大的自由选择范围,全新的 GD32F103 产品线提供从 16KB 到 128KB 的 Flash 容量,并有 QFN36 , TQFP48 , LQFP64 和 LQFP100 多种封装选择。系列产品在软件和引脚封装方面全兼容。   GD
[手机便携]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved