|
大家好,我现在用smbus(I2C)总线进行两个C8051F系列单片机的通讯。单片机中有控制逻辑模块,不需要自己写驱动程序。
我设置的模式是主器件发送,从器件接受。
我现在的问题是,发送数据只能对0确认,其他的数,字符一概不确认,不知是什么原因啊?
调试好几周了,没有结果,很着急。谢谢大家帮忙啊!
这是主发送器的程序:
//-------------------------
//c8051f410_smbus_master.c
//-------------------------
//*********文件包含***********
#include //特殊寄存器地址表声明文件
//********全局常量声明********
#define sysclk 3686400
#define smb_frequency 10000
#define write 0x00
#define read 0x01
#define slave_addr 0xF0
#define smb_start 0xE0
#define already_trans 0xC0
#define receive_data 0x80
//********全局变量*********
unsigned char pdata array _at_ 0x0000;
unsigned char smb_data_in;
unsigned char smb_data_out;
unsigned char target;
bit smb_busy;
bit smb_rw;
unsigned long num_errors;
sfr16 TMR3RL =0x92;
sfr16 TMR3 =0x94;
sbit SDA =P0^0;
sbit SCL =P0^1;
//*********函数原形**********
void config(void);
void smbus_init(void);
void smbus_ISR(void);
void Timer3_ISR(void);
void smb_write(void);
void t0_wait_ms(unsigned char ms);
//---------------------------
// 主程序
//---------------------------
void main(void)
{
unsigned char i;
PCA0MD &= ~0x40; //禁止看门狗
//**********如果由于不恰当的复位或错误,从机将SDA信号拉为低电平
// 提供一个时钟脉冲使从机跳出当前状态,释放SDA***********
while(!SDA)
{
XBR1=0x40; //使能交叉开关
SCL=0;
for(i=0;i<255;i++);
SCL=1;
while(!SCL);
for(i=0;i<10;i++);
XBR1=0x00; //禁止交叉开关
}
config();
smbus_init();
EIE1 |=0x01;
EA=1;
//********开始测试********
array=2;
num_errors=0;
while(1)
{
smb_data_out=array;
target=slave_addr;
smb_write();
while(smb_busy);
t0_wait_ms(1);
}
}
//-----------------------
// 函数块
//-----------------------
void config(void)
{
//********端口配置********
P1MDIN &= ~0x03; //配置XTAL1和XTAL2为模拟输入
P1SKIP |= 0x03;
P1 |= 0x03;
XBR0=0x0D; //时钟、SMBUS、uart均连接到io端口引脚
XBR1=0x40; //使能交叉开关
P0 =0xff;
P0MDOUT=0x00; //漏极开路
//*********振荡器配置**********
OSCXCN=0x66;
t0_wait_ms(1);
while(!(OSCXCN & 0x80));
RSTSRC=0x06;
CLKSEL=0x31;
OSCICN=0x00;
//**********定时器1配置**********
#if((sysclk/smb_frequency/3)<255)
#define scale 1
CKCON |=0x08; //系统时钟
#elif((sysclk/smb_frequency/4/3)<255)
#define scale 4
CKCON |=0x01;
CKCON &=~0x0A; //系统时钟4分频
#endif
TMOD=0x20; //8位自动重装载
TH1= -(sysclk/smb_frequency/scale/3);
TL1=TH1;
TR1=1; //启动定时期T1
//*********定时器3配置***********
TMR3CN=0x00; //16位自动重装载,中断禁止
CKCON &=~0x40; //系统时钟12分频
TMR3RL= -(sysclk/12/40); //????
TMR3=TMR3RL;
EIE1 |=0x80; //定时器3中断使能
TMR3CN |=0x40; //打开定时器3
}
void smbus_init(void)
{
SMB0CF=0x5D;
SMB0CF |=0x80;
}
void t0_wait_ms(unsigned char ms)
{
TCON &= ~0x30; //停止定时器0清中断标志
TMOD &= ~0x0f;
TMOD &= ~0x01; //16位模式
CKCON |=0x04; //系统时钟
while(ms){
TR0=0;
TH0= -(sysclk/1000>>8); //??????
TL0= -(sysclk/1000); //??????
TF0=0;
TR0=1;
while(!TF0);
ms--;
}
TR0=0;
}
void smbus_ISR(void) interrupt 7
{
bit fail=0;
static bit addr_send=0;
if(ARBLOST==0)
{
switch(SMB0CN & 0xF0)
{
case smb_start:
SMB0DAT=target;
SMB0DAT &=0xFE;
SMB0DAT |=smb_rw;
STA=0;
addr_send=1;
break;
case already_trans:
if(ACK)
{
if(addr_send)
{
addr_send=0;
if(smb_rw==write)
{
SMB0DAT=smb_data_out;
}
else{}
}
else
{
STO=1;
smb_busy=0;
}
}
else
{
STO=1;
STA=1;
smb_busy=0;
num_errors++;
}
break;
case receive_data:
smb_data_in=SMB0DAT;
smb_busy=0;
ACK=0;
STO=1;
break;
default:
fail=1;
break;
}
}
else
{
fail=1;
}
if(fail)
{
SMB0CF &=~0x80;
SMB0CF |=0x80;
STA=0;
STO=0;
ACK=0;
smb_busy=0;
fail=0;
num_errors++;
}
SI=0;
}
void Timer3_ISR(void) interrupt 14
{
SMB0CF &=~0x80;
SMB0CF |=0x80;
TMR3CN &=~0x80;
STA=0;
smb_busy=0;
}
void smb_write(void)
{
while(smb_busy);
smb_busy=1;
smb_rw=0;
STA=1;
}
//-------------------------
// End of file
//-------------------------
|
|