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

📄 e2prom.c

📁 此程序是针对I2C总线的读写
💻 C
字号:
//--------------------------------------------------------------------
//
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// 文件名 : 24LC256.c
// 目标器件 : C8051F020
// 编写日期 : 11/07/05
// 作者 : WuShufeng
//
//
// C8051F0xx通过SMBus与一个EEPROM接口的代码
// 该程序有两个具有16位地址空间的EEPROM连在SCL和SDA线上
// 被配置为具有如下从地址
// CHIP_A = 10100000(24LC256)
// 
// 
//
// 从状态和竞争状态没有定义假设CF020为系统中唯一的主器件
// 功能SM_Send执行向指定EEPROM的单字节写操作
// SM_Receive执行从指定EEPROM地址读一个字节的操作两者都用到存储器地址
//
// 包含测试代码部分
//--------------------------------------------------------------------
// 包含文件
//--------------------------------------------------------------------
#include <c8051F020.h>
#include <stdio.h>
#include "Head.h"
//--------------------------------------------------------------------
// 全局常量
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//全局变量
//--------------------------------------------------------------------
char xdata COMMAND; // 在SMBus中断服务程序中用于保存从地址 + R/W 位

unsigned char xdata WORD; // 保持SMBus要发送的数据字节或刚收到的数据

char xdata BYTE_NUMBER; // 在中用于检查发送的是什么数据高地址字节低地址字节或数据字节

unsigned char xdata HIGH_ADD, LOW_ADD; // EEPROM存储器地址的高低字节
bit SM_BUSY; // 该位在发送或接收开始时被置1
// 操作结束后由中断服务程序清0
//--------------------------------------------------------------------
// 函数原型
//--------------------------------------------------------------------

//--------------------------------------------------------------------
// 主程序
//--------------------------------------------------------------------
//
// 主程序配置交叉开关和SMBus并测试SMBus与三个EEPROM之间的接口
void SMBus_Init (void)
{
	SMB0CN = 0x44; // 允许SMBus在应答周期发送ACK
	SMB0CR = -55; // SMBus时钟频率 = 100kHz.
	EIE1 |= 2; // SMBus中断允许
	EA = 1; // 全局中断允许
	SM_BUSY = 0; // 为第一次传输释放SMBus
}
// SMBus 字节写函数-----------------------------------------------------
// 向给定存储器地址写一个字节
//
// out_byte = 待写数据
// byte_address = 待写存储器地址2字节
// chip_select = 待写EEPROM芯片的器件地址
void SM_Send (unsigned int byte_address,unsigned char out_byte)
{
	while (SM_BUSY); // 等待SMBus空闲
	SM_BUSY = 1; // 占用SMBus设置为忙
	SMB0CN = 0x44; // SMBus允许应答周期发ACK
	BYTE_NUMBER = 2; // 2地址字节
	COMMAND = (CHIP_A | WRITE); // 片选 + WRITE
	HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8位地址
	LOW_ADD = (byte_address & 0x00FF); // 低8位地址
	WORD = out_byte; // 待写数据
	STA = 1; // 启动传输过程
}
/////SM_Send_str连续写入
void SM_Send_str (unsigned int byte_address,unsigned char *out_str,unsigned char n)
{
	unsigned char xdata i;
	for( i = 0;i < n;i ++)
		{
			SM_Send(byte_address++,*out_str++);
		}
}
// SMBus随机读函数-----------------------------------------------------
// 从给定存储器地址读一个字节
//
// byte_address = 要读取的存储器地址
// chip_select = 待读EEPROM的器件地址
char SM_Receive (unsigned int byte_address)
{
	while (SM_BUSY); // 等待总线空闲
	SM_BUSY = 1; //占用SMBus设置为忙
	SMB0CN = 0x44; // 允许SMBus应答周期发ACK
	BYTE_NUMBER = 2; // 2地址字节
	COMMAND = (CHIP_A | READ); // 片选 + READ
	HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8位地址
	LOW_ADD = (byte_address & 0x00FF); // 低8位地址
	STA = 1; // 启动传输过程
	while (SM_BUSY); // 等待传输结束
	return WORD;
}
//////SM_Receive_str连续读出
void SM_Receive_str (unsigned int byte_address,unsigned char *in_str,unsigned char n)
{
	unsigned char xdata i;
	for(i = 0;i < n;i ++)
		{
			*in_str++ = SM_Receive(byte_address++);
		}
}

//--------------------------------------------------------------------
// 中断服务程序
//--------------------------------------------------------------------
// 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=1LOW_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 + -