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

发布者:science56最新更新时间:2017-01-06 来源: eefocus关键字:IIC通讯 手机看文章 扫描二维码
随时随地手机看文章

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

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

 

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

Lab6.1

#include

#include

 

#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

#include

#include

 

#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<

       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

clip_image002


关键字:IIC通讯 引用地址:实验5 IIC通讯与AD/接DA接口

上一篇:实验4 IIC通讯与EEPROM接口
下一篇:实验6 LCD接口

推荐阅读最新更新时间:2024-03-16 15:29

STM8 AD转换
系统功能 大部分STM8内部带有AD,本节以使用STM8S105的内部AD为例,给出AD转换中断程序。    硬件设计 AD转换值低位,LED控制电路原理图 AD转换值高位,LED控制电路原理图 软件设计 /********************************************************************* 目标系统: 基于STM8单片机 应用软件: Cosmic CxSTM8 *********************************************************************/ #include stm8s207s8.h v
[单片机]
STM8 <font color='red'>AD</font>转换
低电压放大器AD8517
1 AD8517的主要特点 AD8517是AD公司生产的低电压放大器,它可在低至1.8V的电源电压下工作,由于它能在大多数普通电池的放电电压终止的情况下工作,所以这种放大器对于那些用电池供电的应用场合是很理想的。 AD8517在电源电压低于1.8V的情况下具有非凡的轨至轨输入和输出特性,在放大器的电源范围定到1.8V时,如果把共模电压定到1.8Vp-p,就能使输出摆到电源的上下轨迹上而不会出现削波现象。 AD8517可以在给定的从1.8V到5V的全部电源电压范围内获得良好的轨至轨特性。AD8517低电压放大器还具有很低的总谐波失真,这使得该放大器在音频应用方面也很理想。在同相组态下,当增益为1时,对于Vs 3V的情况,
[应用]
基于AD7896的激光器出射功率测量与控制设计
0 引 言 现代数码激光彩色冲印系统是将存储在计算机中含有光电信号的图像信息转换成激光束控制信号,分别控制R,G,B三支半导体激光器发出不同强度的激光束,再会聚成各种色彩对感光相纸进行逐行扫描而成像。虽然半导体激光器所发出的激光具有单色性好,方向性好,发射角小,输出功率大,工作稳定,寿命长,使用方便等众多优点;但激光作为现代数码彩色冲印系统中感光相纸的光源,每一支半导体激光器都会受周围温度变化和本身寿命等的影响,这种影响会直接反映到所冲印彩色照片的色彩层次、轮廓、清晰度、鲜艳度等。为了有效防止半导体激光器出射光功率的变化对冲印照片造成的色彩失真,提高冲印照片的色彩纯真度,通过自动测量并自动控制R,G,B三支半导体激光器的出射功
[单片机]
基于<font color='red'>AD</font>7896的激光器出射功率测量与控制设计
PADS、AD、Allego、Protel等几款硬件设计EDA工具全面对比,哪款最适合你?
  EDA工具层出不穷,目前进入我国并具有广泛影响的EDA软件有:EWB、PSPICE、OrCAD、PCAD、Protel、ViewLogic、Mentor、Graphics、Synopsys、LSIlogic、Cadence、MicroSim等等。这些工具都有较强的功能,一般可用于几个方面,例如很多软件都可以进行电路设计与仿真,同时以可以进行PCB自动布局布线,可输出多种网表文件与第三方软件接口。下面就随嵌入式小编一起来了解一下相关内容吧。   而在论坛里经常能看到新手的经典提问:我应该学习哪种画图工具呀?哪种画图工具更强大?哪种画图工具更好用?网上关于各种工具功能介绍的资料多如牛毛,EDA工具本身又包含很多版本和独立功能的
[嵌入式]
基于ADμC7024在医疗电子中的应用
0 引言 随着信息技术的迅猛发展和人民生活水平的提高,极大地推动了医疗电子设备的发展,当今医疗电子设备的发展趋势是高精度、实时性、低功耗和小尺寸,作为医疗电子设备中核心地位的MCU(微处理器)也随着这一发展趋势向前不断衍变着。由早期的8位MCU发展到目前的32位RISC(精简指令集计算机)MCU。美国ADI公司根据市场的需要最新推出了一款基于ARM(高级精简指令集计算机)核的微处理器ADμC7024便是目前32位RISC MCU的杰出代表。ADμC7024卓越的处理能力、集成众多片上外围器件和芯片低功耗的特点,完全胜任目前医疗电子设备的需求及未来的发展目标。 本文以ADμC7024在医疗电子中监护产品脉搏血氧计的应
[单片机]
基于<font color='red'>AD</font>μC7024在医疗电子中的应用
STM32F0两路AD配置参考
使用两路PA.1 (ADC Channel 1) 和 PA.4 (ADC Channel 4),配置方式如代码所示。使用的芯片是STM32F030C8。 需定义两个变量 static __IO uint16_t RegularConvertedAdcValue ; // ADC1转换的电压值通过MDA方式传到flash static float AdcValueConvertToVoltage; // 局部变量,用于存从flash读到的电压值 然后上电初始化时调用 void ADCD_Init(void) { GPIO_Config(); DMA_Config(); ADC_Config();
[单片机]
PIC8引脚带A/D的单片机的特点
  PIC 8引脚带A/D的单片机12C6和12CE6系列是Microchip公司生产的一类PIC 8位单片机,其产品型号是12C671/672和12CE673/674,它们是PIC单片机中级型产品之一,其引脚功能如附图所示。   该类产品是一种8引脚带4路8位A/D转换器的超小型产品,是目前性价比极高的8位OTP(一次编程不可擦除)单片机。由于它们体积小巧,所以可嵌入几乎任何一种电子产品中,特别是便携式电子产品,如IC卡、充电器、计时器、智能传感器和儿童玩具等等都已广泛地应用了。   PIC12C6和12CE6系列单片机之间的差别,仅后者产品内部硬件带有E2PROM的数据存储器(16×8),它们的其它性能几乎完全
[单片机]
PIC8引脚带A/D的单片机的特点
CBFET运放AD843及其在阻抗匹配电路中的应用
    摘要: 介绍了CBFET(互补双极型场效应管)运算放大器AD843的主要功能特点及其在阻抗匹配电路中的应用。并通过几种阻抗匹配电路的比较说明了该芯片的独特性和优越性,最后给出了AD843的一个应用实例。     关键词: CBFET 运算放大器 阻抗匹配 AD843 在电路设计中的许多情况下需要进行阻抗匹配变换,以适应各种芯片或元件间的匹配。传统的阻抗匹配由分立器件组成,因而电路干扰大、调试麻烦、开发周期长并且维护困难。而一些运放集成芯片由于本身在结构上的设计局限(如频带宽度,输入偏置电路等),远远不能满足较宽频带和精确匹配的要求。CBFEY(互补双级型场效应管)运算放大器AD843却能以其独特的
[半导体设计/制造]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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