📄 i2c.c
字号:
//I2C
#include "C8051F000.h"
#define uchar unsigned char
#define uint unsigned int
//--------------------------------------------------------------------
// 全局常量
//--------------------------------------------------------------------
#define WRITE 0x00 // SMBus 写命令
#define READ 0x01 // SMBus 读命令
// 器件地址(7位,最低位没使用)
#define CHIP_A 0xA0 // 芯片A的器件地址
#define CHIP_B 0xA2 // 芯片B的器件地址
#define CHIP_C 0xA4 // 芯片C的器件地址
// SMBus状态
// MT = 主发送器
// MR = 主接收器
#define SMB_BUS_ERROR 0x00 // (对所有方式)总线错误
#define SMB_START 0x08 // (MT & MR)起始条件已发送
#define SMB_RP_START 0x10 // (MT & MR)重复起始条件
#define SMB_MTADDACK 0x18 // (MT) 从地址 + W 已发送;收到ACK
#define SMB_MTADDNACK 0x20 // (MT) 从地址 + W 已发送;收到NACK
#define SMB_MTDBACK 0x28 // (MT) 数据字节已发送;收到ACK
#define SMB_MTDBNACK 0x30 // (MT) 数据字节已发送;收到NACK
#define SMB_MTARBLOST 0x38 // (MT) 竞争失败
#define SMB_MRADDACK 0x40 // (MR) 从地址 + R 已发送;收到ACK
#define SMB_MRADDNACK 0x48 // (MR) 从地址 + W 已发送;收到NACK
#define SMB_MRDBACK 0x50 // (MR) 收到数据字节;ACK已发送
#define SMB_MRDBNACK 0x58 // (MR) 收到数据字节;NACK已发送
extern void Delay(uint sum);
//--------------------------------------------------------------------
//全局变量
//--------------------------------------------------------------------
char COMMAND; // 在SMBus中断服务程序中用于
// 保存从地址 + R/W 位。
char WORD; // 保持SMBus要发送的数据字节
// 或刚收到的数据
char BYTE_NUMBER; // 在中用于检查发送的是什么数据
// 高地址字节、低地址字节或数据字节
uchar HIGH_ADD, LOW_ADD; // EEPROM存储器地址的高、低字节
//bit SM_BUSY; // 该位在发送或接收开始时被置1,
// // 操作结束后由中断服务程序
// SMBus 字节写函数-----------------------------------------------------
// 向给定存储器地址写一个字节
//
// out_byte = 待写数据
// byte_address = 待写存储器地址(2字节)
// chip_select = 待写EEPROM芯片的器件地址
void SM_Send (char chip_select, unsigned int byte_address, char out_byte)
{
// while(SM_BUSY); // 等待SMBus空闲
// SM_BUSY = 1; // 占用SMBus(设置为忙)
SMB0CN = 0x44; // SMBus允许,应答周期发ACK
BYTE_NUMBER = 2; // 2地址字节
COMMAND = (chip_select | WRITE); // 片选 + WRITE
HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8位地址
LOW_ADD = (byte_address & 0x00FF); // 低8位地址
WORD = out_byte; // 待写数据
STA = 1; // 启动传输过程
Delay(50);
}
// SMBus随机读函数-----------------------------------------------------
// 从给定存储器地址读一个字节
//
// byte_address = 要读取的存储器地址
// chip_select = 待读EEPROM的器件地址
char SM_Receive (char chip_select, unsigned int byte_address)
{
// while (SM_BUSY); // 等待总线空闲
// SM_BUSY = 1; //占用SMBus(设置为忙)
SMB0CN = 0x44; // 允许SMBus,应答周期发ACK
BYTE_NUMBER = 2; // 2地址字节
COMMAND = (chip_select | READ); // 片选 + READ
HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8位地址
LOW_ADD = (byte_address & 0x00FF); // 低8位地址
STA = 1; // 启动传输过程
// while(SM_BUSY); // 等待传输结束
Delay(50);
return WORD;
}
//--------------------------------------------------------------------
// 中断服务程序
//--------------------------------------------------------------------
// SMBus中断服务程序
void SMBUS_ISR (void) interrupt 7
{
switch (SMB0STA){ // SMBus状态码(SMB0STA寄存器)
// 主发送器/接收器:起始条件已发送
// 在该状态发送的COMMAND字的R/W位总是为0(W),
// 因为对于读和写操作来说都必须先写存储器地址。
case SMB_START:
SMB0DAT = (COMMAND & 0xFE); // 装入要访问的从器件的地址
STA = 0; // 手动清除START位
break;
//主发送器/接收器:重复起始条件已发送。
//该状态只应在读操作期间出现,在存储器地址已发送并得到确认之后
case SMB_RP_START:
SMB0DAT = COMMAND; // COMMAND中应保持从地址 + R.
STA = 0;
break;
// 主发送器:从地址 + WRITE已发送,收到ACK。
case SMB_MTADDACK:
SMB0DAT = HIGH_ADD; // 装入待写存储器地址的高字节
break;
// 主发送器:从地址 + WRITE已发送,收到NACK。
// 从器件不应答,发送STOP + START重试
case SMB_MTADDNACK:
STO = 1;
STA = 1;
break;
// 主发送器:数据字节已发送,收到ACK。
// 该状态在写和读操作中都要用到。BYTE_NUMBER看存储器地址状态 – 如果
// 只发送了HIGH_ADD,则装入LOW_ADD。如果LOW_ADD已发送,检查COMMAND
// 中的R/W 值以决定下一状态。
case SMB_MTDBACK:
switch (BYTE_NUMBER){
case 2: // 如果BYTE_NUMBER=2,
SMB0DAT = LOW_ADD; // 只发送了HIGH_ADD。
BYTE_NUMBER--; // 减1,为下一轮作准备
break;
case 1: // 如果BYTE_NUMBER=1,LOW_ADD已发送。
if (COMMAND & 0x01) // 如果R/W=READ,发送重复起始条件
STA = 1;
else{
SMB0DAT = WORD; // 如果R/W=WRITE,装入待写字节
BYTE_NUMBER--;}
break;
default: // 如果BYTE_NUMBER=0,传输结束
STO = 1;
//SM_BUSY = 0; // 释放SMBus
}
break;
// 主发送器:数据字节已发送,收到NACK。
// 从器件不应答,发送STOP + START重试
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:
STA = 1;
break;
// 收到数据字节。ACK已发送。
// 该状态不应出现,因为AA已在前一状态被清0。如果出现,发送停止条件。
case SMB_MRDBACK:
STO = 1;
//SM_BUSY = 0;
break;
// 收到数据字节。NACK已发送。
// 读操作已完成。读数据寄存器后发送停止条件。
case SMB_MRDBNACK:
WORD = SMB0DAT;
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 + -