实验5 IIC通讯与AD/接DA接口

1.利用单片机控制PCF8591的AD转换,控制AD0和AD1电位器,在数码光上显示DA转换的值。

2.利用单片机控制PCF8591的DA转换,让发光二极管D1由暗到亮变化,整个过程时间差不多2s左右,再由亮到暗变化,循环变化。

 

以下代码将1、2实验合并成一个实验。

Lab6.1

#include<reg51.h>

#include <I2C.H>

 

#define  PCF8591 0x90    //PCF8591 地址

#define uchar unsigned char

#define uint unsigned int

#define ulong unsigned long

 

 

 

//=========全局变量区============================================

unsignedchar AD_CHANNEL;

unsignedint  D[5];

        

sbit high=P2^4;

sbit mid=P2^3;

sbit low=P2^2;

uint code NumTable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//数字的编码

 

 

//=========全局变量区结束========================================

 

 

 

 

//=========函数区============================================

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

    延时

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

void delay_1ms(uint x){

    uint i=x;

    uint j;

    for(;i>0;--i){

       for(j=110;j>0;--j);

    }

}

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

    在数码管上显示对应的值

参数说明:

  Num 要显示的数字

  withDot 是否带点,如果要带点的话,那么传入0x80。不带点,传入0

 

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

void display(uchar Num,uchar withDot)

{

 

    P0=NumTable[Num]|withDot;

    delay_1ms(1);

    P0=0;      //送完段选信号后,进行消影的处理

}

 

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

    控制数码管显示,并分解计数值

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

void DisplayNumByOrder(uint left,uint right){

       low=0; mid=0; high=0;  display(left%10000/1000,0);         //left

        low=1; mid=0; high=0;  display(left%1000/100,0);               

        low=0; mid=1; high=0;  display(left%100/10,0x80);

       low=1; mid=1; high=0;  display(left%10,0);

                                             //right

       low=0; mid=0; high=1;  display(right%10000/1000,0);

       low=1; mid=0; high=1;  display(right%1000/100,0);

       low=0; mid=1; high=1;  display(right%100/10,0x80);

       low=1; mid=1; high=1;  display(right%10,0);

}

 

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

DAC 变换, 转化函数              

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

bit DACconversion(unsignedchar sla,unsignedchar c,  unsignedchar Val)

{

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址

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

   SendByte(c);              //发送控制字节

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

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

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

   Stop_I2c();               //结束总线

   return(1);

}

 

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

ADC发送字节[命令]数据函数              

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

bit ISendByte(unsignedchar sla,unsignedchar c)

{

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址

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

   SendByte(c);              //发送数据

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

   Stop_I2c();               //结束总线

   return(1);

}

 

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

ADC读字节数据函数              

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

unsignedchar IRcvByte(unsignedchar sla)

{  unsignedchar c;

 

   Start_I2c();          //启动总线

   SendByte(sla+1);      //发送器件地址

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

   c=RcvByte();          //读取数据0

 

   Ack_I2c(1);           //发送非就答位

   Stop_I2c();           //结束总线

   return(c);

}

 

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

main()

{ 

     while(1)

     {

       /********以下AD-DA处理*************/ 

       //因为PCF8591读取的是前一个时刻AD转换的值,所以读取的值在第5个时钟才是正常的值,相当于

       //swith经历了一轮case 0~4后,程序里面读取到的AD转换的值才是正常的。

       switch(AD_CHANNEL)    // A/D信道,通过这个函数,4个信道的数值都能读到

       {

            case0: ISendByte(PCF8591,0x41);

                   D[0]=IRcvByte(PCF8591)*2;  //ADC0 模数转换1  放大2倍显示

                   break; 

        

            case1: ISendByte(PCF8591,0x42);

                   D[1]=IRcvByte(PCF8591)*2;  //ADC1  模数转换2

                   break; 

 

            case2: ISendByte(PCF8591,0x43);

                   D[2]=IRcvByte(PCF8591)*2;  //ADC2  模数转换3

                   break; 

 

            case3: ISendByte(PCF8591,0x40);

                   D[3]=IRcvByte(PCF8591)*2;  //ADC3   模数转换4

                   break; 

            case4: DACconversion(PCF8591,0x40, D[4]);//DAC  数模转换

               break;

       }

              D[4]=D[0];  //   把模拟输入采样的信号通过数模转换输出,最终改变灯泡亮度

       if(++AD_CHANNEL>4) AD_CHANNEL=0;

       DisplayNumByOrder(D[0],D[1]);//将AD的值送到LED数码管显示

     } 

}

 

//=========函数结束区============================================

 

 

 

 

/*************************此部分为I2C总线的驱动程序*************************************/

I2c.c

#include<reg51.h>

#include <intrins.h>

#include <I2C.H>

 

#define  NOP()   _nop_()   /* 定义空指令 */

#define  _Nop()  _nop_()   /*定义空指令*/

 

 

sbit     SCL=P2^1;       //I2C  时钟

sbit     SDA=P2^0;       //I2C  数据

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

  

 

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

                     起动总线函数              

函数原型: 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  SendByte(UCHAR c);

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

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

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

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

void  SendByte(unsignedchar  c)

{

 unsignedchar  BitCnt;

 

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

    {

     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/

       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  RcvByte();

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

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

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

unsignedchar   RcvByte()

{

  unsignedchar  retc;

  unsignedchar  BitCnt;

 

  retc=0;

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

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

      {

        _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;

  _Nop();

  _Nop();

  _Nop();     

  SCL=1;

  _Nop();

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

  _Nop();

  _Nop();

  _Nop(); 

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

  _Nop();

  _Nop();   

}

 

 

 

 

I2c.h

作者:kissazi2 
出处:http://www.cnblogs.com/kissazi2/ 
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载:http://www.cnblogs.com/kissazi2/p/3174446.html

时间: 2024-08-07 12:24:03

实验5 IIC通讯与AD/接DA接口的相关文章

实验4 IIC通讯与EEPROM接口

1.       用C语言编程,利用定时器产生一个0~99秒变化的秒表,并且显示在数码管上,每过一秒将这个变化写入实验板上AT24C02,当关闭实验板电源,并再次打开实验板电源时,单片机从AT24C02中将原来写入的数据读出来,接着继续变化在数码管上.   #include<reg51.h> #define uchar unsigned char #define uint unsigned int   //=========全局变量区==============================

单片机系列学习

有感于我做单片机实验的时候,在网上找的参考代码老是写得很糟糕又或者排版很丑,所以我决定将自己做单品机实验的源代码全部放出.另外,因为公布了题目和答案,也希望老师不要以这些千百年不变的题目作为课程的作业了.请看到本文的老师思考一下怎么将课程练习和实际的项目开发结合起来,因为没有人喜欢写那种没有实际应用价值的代码;请思考一下怎么通过实验来激发学生的兴趣,而不是动辄以学分威逼学生去完成课程作业. 以下篇章中的代码有如下的特点: 1.注释多,因为这是面向初学者的,所以代码的注释中包含了很多相关的知识点,

如何将AD 2012林和域级别降级

我们知道,AD 活动目录默认是不能降级的,例如2003的级别提升到2008的级别,是一个不可逆的操作.但是在Windows Server 2008 R2和Windows Server 2012,我们可以将林级别和域级别从2012降级到2008R2, 又或者从2008 R2降级到2008. 当然,我们不能将它再降到更低的级别,例如 2003级别. www.2cto.com 我们可以用Powershell 来添加AD 管理模块,完成以下的实验. 1. 导入AD 管理模块 Import-Module

容联:企业通讯的颠覆者

(容联云通讯CEO孙昌勋揭晓C轮融资金额) 如今,逐渐变冷的资本市场对于那些2VC公司无疑是寒冬刺骨,而对于踏实做实业的公司却好似春天.7月5日,企业通讯云服务商容联云通讯(以下简称"容联")宣布完成了7000万美元的C轮融资,由红杉资本中国基金领投,跟投方包括挚信资本以及新的国际战略投资方. 此前,容联在2013年获得了红杉资本400万美元的A轮融资, 然后又在2015年拿到了挚信资本1500万美元的B轮融资. 为什么这一次A轮和B轮的投资方又接着下大注呢?老冀认为,很关键的就是容联

作为一个云服务提供商,亲加通讯云能为开发者带来怎样的收益?

在通讯云领域,亲加可谓是一个老兵了,从 成立之初,亲加通讯云就一直致力于多媒体通讯领域的耕耘,积累了诸多的技术基础及经验.伴随着移动互联网及云服务的兴起,亲加通讯云瞄准了移动App内社交.聊天的刚需,通过云服务的模式,快速.简便的将多媒体通讯功能提供给开发者,让开发者能够快速为自己的App添加应用内的用户间单聊.群聊.对讲机.实时语音聊天等功能,从而助力App社交化. 如果一个开发者自己动手为应用搭建聊天.通讯的功能,至少需要2.3个月才能完成.而下载亲加通讯云的相关API接口或SDK开发包,可

“容联云通讯”宣布完成B轮投资,估值1亿美元

1月22日消息 云通讯开放平台"容联云通讯"今日宣布,已获得挚信资本独投的1500万美元B轮融资,估值超过1亿美元.据了解,本轮融资于2014年12月完成. 容联云通讯总经理孙昌勋表示,融资后将加大对基础平台资源和技术的投入:另一方面,也会加紧构建开发者生态圈步伐,提高对开发者的项目扶持力度. 容联云通讯常务副总经理韩冬透露,当前API模式大部分由云端提供,对于企业或者创业团队来说,初期投入门槛较低. 目前,容联云通讯拥有8万余名开发者和6000余家企业合作伙伴.通过API接入容联云通

Linux下使用socktop来检测socket的通讯状况

所有的socket通讯都是通过socket接口来的,任何family的通讯包括unix域套接都要走的,所以只要截获了socket 读写的几个syscall 就可以了解unix域套接字的发送和接受情况.systemtap发行版本提供了个工具socktop, 位于 /usr/share/doc/systemtap/examples/network/socktop, 是个非常方便的工具, 干这个事情最合适了.安装为了部署 SystemTap,需要安装以下两个 RPM 包: 代码如下:systemtap

《 Python树莓派编程》——导读

Preface 前 言 在2006年,当Eben Upton和其他树莓派基金会的创办人看到大学计算机专业学生的编程状况时,他们感到无比沮丧.在美国,计算机专业的编程课程被缩减为"CS 101:如何使用Word程序"和"CS 203:优化你的Facebook主页".他们意识到,不是所有人在上大学之前都学过编程.因此,他们酝酿了一个计划--打造一种小型廉价的计算机,使孩子们可以更加方便地学习编程,就如同昔日的Amiga.Spectrum和Commodore 64.随后,

杏林同学录(四)

个人管理:    班级通讯录:class/address.php <? session_start(); // 开始session if(!session_is_registered("userregister")||($userregister==""))//检查是否注册,如userregister未注册或session为空值,重新注册. { echo "<a href='../index.php'>请重新注册<BR>&qu