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

📄 i2c.c

📁 c8052的I2C子程序,比较实用可靠,我们使用的是C8051F020
💻 C
字号:
/*
*********************************************************************************************************
* Copyright (c) 2003, 
* All rights reserved.
* 
* 文件名称:i2c.c
* 文件标识:无
* 摘    要:
* 
* 当前版本:0.1
* 作    者:
* 完成日期:2006年5月10日
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 	
* 包含头文件	
* 	
*********************************************************************************************************
*/

//#include "c8051F020.h"
#include "i2c.h"

/*
*********************************************************************************************************
* 	
* 全局变量定义	
* 	
*********************************************************************************************************
*/

char COMMAND;                       // Holds the slave address + R/W bit for
                                    // use in the SMBus ISR.
char I2CDATA;                       // Holds data to be transmitted by the SMBus
                                    // OR data that has just been received.
char BYTE_NUMBER;                   // Used by ISR to check what data has just been
                                    // sent - High address byte, Low byte, or data
                                    // byte
unsigned char HIGH_ADD, LOW_ADD;    // High & Low byte for EEPROM memory address

bit SM_BUSY;                        // This bit is set when a send or receive
                                    // is started. It is cleared by the
                                    // ISR when the operation is finished.
/*
*********************************************************************************************************
* 
* 函数名称:void SM_Send (char chip_select, unsigned int byte_address, char out_byte)
*	
* 输入变量:out_byte 要发送的数据变量;byte_address 数据写入地址(16位);chip_select 要写入EEPROM的设备地址
* 
* 输出变量:无
* 
* 功能描述:在EEPROM的指定位置写单字节数据
*	
*********************************************************************************************************
*/
void SM_Send (char chip_select, unsigned int byte_address, char out_byte)
{
   while (SM_BUSY);                          // 等待总线空闲
   SM_BUSY = 1;                              // 占用总线(设置为忙)
   SMB0CN = 0x44;                            // 总线允许ACK循环
   BYTE_NUMBER = 2;                          // 16位地址
   COMMAND = (chip_select | WRITE);          // 芯片地址 + 写
   HIGH_ADD = ((byte_address >> 8) & 0x00FF);// 高8位地址
   LOW_ADD = (byte_address & 0x00FF);        // 低8位地址
   I2CDATA = out_byte;                          // 写数据
   STO = 0;
   STA = 1;                                  // 开始传送
}

/*
*********************************************************************************************************
* 
* 函数名称:char SM_Receive (char chip_select, unsigned int byte_address)
*	
* 输入变量:byte_address 数据读出地址(16位);chip_select 要读取的EEPROM的设备地址
* 
* 输出变量:返回指定地址所存储的数据
* 
* 功能描述:在EEPROM的指定存储位置读单字节数据
*	
*********************************************************************************************************
*/
char SM_Receive (char chip_select, unsigned int byte_address)
{
   while (SM_BUSY);                          // 等待总线空闲
   SM_BUSY = 1;                              // 占用总线(设置为忙)
   SMB0CN = 0x44;                            // 总线允许ACK循环
   BYTE_NUMBER = 2;                          // 16位地址
   COMMAND = (chip_select | READ);           // 芯片地址 + 读
   HIGH_ADD = ((byte_address >> 8) & 0x00FF);// 高8位地址
   LOW_ADD = (byte_address & 0x00FF);        // 低8位地址
	 STO = 0;
   STA = 1;                                  // 开始传送
   while (SM_BUSY);                          // 等待传送结束
   return I2CDATA;													 //	返回数据
}

/*
*********************************************************************************************************
* 
* 函数名称:void SMBUS_ISR (void)
*	
* 输入变量:无
* 
* 输出变量:无
* 
* 功能描述:I2C中断函数(中断号为 7,使用寄存器 3)
*	
*********************************************************************************************************
*/

