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

📄 smb_test1.c

📁 有价值的电子书
💻 C
📖 第 1 页 / 共 2 页
字号:
// 两个C8051F020 器件之间用SMBus 接口的示例代码。
// 这两个器件以点对点方式工作。
//
// 该例演示每个器件如何使用操作码命令另一个器件完成:
//
// 1) 向DAC0 写一个字节
// 2) 写一个字节到一个数据缓冲区
// 3) 进行一次ADC 转换
// 4) 从一个数据缓冲区读一个字节
//
// 如果每个器件都将DAC0 连到AIN0,则这些操作码的测试是很容易的。
// 在这种配置下,READ_ADC 命令可以用于测试WRITE_DAC 的输出。
//
// 本程序假设两个CF020 器件通过SCL 和SDA 连在一起,从地址(在寄存器SMB0ADR 中)为:
// CHIP_A = 1111000
// CHIP_B = 1110000
//
// 测试代码已包含在内。为了达到测试目的,一个器件中的测试代码应被去掉,而运行另一个
// 器件的测试代码。这可以通过注释掉假定的主器件中测试代码之前的OP_CODE_HANDLER()
// 调用来完成。
//
// 请注意,常数MY_ADD 必须与当前器件对应,在向CHIP_B 下载代码时应将其改为CHIP_B。
//
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// 包含文件
//--------------------------------------------------------------------
#include <c8051f020.h> // 声明
//--------------------------------------------------------------------
// 全局常量
//--------------------------------------------------------------------
#define WRITE 0x00 		// 写方向位
#define READ 0x01 		// 读方向位
		// 器件地址
#define CHIP_A 0xF0
#define CHIP_B 0xE0
#define MY_ADD CHIP_A 	// 对应当前被编程的器件
		// 点对点操作码
#define READ_ADC 0x01 	// OP_CODE 读从ADC
#define WRITE_DAC 0x02 	// OP_CODE 写从DAC
#define WRITE_BUF 0x03 	// OP_CODE 写从缓冲区
#define READ_BUF 0x04 	// OP_CODE 读从缓冲区
		//SMBus 状态:
		// MT = 主发送器
		// MR = 主接收器
		// ST = 从发送器
		// SR = 从接收器
#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) 从地址+ R 已发送;收到NACK
#define SMB_MRDBACK 0x50 		// (MR) 收到数据字节;ACK 已发送
#define SMB_MRDBNACK 0x58 		// (MR) 收到数据字节;NACK 已发送
#define SMB_SROADACK 0x60 		// (SR) 收到自己的从地址+W;ACK 已发送
#define SMB_SROARBLOST 0x68 	// (SR) 收到自己的从地址+W;竞争失败
#define SMB_SRGADACK 0x70 		// (SR) 收到通用呼叫地址+W;ACK 已发送
#define SMB_SRGARBLOST 0x78 	// (SR) 在作为主器件发送从地址+ R/W
		// 时竞争失败。收到通用呼叫地址;
		// ACK已发送
#define SMB_SRODBACK 0x80 		// (SR) 收到属于自己从地址的数据字节;
		// ACK已发送
#define SMB_SRODBNACK 0x88 		// (SR) 收到属于自己从地址的数据字节;
		// NACK 已发送
#define SMB_SRGDBACK 0x90 		// (SR) 收到通用呼叫地址的数据字节;
		// ACK已发送
#define SMB_SRGDBNACK 0x98 		// (SR) 收到通用呼叫地址的数据字节;
		// NACK 已发送
#define SMB_SRSTOP 0xa0 		// (SR) 在作为从其间被访问时
		// 收到停止条件或重复起始条件
#define SMB_STOADACK 0xa8 		// (ST) 收到自己的从地址+R;ACK 已发送
#define SMB_STOARBLOST 0xb0 	// (ST) 在作为主器件发送从地址+ R/W
		// 时竞争失败。收到自己的从地址;
		// ACK已发送
#define SMB_STDBACK 0xb8 		// (ST) 数据字节已发送;收到ACK
#define SMB_STDBNACK 0xc0 		// (ST) 数据字节已发送;收到NACK
#define SMB_STDBLAST 0xc8 		// (ST) 最后数据字节已发送(AA=0);收到ACK
#define SMB_SCLHIGHTO 0xd0 		// (ST & SR) SCL 时钟高电平定时器根据
		// SMB0CR 已超时(FTE=1)
#define SMB_IDLE 0xf8 			// (对所有方式)等待
//--------------------------------------------------------------------
//全局变量
//--------------------------------------------------------------------
char COMMAND; 					// 在SMBus ISR 中保存从地址+ R/W 位。
char WORD; 						// 保存SMBus 待发送字节或刚收到的字节
char OP_CODE; 					// 保存待发送或刚收到的操作码
char LOST_COMMAND, LOST_WORD, LOST_CODE; // 用于在竞争失败后保存相关数据
char DATA_BUF[16]; 				// 由OP_CODE_HANDLER 访问的数据缓冲区
bit LOST; 						// 竞争失败标志,在主方式下竞争失败时置位。
								// 用于恢复失败的传输过程
bit SM_BUSY; 					// 该位在发送或接收开始时置1。
								// 操作结束后由ISR 清0
bit VALID_OP; 					// 用于确定作为从器件收到的字节是操作码
								// 还是数据。
bit DATA_READY; 				// 由OP_CODE 处理程序使用,用于指示
								// 从主器件接收的数据何时有效
//--------------------------------------------------------------------
// 函数原型
//--------------------------------------------------------------------
void SMBUS_ISR (void);
char SLA_READ(char chip_select, char out_op);
void SLA_SEND(char chip_select, char out_op, char out_data);
void OP_CODE_HANDLER(void);
//--------------------------------------------------------------------
// 主程序
//--------------------------------------------------------------------
void MAIN (void)
{
	char i, check_1, check_2; 		// 只用于测试目的的变量
	WDTCN = 0xde; 					// 禁止看门狗定时器
	WDTCN = 0xad;
	XBR0 = 0x01; 					// 通过交叉开关将SMBus 连到通用I/O 引脚;P0.0,P0.1
	XBR2 = 0x40; 					// 允许交叉开关和弱上拉
	SMB0CN = 0x44; 					// 允许SMBus,应答为低电平(AA = 1)
	SMB0CR = -80; 					// SMBus 时钟频率= 100 kHz
	SMB0ADR = MY_ADD; 				// 设置自己的从地址
	ADC0CN = 0x80; 					// 允许ADC,用写ADBUSY 启动转换
	ADC0CN |= 0x01; 				// ADC 数据寄存器左对齐
	DAC0CN = 0x84; 					// 允许DAC0,数据寄存器左对齐
	REF0CN = 0x03; 					// 允许电压基准
	EIE1 |= 2; 						// SMBus 中断允许
	EA = 1; 						// 全局中断允许
	SM_BUSY = 0; 					// 为第一次传输释放总线
	SI = 0; 
// OP_CODE_HANDLER(); 				// 该行只能在两个点对点器件中的一个里
// 被注释掉。只用于测试目的。
// 在正常设置下OP_CODE_HANDLER 将一直运行,
// 以便根据发送给该器件的操作码执行相应操作
// 测试代码-------------------------------------------------------------
// 本代码只用于测试两个器件间的接口。如果上面的OP_CODE_HANDLER 行被去掉注释标记,
// 该器件被假设为主器件。另一个器件应一直运行OP_CODE_HANDLER,响应下面的操作码:
	SLA_SEND(CHIP_B, (0x40 | WRITE_BUF), 0x24); 		// 写到数据缓冲区下标4
	SLA_SEND(CHIP_B, (0x60 | WRITE_BUF), 0x25); 		// 写到下标6
	SLA_SEND(CHIP_B, (0x80 | WRITE_BUF), 0x26); 		// 写到下标8
	SLA_SEND(CHIP_B, (0x10 | WRITE_BUF), 0x27); 		// 写到下标1
	check_1 = SLA_READ(CHIP_B, (0x40 | READ_BUF)); 		// 从缓冲区读下标4
	check_1 = SLA_READ(CHIP_B, (0x60 | READ_BUF)); 		// 读下标6
	check_1 = SLA_READ(CHIP_B, (0x80 | READ_BUF)); 		// 读下标8
	check_1 = SLA_READ(CHIP_B, (0x10 | READ_BUF)); 		// 读下标1
// 在循环内连续增加CHIP_B 的DAC 输出并在每次循环读ADC。CHIP_B 的DAC 输出应斜升
	for (i=0;i<50;i++){
	SLA_SEND(CHIP_B, WRITE_DAC, 2*i); 					// 写2* i 到CHIP_B 的DAC0
	check_1 = SLA_READ(CHIP_B, READ_ADC); 				// 读CHIP_B 的AIN0
	check_2 = 2*i;}										// check_1 应与check_2
// 基本一致
// 测试代码结束---------------------------------------------------------
}
//--------------------------------------------------------------------
// 函数
//--------------------------------------------------------------------
//向从器件发送
// 发送函数向从器件发送两个字节:一个操作码和一个数据字节。有两个操作码用于发送数据:
// WRITE_DAC 和WRITE_BUF。如果操作码为WRITE_BUF,则操作码的高4 位应含有缓冲区
// 的下表。例如,为了写数据缓冲区下标2 对应的地址,操作码参数应为(0x20 | WRITE_BUF)。
//
// chip_select = 从器件地址。
// out_op = 要发送的操作码。
// out_data = 要发送的数据。
void SLA_SEND(char chip_select, char out_op, char out_data){
	while(SM_BUSY); 					// 在SMBus 忙时等待
	SM_BUSY = 1; 						// SMBus 忙标志置位
	SMB0CN = 0x44; 						// 允许SMBus,ACK 为低电平
	COMMAND = (chip_select | WRITE); 	// COMMAND = 7 个地址位+ WRITE.
	OP_CODE = out_op; 					// WORD = 要发送的操作码。
	WORD = out_data; 					// DATA = 要发送的数据。
	STA = 1; 							// 启动传输过程。
}
// 读从器件
// 读函数发出一个字接的操作码,然后发出一个重复起始条件请求读一个字节。
// 可以在两个操作码READ_ADC 和READ_BUF 之间选择。如果操作码为READ_BUF,
// 则操作码的高4 位应含有缓冲区的索引下标。例如,要读数据缓冲区下标5 对应的地址,
// 则操作码应为(0x50 | READ_BUF)。
//
// chip_select = 从器件地址。
// out_op = 要发送的操作码。
char SLA_READ(char chip_select, char out_op){
	while(SM_BUSY); 					// 在SMBus 忙时等待。
	SM_BUSY = 1; 						// SMBus 忙标志置位
	SMB0CN = 0x44; 						// 允许SMBus,ACK 为低电平
	COMMAND = (chip_select | READ); 	// COMMAND = 7 个地址位+ READ
	OP_CODE = out_op;
	STA = 1; 							// 启动传输过程。
	while(SM_BUSY); 					// 等待传输结束
	return WORD; 						// 返回接收字
}
// OP_CODE handler.
// 对输入操作码译码并根据操作码执行相应的任务。
// 一旦被调用,将一直运行
//
// VALID_OP 位指示收到一个有效操作码。收到后,该处理程序对操作码译码并执行相应的任务,
// 然后清除VALID_OP 以等待下一个操作码。
void OP_CODE_HANDLER(void){
	char index; 				// 数据缓冲区索引下标
	while (1){ 					// 死循环
		VALID_OP = 0; 			// 等待有效的OP_CODE
		while (!VALID_OP); 		
		// OP_CODE 的低4 位用于确定要执行的动作,而高4 位在收到READ_BUF 或
		// WRITE_BUF 操作码时用于指示DATA_BUF 数组的下标。
		// 注意SMBus 被冻结直到OP_CODE 被译码。
		switch (OP_CODE & 0x0F){ // 对OP_CODE 译码
		// OP_CODE = READ_ADC – 进行一次ADC 并将结果放到输出缓冲区。
		// 只读ADC 的高字节。
			case READ_ADC:
			SI = 0; 				// 释放总线
			AA = 0; 				// 使从器件'离线'
			AD0INT = 0; 			// 清ADC 中断标志。
			AD0BUSY = 1; 			// 启动转换。
			while (!AD0INT); 		// 等待转换结束。
			WORD = ADC0H; 			// 将数据放到输出缓冲区
			AA = 1; 				// 使从器件返回'在线'状态
			VALID_OP = 0; 			// 等待新的OP_CODE
			break;
			// OP_CODE=WRITE_DAC –等待一个有效数据字节,并将其写到DAC0 的高字节。
			case WRITE_DAC:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -