⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2cm_drv.c

📁 st7 单片机模拟I2C软件包 对没有I2C总线的单片机需要I2C功能非常有用
💻 C
字号:
/**************** (c) 2003  STMicroelectronics ********************************

PROJECT  : EVALUATION BOARD - ST7 I2C DEMO SYSTEM
COMPILERS : COSMIC AND METROWERKS 
MODULE  :  i2cm_drv.c
REVISION DATE :  12/06/03
AUTHOR : Micro Controller Division Application  Team

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

    THE SOFTWARE INCLUDED IN THIS FILE IS FOR GUIDANCE ONLY. STMicroelectronics 
    SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL 
    DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM USE OF THIS SOFTWARE.

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

DESCRIPTION :   ST7 I2C single master T/R peripheral software driver.
               
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

MODIFICATIONS :

  27/08/98  - V1.0  - First version (error management:AF).
  12/06/03  - V1.1  - 1) Compatibility With Cosmic And Metrowerks.
                      2) Generation Of Non - Ack. 
                      3) Update for st72324      

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

#pragma NO_STRING_CONSTR

#define SDA     6
#define SCL     7

/* EXTERNAL DECLARATIONS *****************************************************/
/* List of all the variables defined in another module and used in this one. */
/* MODEL => #include {file_name}.h                                           */
#include "map72324.h"                 /* Declaration of the I2C HW registers.*/
#include "lib_bits.h"                      /* Bit handling macro definitions.*/
#include "variable.h"

/* FUNCTION DESCRIPTIONS *****************************************************/
/* Description of all the functions defined in this module.                  */
/* MODEL => [static] type_name var_name;  or #define                         */


void delay (unsigned char time)
{
     #ifdef __HIWARE__
     asm
     {
          nop               /* Time is stored on the Accumulator automatically */
          again:  DEC     A        /* When the function is called.             */
          JRNE    again            /* (15+6*time) clock cycles                 */
     }                
     #else
     #ifdef __CSMC__
     {
          _asm ("nop");
          _asm("again: DEC A");
          _asm(" JRNE again");
     }
     #endif
     #endif
}
       
/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_Start
INPUT/OUTPUT : None.
DESCRIPTION  : Generates I2C-Bus Start Condition.
COMMENTS     :
-----------------------------------------------------------------------------*/ 
void I2Cm_Start (void)
{
    ClrBit(PADDR,SDA);     
             /* Configure SDA and SCL as floating input to have a high state */
    ClrBit(PADDR,SCL);
    delay(10);
    SetBit(PADDR,SDA); 
                   /* Configure SDA as output open drain to have a low state */
    delay(4);
     /* Waits 39 cycles=4.875祍 at a Fcpu=8MHz to keep the high state on SCL */
    SetBit(PADDR,SCL);
                   /* Configure SCL as output open drain to have a low state */
    delay(6);      /* Delay to wait after a START                            */
} 

/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_Stop
INPUT/OUTPUT : None.
DESCRIPTION  : Generates I2C-Bus Stop Condition.
COMMENTS     :
-----------------------------------------------------------------------------*/
void I2Cm_Stop (void)    
{
     SetBit(PADDR,SDA);   
           /* Configure SDA and SCL as output open drain to have a low state */
     SetBit(PADDR,SCL);
     ClrBit(PADDR,SCL); 
           /* Configure SCL as floating input to have a high state           */
     delay(4);              /* Macro delay with time=4 (4.875 祍)            */
     ClrBit(PADDR,SDA); 
           /* Configure SDA as floating input to have a high state           */  
           /* Delay after the Stop did in main.c with Wait_1ms()             */
} 

