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

1.利用单片机控制PCF8591AD转换,控制AD0AD1电位器,在数码光上显示DA转换的值。

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

 

以下代码将12实验合并成一个实验。

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 模数转换放大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

clip_image002

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的问题是关于嵌入式系统的不同模块的功能和作用。我可以解释一下每个模块的作用以及它们可以实现的功能。 1. GPIO (通用输入输出):GPIO是一种通用的数字输入/输出端口,它可以在嵌入式系统中实现各种不同的功能。使用GPIO,您可以控制外部设备的开关、读取传感器的数据、控制 LED 灯等等。 2. 中断:中断是一种机制,它可以在处理器执行某些任务时打断它,执行其他紧急任务,然后返回原来的任务。中断可以用于处理实时事件,例如按键操作、定时器事件等等。使用中断,您可以实现实时响应和高效处理事件的功能。 3. 定时计数器:定时计数器可以在嵌入式系统中实现时间相关的功能。使用定时计数器,您可以计算时间、测量时间间隔、触发定时器事件等等。 4. SPI (串行外设接口):SPI是一种串行通信协议,它可以用于连多个外设,例如存储器、传感器、显示器等等。使用SPI,您可以实现高速数据传输、异步通信、多设备连等功能。 5. IIC (I2C):IIC是一种串行通信协议,它可以用于连多个外设,例如存储器、传感器、显示器等等。使用IIC,您可以实现低速数据传输、同步通信、多设备连等功能。 6. AD (模拟输入):AD是一种模拟输入端口,它可以读取模拟信号并将其转换为数字信号。使用AD,您可以实现模拟信号采集、传感器数据读取等功能。 7. DA (模拟输出):DA是一种模拟输出端口,它可以输出数字信号并将其转换为模拟信号。使用DA,您可以实现模拟信号输出、控制执行器等功能。 以上是几个嵌入式系统中常用的模块及其功能介绍,您可以根据实际应用需求选择所需的模块来实现相应的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值