STM32学习笔记之IIC操作

 STM32中的IIC可分为硬件IIC和软件IIC,但实际应用中更倾向于软件IIC。即可自行指定两个端口为数据线和时钟线进行IIC的模拟。但是相对于52单片机的IIC协议,STM32的IIC时序操作完全一致,唯一的差别在与STM32需要对端口的信号输入输出端口进行配置。

IIC总线协议之起始信号: IIC的启动实在SDA和SCL均为高电平期间,SDA拉低后SCL接着拉低。

void IIC_Start(void)
{
		SDA_OUT();    // 配置SDA为输出模式
		SDA_SET;
		SCL_SET;        // 初始状态SDA、SCL均为高电平
		delay_us(5);
		SDA_CLR;        // SDA拉低
		delay_us(5);    // 延时5us以上
		SCL_CLR;
}

      IIC总线协议之停止信号:IIC的停止是发生在SCL为高电平期间,SDA突然拉高。

void IIC_Stop(void)
{
	SDA_OUT();
	SDA_CLR;
	SCL_SET;
	delay_us(5);
	SDA_SET;
	delay_us(5);
}

  IIC总线协议之伪造应答:IIC从器件的应答主要是发生在SCL为高电平期间,SDA为低电平,延时5us以后SCL拉低。 

void IIC_Ack(void)
{
	SDA_OUT();
	SDA_CLR;
	SCL_SET;
	delay_us(5);
	SCL_CLR;
	delay_us(5);
}

IIC总线协议之伪造非应答:IIC器件的非应答是指在SCL为高电平期间,SDA也为高电平,延时5us以后SCL拉低。 

void IIC_NoAck(void)
{
	SDA_OUT();
	SDA_SET;
	SCL_SET;
	delay_us(5);
	SCL_CLR;
	delay_us(5);
}

     IIC总线协议之写单字节:IIC发送数据时从高到低位发送。

void IIC_WriteByte(unsigned char data)
{
	unsigned char i ;
			SDA_OUT();
	for(i=0;i<8;i++)
	{
		if((data<<i)&0x80)	// 先发送高位数据
				SDA_SET;
		else
				SDA_CLR;
	//	__Nop();        //确保数据线上电平稳定
		SCL_SET;	// 时钟线高电平期间,数据线上数据稳定有效
		delay_us(5);
		SCL_CLR;	// 时钟线为低电平期间,开始发送数据
	}
}

    IIC总线协议之读单字节:IIC读取数据时也是先读取高位。 

unsigned char IIC_ReadByte(void)
{
	unsigned char i,dat=0;
	SDA_IN();
	SDA_SET;
	for(i=0;i<8;i++)
	{
		SCL_CLR;
		delay_us(5);
		SCL_SET;
		dat<<=1;	
		if(SDA)
			dat+=1;
	}	
	SCL_CLR;
	delay_us(5);
	return(dat);
}

  IIC总线协议之写数据:按照总线协议发送。 

void IIC_WriteData(unsigned char add,unsigned char dat)
{
	IIC_Start();                // 开启IIC总线
	IIC_WriteByte(0XA0);        // 写入从器件地址
	IIC_Ack();                  // 伪造应答
	IIC_WriteByte(add);         // 写入从器件内存地址
	IIC_Ack();                  // 伪造应答
	IIC_WriteByte(dat);         // 写入数据
	IIC_Ack();                  // 伪造应答
	IIC_Stop();                 // 停止IIC总线
}

  IIC总线协议之读数据:在读取时首先发送从期间地址和要读取的内存地址,然后重新启动总线读取数据。

unsigned char IIC_ReadData(unsigned char add)
{
	unsigned char temp=0;
	IIC_Start();
	IIC_WriteByte(0XA0);
	IIC_Ack();
	IIC_WriteByte(add);
	IIC_Ack();
	
	IIC_Start();
	IIC_WriteByte(0XA1);        // 从期间读操作
	IIC_Ack();
	temp=IIC_ReadByte();        // 读取值
	SCL_CLR;
	IIC_NoAck();
	IIC_Stop();
	return temp;
}

     当然在这些操作之前,还需要配置相关的IO口。

void IIC_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct ;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7 ;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP ;	           // 推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);	            //先拉高
}

   除此之外,还有关于端口的宏定义。

#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

#define SCL_SET	 GPIO_SetBits(GPIOB,GPIO_Pin_6)
#define SCL_CLR	 GPIO_ResetBits(GPIOB,GPIO_Pin_6)

#define SDA_SET	 GPIO_SetBits(GPIOB,GPIO_Pin_7)
#define SDA_CLR	 GPIO_ResetBits(GPIOB,GPIO_Pin_7)

#define SDA GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)

      最后当然是我们验证对24C02的数据读写结果是否正确。 

int main(void)
 {	 
	u8 flag=0 ;
	 
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(9600);	 	//串口初始化为115200
	LCD_Init();
	POINT_COLOR=RED;
	 
	IIC_Config();                      //IIC相关端口配置
	flag=IIC_ReadData(0x00);             // 读取之前开机次数
	flag++;                            // 加1次
	IIC_WriteData(0x00,flag);	         // 将当前开机启动次数写进去
	 printf("%d",flag);                // 串口显示当前开机次数

	 while(1) 
	{		 
		POINT_COLOR=RED;	  
		LCD_ShowString(30,40,210,16,16,"This is the"); 
		LCD_ShowNum(124,40,flag,2,16);
	  LCD_ShowString(140,40,210,24,16,"th Start The System");   	
		LED0=!LED0;				   		 
		delay_ms(1000);	
	} 
}

到此,就完成了关于IIC协议操作24C02的操作,实现开机记录次数。 




 

猜你喜欢

转载自blog.csdn.net/qq_37425883/article/details/80214454