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

📄 iic_rom.c

📁 C8051F040单片机开发与C语言编程-例子
💻 C
字号:
///////////应用SMBUS操作IIC ROM////////////////
////////IIC_ROM.c/////////////////////////////////
#include "smbus.h"
#include "absacc.h"
#define FLOATADR 0x0000
#define SLAVE_FLOATADR 0x0000
#define IIC_R 0x01
#define RETRY_MAX 50
/* IIC_R为SMBUS读控制*/
#define IIC_W 0xfe
#define READ 0x01
#define ROMID 0x50
#define DATALEN 5
/* IIC_W为SMBUS写控制*/
union int16{//采用联合体实现16位与8位混合操作
	uint word;
	struct {uchar hi;uchar low;}split;
};
struct smbus_mes{
	uchar id;
	union int16 target_adr;
	uint self_adr;
	uchar len;
	uchar isread;
	uchar adr_end;
	uchar isbuserror;
};
xdata struct smbus_mes mes_M,mes_S;//将结构体定义到外部内存上
xdata float floattest _at_ FLOATADR;
xdata uchar *p;
void master_mes_creat(uchar id,uint target_adr,uint self_adr,uchar len,uchar dir){
	mes_M.id=id<<1;//id数据在7-1位,须右移1位
	mes_M.id&=IIC_W;//主机要发送从机的内存地址,故起始必然是写操作
	mes_M.target_adr.word=target_adr;
	mes_M.self_adr=self_adr;
	mes_M.len=len;
	mes_M.isread=dir;
	mes_M.isbuserror=0;
}
void config(){//crossbar 使能,但并没有进行外围设备配置
	WDTCN = 0x07;	//看门狗禁止
  	WDTCN = 0xDE;    
   	WDTCN = 0xAD;
	SFRPAGE = 0x0F;
	XBR2&=~0x40;//关闭Crossbar;
	XBR0|=0x01;//将SMBUS配置到P口上
	XBR2|=0x40;//Crossbar 交叉开关使能,开启Crossbar
 	P0MDOUT = 0x00; 
  	P1MDIN = 0xFF;  // P1数字输入口
	SFRPAGE = 0x0F;
 	CLKSEL = 0x00;  // 选择内部晶振8分频
	OSCXCN = 0x00;	
	OSCICN = 0x84;	
}
void main(){
	xdata float pai=3.14159;
	xdata float float_get=0.0;
	bit needreceive;
	config();
	smbus_cfg(0x40,0xf1,0x70);
	/*
	smbus使能,AA=0,SCL高电平和低电平超时禁止
	smbus时钟频率为100khz
	自身从机地址为0x70/2,即为56(十进制),且广播寻址禁止
	*/
	master_mes_creat(ROMID,0x7000,&pai,sizeof(float),0);
	/*
	读从机浮点数的值(始地址为SLAVE_FLOATADR)
	将读取值存放于始地址为FLOATADR的外部内存上
	*/
	EA=1;//打开全局中断
	SFRPAGE=0x00;
	while(BUSY);//等待总线释放
	smbusMasterStart();//主机发送起始位
	needreceive=1;
	while(1){
		SFRPAGE=0x00;
		if(!BUSY){//总线空闲时查询总线传输状况
			if(mes_M.isbuserror!=0)
				if(mes_M.len>0)
					smbusMasterStart();//再次发送。
			if(mes_M.len==0){
				if(needreceive){
					master_mes_creat(ROMID,0x7000,&float_get,sizeof(float),READ);
					smbusMasterStart();
					needreceive=0;
				}
			}
		}
		if(mes_M.len==0){
			if(!needreceive)
				needreceive=0;
		}
	}
}
void int0() interrupt 0{
}
void int1() interrupt 1{
}
void int2() interrupt 2{
}
void int3() interrupt 3{
}
void int4() interrupt 4{
}
void int5() interrupt 5{
}
void int6() interrupt 6{
}
void smbusInt() interrupt 7{//smbus中断
//比较完善的SMBUS中断处理程序,但是由于对各种状态均作出处理,降低处理速度
//读者可根据需要删减一些状态处理
	static uchar retry_time=0;
	SFRPAGE=0x00;
	if(SMB0STA==0x08){//起始位发送成功,主机模式下才会出现这种状态
		SMB0DAT=mes_M.id;//将地址和读写控制装入发送缓冲区
		STA=0;//将STA清零,注意,若不清零则将一直为重复起始状态
		mes_M.adr_end=0;//内存地址没有发送完毕
		goto bus_end;
	}
	if(SMB0STA==0x10){//重复起始条件处理
		SMB0DAT=mes_M.id;
		STA=0;
		mes_M.adr_end=0;//内存地址没有发送完毕
		goto bus_end;
	}
	if(SMB0STA==0x18){//从地址+W发出,收到从机ACK应答
		SMB0DAT=mes_M.target_adr.split.hi;//发送内存高地址
		mes_M.adr_end=0;//内存地址没有发送完毕
		retry_time=0;//将重试计数器清零
		goto bus_end;
	}
	if(SMB0STA==0x20){//从地址+W发出,收到从机NACK应答
		STO=1;
		retry_time++;
		if(retry_time<RETRY_MAX){
			STA=1;//若重试次数小于最大限值,则产生重复起始条件
		}
		else{
			mes_M.isbuserror=1;//isbuserror在初始化时须清零
			retry_time=0;//若大于重试次数,由于没有将STA置1,不会产生重复起始条件
		//且须将retry_time即时清零,以便下一次SMBUS中断时,重试次数从零开始计数
		}
		goto bus_end;
	}
	if(SMB0STA==0x28){//SMBUS数据成功发送,且收到从机ACK应答
		if(mes_M.len>0){
			if(mes_M.adr_end==0){//若内存地址没有发送完毕,继续发送内存地址
				SMB0DAT=mes_M.target_adr.split.low;//发送内存低地址	
				mes_M.adr_end=2;
			}
			else{
				if(mes_M.isread==READ){
				//更换角色,对从机写完内存地址后,读取从机发送过来的数据
					mes_M.id|=IIC_R;//将id中写控制位改成读控制位
					STA=1;//此时不需要将STO置1
				}
				else{
					SMB0DAT=XBYTE[mes_M.self_adr];
					//取自身外部内存相应地址上的数据发送到SMBUS总线上
					mes_M.target_adr.word++;//对从机操作的内存地址自增1
					mes_M.self_adr++;//自身内存地址自增1
					mes_M.len--;//数据长度减1
				/*
				主从机内存地址自增能保证当产生重复起始条件时,对于成功发送的数据不再重发
				*/
					}
				
			}
		}
		else{//若数据长度等于0,则停止发送
			STO=1;
			retry_time=0;
		}
		goto bus_end;
	}
	if(SMB0STA==0x30){//SMBUS数据成功发送,但接收到从机NACK应答
		STO=1;
		STA=1;//产生重复起始条件
		goto bus_end;
	}
	if(SMB0STA==0x38){//总线竞争失败。
		STO=1;//发送停止帧,并把总线错误标志位置1。
		mes_M.isbuserror=1;
		goto bus_end;
	}
	if(SMB0STA==0x40){//从机地址+R发送成功,接收到从机ACK应答信号
		if(mes_M.len>1)
			AA=1;//下一接收数据不是最后数据,故AA置1,以应答从机
		else{
			if(mes_M.len==1)//下一数据为最后数据
				AA=0;
		}
		retry_time=0;//将重试计数器清零
		goto bus_end;
	}
	if(SMB0STA==0x48){//从机地址+R发送成功,但接收到从机NACK应答信号
		retry_time++;
		STO=1;
		if(retry_time<RETRY_MAX){//若小于重试最大限值,则继续重试
			STA=1;
		}
		else{
			mes_M.isbuserror=1;//若大于重试最大限值,则停止总线,且将总线错误标志位置1
			retry_time=0;
			}
		goto bus_end;
	}
	if(SMB0STA==0x50){//接收到从机所发送的数据,并发送ACK应答信号
		if(mes_M.len>1)
			AA=1;//下一接收数据不是最后数据,故AA置1,以应答从机
		else{
			if(mes_M.len==1)//下一数据为最后数据
				AA=0;
		}
		XBYTE[mes_M.self_adr]=SMB0DAT;
		mes_M.self_adr++;
		mes_M.target_adr.word++;
		mes_M.len--;
		goto bus_end;
	}
	if(SMB0STA==0x58){//接收到从机所发送的最后一个数据,并发送NACK应答信号
		XBYTE[mes_M.self_adr]=SMB0DAT;
		mes_M.len=0;
		STO=1;//结束总线传输
		goto bus_end;
	}
	if(SMB0STA==0x00){//出现总线错误
		mes_M.isbuserror=1;
		mes_S.isbuserror=1;
		STO=1;
	}
bus_end:
		SI=0;
}

⌨️ 快捷键说明

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