void SMBUS_ISR(void) interrupt 7	using 3
{
	if(SI == 1)
	{
   switch (SMB0STA){              	   // I2C状态码 (SMB0STA 寄存器)
																			 // 主控模式 发送/接收: 开始条件传送
      																 // 在命令字中的读、写位操作时,无论读或者写此状态字必须为零
																	     // 必须先写存储地址
      case SMB_START:
         SMB0DAT = (COMMAND & 0xFE);   // 载入从地址
         STA = 0;                      // 手动清除开始位
         break;
      																 // 主控模式 发送/接收: 重复开始条件传送
      																 // 此状态只发生在读操作期间, 在存储地址和ACK信号送出之后
      case SMB_RP_START:
         SMB0DAT = COMMAND;            // 命令字 = 地址+读位
         STA = 0;
         break;
      																 // 主控制器传送: 从机地址 + 写传送.  ACK信号接收。
      case SMB_MTADDACK:
         SMB0DAT = HIGH_ADD;           // 载入被写入的地址高字节
         break;
																       // 主控制器传送: 从机地址 + 写传送.  NACK信号接收。
      																 // 从机无响应。停止后送出开始再次操作。
      case SMB_MTADDNACK:
         STO = 1;
         STA = 1;
         break;
																		   // 主控制器传送: 数据字节传送。  ACK 接收。
      																 // 这种状态读和写都会存在。检查存储地址状态-如果只送出地址高字节,载入地址低字节。
      																 // 如果地址低字节也被传送, 检查命令的读写位来决定下一个状态
      case SMB_MTDBACK:
         switch (BYTE_NUMBER){
            case 2:                    // 如果 BYTE_NUMBER=2, 只送出了地址高字节。
               SMB0DAT = LOW_ADD;      //
               BYTE_NUMBER--;          // 进入下一次
               break;
            case 1:                    //  如果 BYTE_NUMBER=1, 送出了地址低字节。
               if (COMMAND & 0x01){    // 如果 R/W=读, 重新开始
                  STO = 0;
                  STA = 1;

               } else { 
                  SMB0DAT = I2CDATA;     // 如果 R/W=写, 载入要写的字节
                  BYTE_NUMBER--;
               }
               break;
            default:                   // 如果 BYTE_NUMBER=0, 传送完成。
               STO = 1;
               SM_BUSY = 0;            // 释放总线。
               break;
            }
         break;
																       // 主控制器传送: 数据字节传送.  NACK信号接收。
      																 // 从机无响应。停止后送出开始再次操作。
      case SMB_MTDBNACK:
         STO = 1;
         STA = 1;
         break;
																			 // 主控制器传送:仲裁失败
      																 // 一般不会发生  如果有重新开始传送
      case SMB_MTARBLOST:
         STO = 1;
         STA = 1;
         break;
																		   // 主控制器接收: 从机地址 + READ 传送.  ACK 接收.
      																 // 最后一个字节后设置传送NACK。
      case SMB_MRADDACK:
         AA = 0;                       // NACK 发送
         break;
																			 // 主控制器接收: 从机地址 + READ 传送.  NACK 接收.
      																 // 从机无响应,重新开始重试
      case SMB_MRADDNACK:
         STO = 0;
         STA = 1;
         break;
																	     // 数据接收  ACK 传送.
      																 // 前一状态AA置零时本状态不会出现
      																 // 本状态出现时停止总线
      case SMB_MRDBACK:
         STO = 1;
         SM_BUSY = 0;
         break;
																		    // 数据字节接受.  NACK 发送.
      																	// 读操作完成.  读取数据寄存器并且停止总线.
      case SMB_MRDBNACK:
         I2CDATA = SMB0DAT;
         STO = 1;
         SM_BUSY = 0;                  // 释放总线
         break;
																		   // 这个应用中其他状态码是无意义的. 通讯过程复位.
      default:
         STO = 1;                      // 通讯过程复位.
         SM_BUSY = 0;
         break;
      }
   SI=0;                               // 清中断标志位
	}
}

⌨️ 快捷键说明

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