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

📄 smb_test0.c

📁 有价值的电子书
💻 C
字号:
// C8051F020 通过SMBus 与三个EEPROM 接口的示例代码。
// 该程序假设三个具有16 位地址空间的EEPROM 连在SCL 和SDA 线上,
// 被配置为具有如下从地址:
// CHIP_A = 1010000
// CHIP_B = 1010001
// CHIP_C = 1010010
// 从状态和竞争状态没有定义。假设C8051F020 为系统中唯一的主器件。
// 功能:SM_Send 执行向指定EEPROM 的单字节写操作
// SM_Receive 执行从指定EEPROM 地址读一个字节的操作(两者都用到存储器地址)
//
// 包含测试代码部分。
//--------------------------------------------------------------------
// 包含文件
//--------------------------------------------------------------------
#include <c8051f020.h> // SFR 声明
//--------------------------------------------------------------------
// 全局常量
//--------------------------------------------------------------------
#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 已发送
//--------------------------------------------------------------------
//全局变量
//--------------------------------------------------------------------
char COMMAND; 		// 在SMBus 中断服务程序中用于
					// 保存从地址+ R/W 位。
char WORD; 			// 保持SMBus 要发送的数据字节
					// 或刚收到的数据
char BYTE_NUMBER; 	// 在中用于检查发送的是什么数据
					// 高地址字节、低地址字节或数据字节
unsigned char HIGH_ADD, LOW_ADD; 	// EEPROM 存储器地址的高、低字节
bit SM_BUSY; 		// 该位在发送或接收开始时被置1,
					// 操作结束后由中断服务程序清0
//--------------------------------------------------------------------
// 函数原型
//--------------------------------------------------------------------
void SMBus_ISR (void);
void SM_Send (char chip_select, unsigned int byte_address, char out_byte);
char SM_Receive (char chip_select, unsigned int byte_address);
//--------------------------------------------------------------------
// 主程序
//--------------------------------------------------------------------
//
// 主程序配置交叉开关和SMBus,并测试SMBus 与三个EEPROM 之间的接口
void main (void)
{
	unsigned char check; 		// 用于测试目的
	WDTCN = 0xde; 				// 禁止看门狗定时器
	WDTCN = 0xad;
	OSCICN |= 0x03; 			// 设置内部振荡器为最高频率(16 MHz)
	XBR0 = 0x01; 				// 通过交叉开关将SMBus 连到通用I/O 引脚;P0.0,P0.1
	XBR2 = 0x40; 				// 允许交叉开关和弱上拉
	SMB0CN = 0x44; 				// 允许SMBus 在应答周期发送ACK
	SMB0CR = -80; 				// SMBus 时钟频率= 100kHz.
	EIE1 |= 2; 					// SMBus 中断允许
	EA = 1; 					// 全局中断允许
	SM_BUSY = 0; 				// 为第一次传输释放SMBus。
// 测试代码-------------------------------------------------------------
	SM_Send(CHIP_A, 0x0088, 0x53); 		//发送0x53(数据)到CHIP_A 的地址0x88
	SM_Send(CHIP_B, 0x0001, 0x66); 		//发送0x66(数据)到CHIP_B 的地址0x01
	SM_Send(CHIP_C, 0x0010, 0x77);
	SM_Send(CHIP_B, 0x0333, 0xF0);
	SM_Send(CHIP_A, 0x0242, 0xF0);
	check = SM_Receive(CHIP_A, 0x0088); // 读CHIP_A 的地址0x88
	check = SM_Receive(CHIP_B, 0x0001); // 读CHIP_B 的地址0x01
	check = SM_Receive(CHIP_C, 0x0010);
	check = SM_Receive(CHIP_B, 0x0333);
	check = SM_Receive(CHIP_A, 0x0242);
// 代码结束----------------------------------------------------------
}
// 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; 							// 启动传输过程
}
// 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); 					// 等待传输结束
	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 + -