📄 smbus.c
字号:
#include "C8051F020.h"
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define WRITE1 0x00 // SMBus 写命令
#define READ1 0x01 // SMBus 读命令
#define CHIP_A 0xA0 // 芯片A 的器件地址
#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 已发送
#define uchar unsigned char
xdata unsigned char SPI_byte;
char TX_data[4]={1,2,3,4};
char RX_data[4]={0,0,0,0};
//char TX_data=1;
//char RX_data=0;
//全局变量
unsigned char check=0;
//--------------------------------------------------------------------
char COMMAND; // 在SMBus 中断服务程序中用于
// 保存从地址+ R/W 位
char WORD; // 保持SMBus 要发送的数据字节
// 或刚收到的数据
char BYTE_NUMBER; // 在中用于检查发送的是什么数据
// 地址字节或数据字节
unsigned char ADDR; // EEPROM 存储器地址
bit SM_BUSY; // 该位在发送或接收开始时被置1 操作结束后由中断服务程序清0
//void SMBus_ISR (void);
//void SM_Send (char chip_select, unsigned char byte_address, char out_byte);
//char SM_Receive (char chip_select, unsigned char byte_address);
void SMBus_Init()
{
SMB0CN = 0x44;
SMB0CR = 0x99;
//SMB0ADR = MY_ADDR; // Set own slave address.
}
void Port_IO_Init()
{
XBR0 = 0x05;
XBR1 = 0x04;
XBR2 = 0x40;
}
void Oscillator_Init()
{
int i = 0;
OSCXCN = 0x67;
for (i = 0; i < 3000; i++); // Wait 1ms for initialization
while ((OSCXCN & 0x80) == 0);
OSCICN = 0x08;
}
void SMBUS_ISR () ;
// SMBus 字节写函数-----------------------------------------------------
// 向给定存储器地址写一个字节
// out_byte = 待写数据
// byte_address = 待写存储器地址
// chip_select = 待写EEPROM 芯片的器件地址
void SM_Send ( unsigned char byte_address, char out_byte)
{
while (SM_BUSY); // 等待SMBus 空闲
SM_BUSY = 1; // 占用SMBus 设置为忙
//SMB0CN = 0x44; // SMBus 允许应答周期发ACK
BYTE_NUMBER = 1; // 地址字节
COMMAND = (0xA0| WRITE1); // 片选+ WRITE
ADDR = byte_address;
WORD = out_byte; // 待写数据
STA = 1; // 启动传输过程
while(SI==0);
SMBUS_ISR ();//起始条件发送 0x08,同时装入从地址+W
while(SI==0);
SMBUS_ISR ();//从地址+W已发送,收到ACK 0x18,同时装入字节地址
while(SI==0);
SMBUS_ISR ();//字节地址已发送,收到ACK,0x28,同时装入字节数据
while(SI==0);
SMBUS_ISR ();//字节数据已发送,收到ACK,0x28,同时结束写操作
}
// SMBus 随机读函数-----------------------------------------------------
// 从给定存储器地址读一个字节
// byte_address = 要读取的存储器地址
// chip_select = 待读EEPROM 的器件地址
char SM_Receive(unsigned char byte_address)
{
while (SM_BUSY); // 等待总线空闲
SM_BUSY = 1; //占用SMBus 设置为忙
//SMB0CN = 0x44; // 允许SMBus 应答周期发ACK
BYTE_NUMBER = 1; // 1地址字节
COMMAND = (0xA0| READ1); // 片选+ READ
ADDR = byte_address ; //8 位地址
STA = 1; // 启动传输过程
while(SI==0);
SMBUS_ISR ();//起始条件发送 0x08,同时装入从地址+W
while(SI==0);
SMBUS_ISR ();//从地址+W已发送,收到ACK 0x18,同时装入字节地址
while(SI==0);
SMBUS_ISR ();//字节地址已发送,收到ACK,0x28,同时装入从地址+R
while(SI==0);
SMBUS_ISR ();//重复起始条件已发送,0x10,同时装入从地址+R
while(SI==0);
SMBUS_ISR ();//从地址+R已发送,收到ACK,0x40,同时清零AA(只收一个数据)
while(SI==0);
SMBUS_ISR(); //数据字节收到,0x50,ACK已发送
//while (SM_BUSY); // 等待传输结束
return WORD;
}
//--------------------------------------------------------------------
// 中断服务程序
//--------------------------------------------------------------------
// SMBus 中断服务程序
void SMBUS_ISR ()
{
switch (SMB0STA){ // SMBus状态码SMB0STA 寄存器
// 主发送器/接收器起始条件已发送
// 在该状态发送的COMMAND 字的R/W 位总是为0(W)
// 因为对于读和写操作来说都必须先写存储器地址
case SMB_START: //0x08
SMB0DAT = (COMMAND & 0xFE); // 装入要访问的从器件的地址
STA = 0; // 手动清除START 位
break;
//主发送器/接收器重复起始条件已发送
// 该状态只应在读操作期间出现在存储器地址已发送并得到确认之后
case SMB_RP_START: //0x10
SMB0DAT = COMMAND; // COMMAND 中应保持从地址+ R.
STA = 0;
break;
// 主发送器从地址+ WRITE 已发送收到ACK
case SMB_MTADDACK: //0x18
SMB0DAT = ADDR; // 装入待写存储器地址的高字节
break;
// 主发送器从地址+ WRITE 已发送收到NACK
// 从器件不应答发送STOP + START 重试
case SMB_MTADDNACK: //0x20
STO = 1;
STA = 1;
break;
// 主发送器数据字节已发送收到ACK
// 该状态在写和读操作中都要用到BYTE_NUMBER 看存储器地址状态– 如果
// 只发送了HIGH_ADD 则装入LOW_ADD 如果LOW_ADD 已发送检查COMMAND
// 中的R/W 值以决定下一状态
case SMB_MTDBACK: //0x28
switch (BYTE_NUMBER){
case 1: // 如果BYTE_NUMBER=1 ADDR 已发送
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: //0x30
STO = 1;
STA = 1;
break;
// 主发送器竞争失败
// 不应出现如果出现重新开始传输过程
case SMB_MTARBLOST: //0x38
STO = 1;
STA = 1;
break;
// 主接收器从地址+ READ 已发送收到ACK
// 设置为在下一次传输后发送NACK 因为那将是最后一个字节唯一
case SMB_MRADDACK: //0x40
AA = 0; // 在应答周期NACK
break;
// 主接收器从地址+ READ 已发送收到NACK
// 从器件不应答发送重复起始条件重试
case SMB_MRADDNACK: //0x48
STA = 1;
break;
// 收到数据字节ACK 已发送
// 该状态不应出现因为AA 已在前一状态被清0 如果出现发送停止条件
case SMB_MRDBACK: //0x50
STO = 1;
SM_BUSY = 0;
break;
// 收到数据字节NACK 已发送
// 读操作已完成读数据寄存器后发送停止条件
case SMB_MRDBNACK: //0x58
WORD = SMB0DAT;
STO = 1;
SM_BUSY = 0; // 释放SMBus
break;
// 在本应用中所有其它状态码没有意义通信复位
default:
STO = 1; // 通信复位
SM_BUSY = 0;
break;
}
SI=0; // 清除中断标志
}
void Write_FRAM(uchar *SendData,uchar Addr,uchar DataLen)
{
uchar i;
for(i=0;i<DataLen;i++)
{
SM_Send(Addr++, *(SendData++));
}
}
void Read_FRAM(uchar *GetData,uchar Addr,uchar DataLen)
{
uchar i;
for(i=0;i<DataLen;i++)
{
*GetData++=SM_Receive(Addr);
Addr++;
}
}
void Init_Device()
{
SMBus_Init();
Port_IO_Init();
Oscillator_Init();
}
void main()
{
WDTCN=0xde; //禁止看门狗定时器
WDTCN=0xad;
Init_Device();
SM_BUSY = 0; // 为第一次传输释放SMBus
EIE1 = 0x00;// SMBus中断允许
IE = 0x00;//开中断
Write_FRAM(TX_data,0x00,4);
//
//SM_Send(CHIP_A, 0x00, 1); //发送0x53 数据到CHIP_A 的地址0x88
//SM_Send(CHIP_A, 0x01, 2); //发送0x53 数据到CHIP_A 的地址0x88
//SM_Send(CHIP_A, 0x02, 3); //发送0x53 数据到CHIP_A 的地址0x88
//SM_Send(CHIP_A, 0x03, 4); //发送0x53 数据到CHIP_A 的地址0x88
Read_FRAM(RX_data,0x00,4);
//RX_data[0] = SM_Receive(CHIP_A, 0x00); // 读CHIP_A 的地址0x88
//RX_data[1] = SM_Receive(CHIP_A, 0x01); // 读CHIP_A 的地址0x88
//RX_data[2] = SM_Receive(CHIP_A, 0x02); // 读CHIP_A 的地址0x88
//RX_data[3] = SM_Receive(CHIP_A, 0x03); // 读CHIP_A 的地址0x88
check=0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -