📄 iic_rom.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 + -