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

📄 smbus.c

📁 用查询方式实现C8051F021的SMBUS对FM24CL04的读写(鉴于在其他中断中不能发生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 + -