文章出處

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 模數轉換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

clip_image002


文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()