📄 i2c.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 + -