/*-----------------------------------------------------------------------------
ROUTINE NAME : wait_Ack
INPUT/OUTPUT : None.
DESCRIPTION  : Acknowledge received?
COMMENTS     : Transfer sequence = DATA, ACK.
-----------------------------------------------------------------------------*/ 
void wait_Ack (void)
{       
     SetBit(PADDR,SCL);             /* Output open drain to have a low level */
     ClrBit(PADDR,SDA);     /* Floating input, the slave has to pull SDA low */
     delay(1);
     if (ValBit(PADR,SDA))         /* Test of SDA level, if high -> pb       */
     { 
          SetBit(I2C_SR2,AF);
          ClrBit(I2C_SR1,ACK);
          return;
     }
     delay(2);
     if (ValBit(PADR,SDA))         /* Test of SDA level, if high -> pb       */
     {
          SetBit(I2C_SR2,AF);
          ClrBit(I2C_SR1,ACK);
          return;
     }
     delay(5);
     ClrBit(PADDR,SCL);          /* Start of the generation of 1 clock pulse */ 
          delay(1);
     if (ValBit(PADR,SDA))        /* Test of SDA level, if high -> pb        */
     { 
          SetBit(I2C_SR2,AF);
          ClrBit(I2C_SR1,ACK);
          return;
     }
     delay(1);
     if (ValBit(PADR,SDA))         /* Test of SDA level, if high -> pb       */
     {
          SetBit(I2C_SR2,AF);
          ClrBit(I2C_SR1,ACK);
          return;
     }     
     delay(1);
     SetBit(PADDR,SCL);            /* End of the clock pulse                 */
     SetBit(I2C_SR1,ACK);
     delay(1);
     ClrBit( PADR, SDA);
     SetBit(PADDR,SDA);   
          /* Reconfigure SDA as output to proceed at the next transmission   */         
} 

/*-----------------------------------------------------------------------------
ROUTINE NAME : I2C_nAck
INPUT/OUTPUT : None.
DESCRIPTION  : Non acknoledge generation from now.
COMMENTS     : Transfer sequence = DATA, NACK.
-----------------------------------------------------------------------------*/ 
void I2C_nAck (void)
{
     ClrBit(I2C_SR2,ACK);    /* Non acknoledge when the master is receiver   */            
     SetBit(PADR,SDA);       /* The master pulls the SDA line high           */ 
     SetBit(PADDR,SCL);      /* Output open drain to have a low level        */
     delay(10);
     ClrBit(PADDR,SCL);      /* The master generates a clock pulse           */ 
     delay(10);
     SetBit(PADDR,SCL);      /* Clock pulse complete                         */
     ClrBit(PADR,SDA);       /* The master pulls the SDA line high           */         
     delay(3);
        
 } 

/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_Init
INPUT/OUTPUT : None.
DESCRIPTION  : I2C peripheral initialisation routine.
COMMENTS     : Contains inline assembler instructions in C like mode !
-----------------------------------------------------------------------------*/ 
void I2Cm_Init (void)
{
     count=0;
     I2C_SR1=0;
     I2C_SR2=0;
     I2C_DR=0;
     err_status=0;
     t_count_err=0;
     r_count_err=0;
     SetBit(I2C_SR1,M_SL);   /* Master mode: M_SL=1                          */
} 


/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_TxData
INPUT/OUTPUT : data byte to be transfered(MSB first) / None.
DESCRIPTION  : Transmits a data bit.
COMMENTS     : Transfer sequence = DATA, ACK, ...
-----------------------------------------------------------------------------*/ 
void I2Cm_TxData (void)
{
     SetBit(PADDR,SCL);              /* Low level on SCL                     */
     if (I2C_SR2)                    /* Check the communication error status */
     {
          err_status++;
          t_count_err++;
          if (t_count_err==0) t_count_err++;
     }
     else                             /* If  no error                        */
     {       
          if (ValBit(I2C_DR,7))       /* Send data bit per bit, MSB first    */
               SetBit(PADR,SDA);      /* Send a one                          */
          else
               ClrBit(PADR,SDA);      /* Send a zero                         */
          
          I2C_DR*=2;
          ClrBit(PADDR,SCL);          /* High state on SCL                   */
          delay(10);        
     }    
}    

/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_RxData
INPUT/OUTPUT : Last byte to receive flag (active high) / Received data bit.
DESCRIPTION  : Receive a data byte.
COMMENTS     : Transfer sequence = DATA, ACK, EV7...
-----------------------------------------------------------------------------*/ 
void I2Cm_RxData (void)
{
     if (!I2C_SR2)          /* No communication error detected               */
     {
          buff*=2;          /* Shift I2C_DR to receive next bit              */

          #ifdef __HIWARE__
          asm
          {
               nop
               nop
               nop
          }                
          #else
          #ifdef __CSMC__
          {
                _asm("nop");
                _asm("nop");
                _asm("nop");        
          }
          #endif
          #endif
                
          ClrBit(PADDR,SCL);          /* Rise the SCL line                   */
          do{
          }while(ValBit(PADR,SCL)!=0);      /* Wait SCL at a high state      */
          if(ValBit(PADR,SDA))  
               buff|=1;               /* The received bit is 1               */
          else     
               buff|=0;               /* The received bit is 0               */
          delay(10);
          SetBit(PADDR,SCL);          /* SCL at a low level                  */ 
     }
     else
          r_count_err++;
}


