STM32 软件模拟IIC 标准库

 

#define SCL   PBout(8)
#define SDA   PBout(9)
#define SDA_R PBin(9)

#define IIC_Init  IIC_Config

void IIC_Config(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_WriteByte(unsigned char WData);
unsigned char IIC_ReadByte(void);
void IIC_WriteAck(char Ack);
char IIC_ReadAck(void);

void IIC_Read_One_Byte(u8 daddr,u8 addr,u8* data);
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
void IIC_ReadBytes(u8 deviceAddr, u8 writeAddr,u8* data,u8 dataLength);
void IIC_Config(void)
{
	//SCL 固定模式 输出  SDA 可变
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIOInitStruct;
	GPIOInitStruct.GPIO_Pin 	= GPIO_Pin_8 | GPIO_Pin_9;
	GPIOInitStruct.GPIO_Mode 	= GPIO_Mode_OUT;
	GPIOInitStruct.GPIO_OType 	= GPIO_OType_OD;//开漏
	GPIOInitStruct.GPIO_Speed 	= GPIO_Low_Speed;
	GPIOInitStruct.GPIO_PuPd  	= GPIO_PuPd_UP;
	GPIO_Init(GPIOB,&GPIOInitStruct);//这里才是寄存器配置

}


static void IIC_SDAConfig(GPIOMode_TypeDef Mode)
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIOInitStruct;
	GPIOInitStruct.GPIO_Pin 	= GPIO_Pin_9 ;//SDA
	GPIOInitStruct.GPIO_Mode 	= Mode;
	GPIOInitStruct.GPIO_OType 	= GPIO_OType_OD;
	GPIOInitStruct.GPIO_Speed 	= GPIO_Low_Speed;
	GPIOInitStruct.GPIO_PuPd  	= GPIO_PuPd_UP;
	GPIO_Init(GPIOB,&GPIOInitStruct);//这里才是寄存器配置
}



void IIC_Start(void)
{
	//SDA配置为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);

	SCL = 1;
	SDA = 1;
	delay_us(5);
	
	SDA = 0;//SCL的高电平期间产生了下降沿
	delay_us(5);
	SCL = 0;
}

void IIC_Stop(void)
{
	IIC_SDAConfig(GPIO_Mode_OUT);
	SCL = 0;
	SDA = 0;
	SCL = 1;
	delay_us(5);
	SDA = 1;
}



//标准IIC 速度 100Khz
void IIC_WriteByte(unsigned char WData)
{
	
	//SDA配置为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);
	
	for(int i=0;i<8;i++)
	{
		SCL = 0;//低电平期间改变SDA发送1bit
		delay_us(2);
		if(WData & (0x80>>i)) 
			SDA = 1;
		else
			SDA = 0;
		delay_us(3);
		
		SCL = 1;//高电平期间给从机接收该位
		delay_us(5);
	}
	SCL = 0;
}

//IIC_WriteByte(0x12);//SDA 输出模式 ODR  拉低 SDA = 0

//if(1 ==  IIC_ReadAck())//SDA 输入模式 外部电路决定 SDA = 1;
//{
//	//
//}

unsigned char IIC_ReadByte(void)
{
	unsigned char RData = 0;
	//SDA配置为输入模式
	IIC_SDAConfig(GPIO_Mode_IN);
	
	for(int i=0;i<8;i++)
	{
		SCL = 0;//低电平 是从机发数据的时间
		delay_us(5);
		
		
		SCL = 1;//高电平期间读取SDA 接收1bit数据
		delay_us(2);
		if(SDA_R)
			RData |= (0x80>>i);//数字1  数字0跳过
		delay_us(3);
	}
	SCL = 0;
	
	return RData;
}




//产生ACK应答
void IIC_Ack(void)
{
	SCL=0;
	IIC_SDAConfig(GPIO_Mode_OUT);
	SDA=0;
	delay_us(2);
	SCL=1;
	delay_us(2);
	SCL=0;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	SCL=0;
	IIC_SDAConfig(GPIO_Mode_OUT);
	SDA=1;
	delay_us(2);
	SCL=1;
	delay_us(2);
	SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	IIC_SDAConfig(GPIO_Mode_OUT);	    
    SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		SCL=1;
		delay_us(2); 
		SCL=0;	
		delay_us(2);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	IIC_SDAConfig(GPIO_Mode_IN);//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        SCL=0; 
        delay_us(2);
		SCL=1;
        receive<<=1;
        if(SDA_R)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}











//T = 10us
//f = 1000000us/10us = 100KHz

//主机发送1bit应答
void IIC_WriteAck(char Ack)
{
	//SDA 为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);
	
	SCL = 0;
	delay_us(2);
	SDA = Ack;
	delay_us(3);
	
	SCL = 1;
	delay_us(5);
	
	SCL = 0;
}


//主机发送1bit应答
char IIC_ReadAck(void)
{
	char Ack=1;
	//SDA设置为输入模式
	IIC_SDAConfig(GPIO_Mode_IN);
	
	SCL = 0;
	delay_us(5);
	
	SCL = 1;
	delay_us(2);
	if(SDA_R==0)
		Ack = 0;
	delay_us(3);
	
	
	SCL = 0;
	return Ack;
}


//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	IIC_SDAConfig(GPIO_Mode_IN);      //SDA设置为输入  
	SDA=1;delay_us(1);	   
	SCL=1;delay_us(1);	 
	while(SDA_R)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL=0;//时钟输出0 	   
	return 0;  
}

void IIC_ReadBytes(u8 deviceAddr, u8 writeAddr,u8* data,u8 dataLength)
{		
	u8 i;	
    IIC_Start();  

	IIC_Send_Byte(deviceAddr);	    //发送写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(writeAddr);
	IIC_Wait_Ack();
	IIC_Send_Byte(deviceAddr|0X01);//进入接收模式			   
	IIC_Wait_Ack();
	
	for(i=0;i<dataLength-1;i++)
	{
		data[i] = IIC_Read_Byte(1);
	}		
	data[dataLength-1] = IIC_Read_Byte(0);	
    IIC_Stop();//产生一个停止条件 
	delay_ms(10);	 
}

void IIC_Read_One_Byte(u8 daddr,u8 addr,u8* data)
{				  	  	    																 
    IIC_Start();  
	
	IIC_Send_Byte(daddr);	   //发送写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(addr);//发送地址
	IIC_Wait_Ack();		 
	IIC_Start();  	 	   
	IIC_Send_Byte(daddr|0X01);//进入接收模式			   
	IIC_Wait_Ack();	 
    *data = IIC_Read_Byte(0);		   
    IIC_Stop();//产生一个停止条件	    
}

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data)
{				   	  	    																 
    IIC_Start();  
	
	IIC_Send_Byte(daddr);	    //发送写命令
	IIC_Wait_Ack();
	IIC_Send_Byte(addr);//发送地址
	IIC_Wait_Ack();	   	 										  		   
	IIC_Send_Byte(data);     //发送字节							   
	IIC_Wait_Ack();  		    	   
    IIC_Stop();//产生一个停止条件 
	delay_ms(10);	 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值