#define IIC_SDA P16
#define IIC_SCL P15
#define READ_SDA P1CON &= 0xbf
#define SDA_OUT() P1CON |= 0x40,P1PH |=0x40
#define SDA_IN() P1CON &= 0xbf,P1PH |=0x40
#define ADDR_PLF2105D 0x50
void delay_us( uint us)
{
uint x;
for(x=us;x>0;x--);
}
void delay_ms(u16 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(3200);
}
void IIC_Init(void)
{
P1CON = 0xFF; //SDA与SCL设置为推挽输出模式
P1PH = 0x00; //SDA与SCL的上拉电阻打开
IIC_SDA = 1; //IIC_SDA 置高电平
IIC_SCL = 1; //IIC_SCL 置低电平
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA = 1;
IIC_SCL = 1;
delay_us(32);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(32);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(32);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(32);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uchar IIC_Wait_Ack(void)
{
uchar ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;
delay_us(6);
IIC_SCL=1;
delay_us(6);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(6);
IIC_SCL=1;
delay_us(6);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(6);
IIC_SCL=1;
delay_us(6);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(uchar txd)
{
uchar t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(6); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(6);
IIC_SCL=0;
delay_us(6);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uchar IIC_Read_Byte(uchar ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(32);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(16);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
//IIC连续写
//addr:器件地址
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
// 其他,错误代码
uchar IIC_Write_Len(uchar addr,uchar len,uchar *buf)
{
uchar i;
IIC_Start();
IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()) //等待应答
{
IIC_Stop();
return 1;
}
for(i=0;i<len;i++)
{
IIC_Send_Byte(buf[i]); //发送数据
if(IIC_Wait_Ack()) //等待ACK
{
IIC_Stop();
return 1;
}
}
IIC_Stop();
return 0;
}
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
// 其他,错误代码
uchar IIC_Read_Len(uchar addr,uchar len,uchar *buf)
{
IIC_Start();
IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令
IIC_Wait_Ack(); //等待应答
delay_ms(5);
while(len)
{
if(len==1) *buf=IIC_Read_Byte(0);//读数据,发送nACK
else *buf=IIC_Read_Byte(1); //读数据,发送ACK
len--;
delay_us(64);
buf++;
}
IIC_Stop(); //产生一个停止条件
return 0;
}
本人新手初次使用赛元模拟IIC,原先是利用STM32F103来模拟IIC,后移植过来 发现SDA_OUT();似乎并未起作用
通过逻辑分析仪,只执行void IIC_Ack(void)得到的波形图如下图
channel2 3 是在stm32 上可以用的IIC应答时序
SDA SCL是移植在赛元的IIC时序
小白求解
|