/*-----------------------------------------------------------------------------
ROUTINE NAME : I2C_Ack
INPUT/OUTPUT : None.
DESCRIPTION  : Send Ack to the slave.
COMMENTS     : 
-----------------------------------------------------------------------------*/ 
void I2C_Ack(void)
{
     ClrBit(PADR,SDA);           /* The master pulls the SDA line low        */ 
     SetBit(PADDR,SDA);
     delay(10);
             
     ClrBit(PADDR,SCL);         /* Waits the master takes the control of SDA */
     delay(10);
                     
     SetBit(PADDR,SCL);
     delay(5);
     
     ClrBit(PADDR,SDA);         /* The master releases the SDA line          */
     SetBit(I2C_SR1,ACK);       /* ACK=1: Acknowledge sent by the master     */
        
}        

        
/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_Tx
INPUT/OUTPUT : send_tab and n, the number of data to transmit (with 2 addresses)
               / None.
DESCRIPTION  : Transmit data buffer.
COMMENTS     : Most significant bytes first.
-----------------------------------------------------------------------------*/ 
void I2Cm_Tx (char * buffout,char nb)
{
     SetBit(PADDR,SDA);         /* Configure SDA as an output to send data   */
     for (j=nb;j!=0xFF;j--)  
     {          /* 2 addresses and 3 data to send: from X=n downto X=0       */
          flag=0;
          if ((j==(nb-2))&&(ValBit(I2C_SR1,RCPT)))
          {                
               I2Cm_Start();       /* Start condition                        */
               j=nb;               /* EEPROM @ with the LSB at 1 to send     */
               flag=1;
          }
          count=1;
          I2C_DR=buffout[j];
          if (flag==1) I2C_DR=I2C_DR|1; 
                      /* If master receiver, the address to send is A1       */
          do
          {       
               I2Cm_TxData();    /* Sending of data bit per bit, MSB first   */        
	       count*=2;
          }while(count!=0);
          wait_Ack();                  /* Wait ACK from the slave            */
          if(!ValBit(I2C_SR1,ACK))
               SetBit(I2C_SR2,AF);
          if (flag==1) return;            
                 /* If master receiver, go back to I2Cm_Rx() to receive data */
        }
}

/*-----------------------------------------------------------------------------
ROUTINE NAME : I2Cm_Rx
INPUT/OUTPUT : @ reception buffer + n-2 data/ None.
DESCRIPTION  : Receive in data buffer via I2C.
COMMENTS     : Most significant bytes first.
-----------------------------------------------------------------------------*/ 
void I2Cm_Rx (char *buffin,char nb)
{
     SetBit(I2C_SR1,RCPT);             /* Master in receiver mode            */
     I2Cm_Tx(send_tab,nb);             /* Send the addresses and wait ACK    */
     if (ValBit(I2C_SR2,AF)) return;  
                 /* If AF -> go back to main and restart the reception       */   
     for (j=nb-2;j!=0xFF;j--)
     {
          count=1;
          buff=0;
          ClrBit(PADDR,SDA);                 
                     /* SDA as floating input to read data from the EEPROM   */
          do
          {
               I2Cm_RxData();          /* Read data bit per bit, MSB first   */
	       count*=2;
          }while(count!=0);
          I2C_DR=buff;
          SetBit(PADDR,SDA);           /* Configure SDA as output            */   
          if (j==0)
               I2C_nAck();  
                     /* Non acknowledge to make the master generate the STOP */
          else
               I2C_Ack();               /* To acknowledge read data          */                
              
          buffin[j]=I2C_DR;             /* Store read data into buffin       */
     }
        
}

/******************* (c) 2003  STMicroelectronics ************ END OF FILE ***/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -