📄 i2c.c
字号:
#include <c8051f020.h>
//------------------------------------------------------------------------------------
// Global CONSTANTS
//------------------------------------------------------------------------------------
#define WRITE 0x00 // SMBus WRITE command
#define READ 0x01 // SMBus READ command
//SMBus状态:MT=主发送器;MR=主接受器
#define SMB_BUS_ERROR 0x00 // (所以模式)总线错
#define SMB_START 0x08 // (主发送器和主接受器)开始条件已发送
#define SMB_RP_START 0x10 // (主发送器和主接受器)重复开始条件已发送
#define SMB_MTADDACK 0x18 // (主发送器)从地址+W 已发送,收到ACK
#define SMB_MTADDNACK 0x20 // (主发送器)从地址+W 已发送,收到NACK
#define SMB_MTDBACK 0x28 // (主发送器)数据字节已发送,收到ACK
#define SMB_MTDBNACK 0x30 // (主发送器)数据字节已发送,收到NACK
#define SMB_MTARBLOST 0x38 // (主发送器)竞争失败
#define SMB_MRADDACK 0x40 // (主接受器)从地址+R已发送,收到ACK
#define SMB_MRADDNACK 0x48 // (主接受器)从地址+R已发送,收到NACK
#define SMB_MRDBACK 0x50 // (主接受器)数据字节已收到,ACK已发出
#define SMB_MRDBNACK 0x58 // (主接受器)数据字节已收到,NACK已发出
//--------------------------------------------------------------------
//全局变量
//--------------------------------------------------------------------
unsigned char COMMAND; // 在SMBus 中断服务程序中用于
// 保存从地址+ R/W 位。
unsigned char *I2CDataBuff; // 保持SMBus 要发送的数据字节
// 或刚收到的数据
unsigned char NByte; // 数据字节数
// 高地址字节、低地址字节或数据字节
unsigned char HIGH_ADD, LOW_ADD;// EEPROM 存储器地址的高、低字节
bit SM_BUSY; // 该位在发送或接收开始时被置1,
// 操作结束后由中断服务程序清0
bit Attrib; // 地址字节数 1为双字节,0为单字节
//------------------------------------------------------------------------------------
// Function PROTOTYPES
//------------------------------------------------------------------------------------
void SMBus0_Init(void)
{
SMB0CN = 0x44; // 允许SMBus 在应答周期发送ACK
SMB0CR = -80; // SMBus 时钟频率= 100kHz.
EIE1 |= 2; // SMBus 中断允许
EA = 1; // 全局中断允许
SM_BUSY = 0; // 为第一次传输释放SMBus。
}
// SMBus 中断服务程序
void SMBUS_ISR (void) interrupt 7
{
// SMBus 状态码(SMB0STA 寄存器)
switch (SMB0STA)
{
// 主发送器/接收器:起始条件已发送
// 在该状态发送的COMMAND 字的R/W 位总是为0(W),
// 因为对于读和写操作来说都必须先写存储器地址。
case SMB_START:
SMB0DAT = (COMMAND & 0xFE); // 装入要访问的从器件的地址
STA = 0; // 手动清除START 位
break;
// 主发送器/接收器:重复起始条件已发送。
// 该状态只应在读操作期间出现,在存储器地址已发送并得到确认之后
case SMB_RP_START:
SMB0DAT = (COMMAND | 0x01); // COMMAND 中应保持从地址 + R.
STA = 0;
break;
// 主发送器: 从地址+ WRITE 已发送,收到ACK。
case SMB_MTADDACK:
SMB0DAT = HIGH_ADD;
break;
// 主发送器: 数据字节已发送 收到ACK
case SMB_MTDBACK:
if( Attrib ) // 如果为 2 字节地址
{
Attrib = 0; // 清标志位
SMB0DAT = LOW_ADD; // 发低字节地址
break;
}
else if( COMMAND & 0x01 ) // 如果为读操作
{
STA = 1; // 重复起始条件
break;
}
else if( NByte ) // 如果未写完数据,继续写直到NByte=0;
{
SMB0DAT = *I2CDataBuff;
I2CDataBuff++;
NByte--;
break;
}
else
{
STO = 1;
SM_BUSY = 0;
}
break;
// 主发送器 从地址 + WRITE 已发送 收到NACK
// 从器件不应答发送STOP + START 重试
case SMB_MTADDNACK:
// 主发送器 数据字节已发送 收到NACK
// 从器件不应答发送STOP + START 重试
case SMB_MTDBNACK:
// 主发送器竞争失败
// 不应出现如果出现重新开始传输过程
case SMB_MTARBLOST:
STO = 1;
STA = 1;
break;
// 主接收器从地址 + READ 已发送,收到ACK
case SMB_MRADDACK:
AA = 1; // 在应答周期ACK
if (!NByte)
{
STO = 1;
SM_BUSY = 0; // 释放SMBus
}
break;
// 主接收器从地址 + READ 已发送收到NACK
// 从器件不应答发送重复起始条件重试
case SMB_MRADDNACK:
STA = 1;
break;
// 收到数据字节ACK 已发送
// 该状态不应出现因为AA 已在前一状态被清0 如果出现发送停止条件
case SMB_MRDBACK:
if ( NByte )
{
*I2CDataBuff = SMB0DAT;
I2CDataBuff++;
NByte--;
}
if (!NByte)
AA= 0;
break;
// 收到数据字节 NACK 已发送
// 读操作已完成读数据寄存器后发送停止条件
case SMB_MRDBNACK:
STO = 1;
SM_BUSY = 0; // 释放SMBus
break;
// 在本应用中所有其它状态码没有意义通信复位
default:
STO = 1; // 通信复位
SM_BUSY = 0;
break;
}
SI=0; // 清除中断标志
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -