官方IIC从机实在用不到,经过本人研究,写了个简单可通讯的从机版本。现在发出来分享下。
从机程序:
uchar u8_My_Buffer[8]; //存储要发送的值
/***IIC初始化****/
void Init_I2C (void)
{
I2C_CR1 =0x81;//关闭时钟延展,启动IIC
I2C_CR2=0x04;
I2C_FREQR=1;
I2C_OARL=0xa0;//设备地址
I2C_OARH=0x40;
I2C_ITR=0x06;
}
/***********IIC中断服务函数*********************/
@far @interrupt void I2C_Slave_check_event(void)
{
static uchar sr1;
static uchar sr2;
static uchar sr3;
uchar tsr1,tsr2,tsr3;
if(I2C_SR1_ADDR) // 地址匹配
{
uchar erro=8;
iict=0;
I2C_DR=u8_My_Buffer[0];
tsr1=I2C_SR1;
tsr3=I2C_SR3;
iict++;
while(I2C_SR1_BTF&(erro--));
}
if(I2C_SR1_TXE) //继续发送数据
{
uchar erro=8;
I2C_DR=u8_My_Buffer[iict++];
while(I2C_SR1_BTF&(erro--));
}
if(I2C_SR2_AF)
{
I2C_SR2 &= ~I2C_SR2_AF;
}
}
/*******************************************************/
主机读取数据(模拟):
@near uchar iictemp[7];//存储读取到的数据
void SDA_out(void) //配置SDA引脚为输出
{
PB_DDR|=0x20;//PB5
PB_CR1|=0x20;//推挽输出
PB_CR2&=0xdf;
}
void SDA_in(void) //配置SDA引脚为输入
{
PB_DDR&=0xdf;//PB5
PB_CR1|=0x20;//上拉输入
PB_CR2&=0xdf;
}
void SCL_out(void) //配置SCL引脚为输出
{
PB_DDR|=0x10;//PB4
PB_CR1|=0x10;//推挽输出
PB_CR2&=0xef;
}
void SCL_in(void) //配置SCL引脚为输入
{
PB_DDR&=0xef;//PB5
PB_CR1|=0x10;//上拉输入
PB_CR2&=0xef;
}
/*起始条件*/
void Start(void)
{
SCL_out();
SDA_out();
SCL=1;
SDA=1;
Delay_us(1);
SDA=0;
Delay_us(1);
SCL=0;
}
/*停止条件*/
void Stop(void)
{
SDA_out();
SDA=0;
Delay_us(1);
SCL=1;
Delay_us(1);
SDA=1;
}
void IIC_w(uchar Idata) //写一个字节
{
uchar iici;
for(iici=0;iici<8;iici++)
{
SCL=0;
Delay_us(1);
if(Idata&0x80)
SDA=1;
else
SDA=0;
Delay_us(1);
SCL=1;
Idata<<=1;
Delay_us(1);
}
SCL=0;
}
void IIC_r(uchar* Idata) //读一个字节
{
uchar iici;
SDA=1;
SDA_in();
for(iici=0;iici<8;iici++)
{
SCL=1;
Delay_us(1);
*Idata<<=1;
if(SDAI)
*Idata|=1;
else
*Idata|=0;
Delay_us(1);
SCL=0;
Delay_us(1);
}
}
void I2C_Send_Ack(void) //发送ACK
{
SDA=0;
SDA_out();
SCL=0;
Delay_us(1);
SDA=0;
Delay_us(1);
SCL=1;
Delay_us(1);
SCL=0;
}
unsigned char I2C_Get_Ack(void) //读取ACK
{
uchar ack;
SDA=1;
SDA_in();
Delay_us(1);
SCL=1;
ack=SDAI;
Delay_us(1);
SCL=0;
SDA_out();
return ack;
}
void IICdata_Read(void) //调用该函数会读取到从机数据
{
uchar i;
Start();
IIC_w(0xa1);
if(I2C_Get_Ack())
{
Stop();
return;
}
for(i=0;i<8;i++)
{
Delay_us(1);
IIC_r(&iictemp);
if(i<7) //这里很重要,最后一位不发送ACK,自动停止通讯
I2C_Send_Ack();
}
Stop();
}
该程序存在较少的误码,加上校验位后可以稳定的通讯。
|