IIC驱动代码

本文详细介绍了STM32F407芯片的IIC底层驱动实现,包括信号时序、延时控制和函数操作,对MCU开发者的应聘准备具有指导意义。
摘要由CSDN通过智能技术生成

本文章是作为学习理解的一个IIC底层驱动,是以STM32F407芯片为例子,如有问题请大佬们指点。
那么IIC在MCU开发者应聘中是必不可少的提问的一个问题,所以我在正点原子和一个大哥的例子上学习,再修改一些自己所理解的注释,方便能更容易的理解代码的意思。
在IIC底层中无非就是开始信号、结束信号、应答信号、不应答信号、发送一个字节、接收一个字节。
起始信号和停止信号时序图:

在这里插入图片描述

对于延时在正点的文章里解释的是:为了控制IIC的读写速度,通过示波器检测读写速度在250KHz内,所以一秒钟传送500Kb数据,换算一下即一个bit位需要2us,在这个延时时间内可以让器件进行获得一个稳定性的数据采集。
应答信号和非应答信号时序图:
在这里插入图片描述这里的区别就是在SCL为1时应答信号SDA线由高到低,非应答信号SDA线由低到高变化。
IIC总时序图:

从这里不难看出,当数据传输第一数据的时候SDA为高,而SCL经过一个完整的脉冲且最后一位R/W位为读写控制位,这里用到一个循环8次就可以完成读写一字节的数据了。
接下来就看看下方总结来的IIC底层驱动代码结合上面的图片来分析就很容易理解到位。

#ifdef  _MYIIC_H_
#define _MYIIC_H_
//---------------------------
//此区域用做IIC配置以STM32F407芯片为例子
#define IIC_SCL  PB8
#define IIC_SDA  PB9
#define IIC_SDA_IN  	{GPIOB->MODER& = ~(3<<(9*2)),GPIOB->MODER|= 0<<(9*2);}  //先将PB9->MODER先清零再置为输出模式 01
#define IIC_SDA_OUT		{GPIOB->MODER& = ~(3<<(9*2)),GPIOB->MODER|= 1<<(9*2);} //输入模式为00
#define IIC_SCL_H       do{GPIOB->BSRR |= (0x1 << 8);}while(0)     
#define IIC_SCL_L       do{GPIOB->BRR |= (0x1 << 8);}while(0)                                                                        
#define IIC_SDA_H       do{GPIOB->BSRR |= (0x1 << 9);}while(0)     
#define IIC_SDA_L       do{GPIOB->BRR |= (0x1 << 9);}while(0) 
#define IIC_SDA_READ     GPIOB->IDR &(1<<9)

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口			 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Write_Byte(u8 dat);		//IIC发送一个字节
u8 IIC_Read_Byte(bool ack);         //IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ack信号
void IIC_Ack(void);					//IIC发送ack信号
void IIC_nAck(void);				//IIC不发送ACK信号

#endif

#include "stm32f4xx.h"
#include "MYIIC.h"
#include "gpio.h"
#include "delay.h"
#typedef unsigned char u8;
#typedef unsigned char u16;
#define  IIC_SCL   PA_1
#define  IIC_SDA   PA_2

void IIC_Init(void)
{
	RCC->AHB1ENR|=1<<1;//使能GPIOB时钟
	GPIOB ->MODER &= (~0xF<<(8*2));         //先清零
	GPIOB ->MODER |= 10 <<(8*2);           //在为引脚PB8、PB9设置为通用的输出功能  
	GPIOB ->OTYPER &= (~(0x3 << 8));      //设置为推挽输出
	GPIOB ->OSPEEOR |=0xF <<(8*2);       //设置高速输出
	GPIOB ->PUPDR &= (~(0xF << (8*2))); //禁止上拉和下拉
	
	IIC_SCL_H;
	IIC_SDA_H;  
}
/******************************************************************************
* 函数名:        IIC_Start
* 功能描述:      IIC_Start  开始信号
******************************************************************************/
void IIC_Start(void)
{	
	IIC_SDA_OUT	;
	IIC_SCL_H;
	IIC_SDA_H;
	delay_us(2);    
	IIC_SDA_L;
	delay_us(2);
	IIC_SCL_L;
	delay_us(2);
}
/******************************************************************************
* 函数名:        IIC_Stop
* 功能描述:      IIC_Stop 结束信号
******************************************************************************/
void IIC_Stop(void)
{	
	IIC_SDA_OUT	 ;
	IIC_SDA_L;
	delay_us(2);
	IIC_SCL_H;
	delay_us(2);
	IIC_SDA_H;
	delay_us(2);
}
/******************************************************************************
* 函数名:        IIC_Ack
* 功能描述:      IIC_Ack 应答信号
******************************************************************************/
//此区域作为应答信号,不应答信号以及等待信号函数,该组信号在对于从机是否收到信号极为重要
void IIC_Ack(void)
{	
	IIC_SCL_L;
	IIC_SDA_OUT;
	IIC_SDA_L;    //应答与不应答信号主要区别的数据线的高低脉冲的区别;
	delay_us(2);
	IIC_SCL_H;      
	delay_us(2);
	IIC_SDA_L;
	delay_us(2);
}
/******************************************************************************
* 函数名:        IIC_nAck
* 功能描述:      IIC_nAck 非应答信号
******************************************************************************/
void IIC_nAck()
{	
	IIC_SCL_L;
	IIC_SDA_OUT;
	IIC_SDA_H;
	delay_us(2);
	IIC_SCL_H;
	delay_us(2);
	IIC_SDA_L;
	delay_us(2);
}
/******************************************************************************
* 函数名:        IIC_Wait_Ack
* 功能描述:      IIC master 等待应答信号
* 参数说明:      Flase,接收应答失败
*                True,接收应答成功
******************************************************************************/
//在主机发送一个字节后,从机需给主机返回一个应答信号,在此用bool类型返回,当等待应答接受成功后返回True,反之则是False
bool IIC_Wait_Ack(void)
{	
	u8 errtime=0;
	IIC_SDA_IN;
	IIC_SDA_H;
	delay_us();
	IIC_SCL_H;
	delay_us();
	while(I2C_SDA_READ)
	{
		errtime++;
		if(errtime >250)
		{
			IIC_Stop();
			return False;
		}
	}
	IIC_SCL_L;
	return True;
}
/******************************************************************************
* 函数名:        IIC_Write_Byte
* 功能描述:      发送一个字节 
******************************************************************************/
//此区域用作IIC的写和读字节
/* 时钟在低电平时候,发送器向数据线上写入数据
    时钟在高电平时候,接收器从数据线上读取数据   */
void IIC_Write_Byte(u8 dat) 
{
	
		
	u16 i ;   
	IIC_SDA_OUT	;    
	IIC_SCL_L;           //拉低时钟开始传输数据
	for(i=0;i<8;i++)    
	{
		if(dat & 0x80)    //检测最高位是否为1
		{
			IIC_SDA_H;  //当检测到有数据就把数据线拉高
		}
		else
		{
			IIC_SDA_L;
		}
		delay_us(2);
		IIC_SCL = 1;
		delay_us(2);
		IIC_SCL = 0;
		dat<< = 1;         //从左向右传递数据,因此需要移位
	}
	IIC_SDA_H;
}
/******************************************************************************
* 函数名:        IIC_Read_Byte
* 功能描述:      读取一个字节 
******************************************************************************/
u8 IIC_Read_Byte(bool ack)
{
	
	u16 i,dat=0;
	IIC_SDA_IN;
	for(i=0;i<8;i++)
	{
		dat<< = 1;
	    IIC_SCL_H;
	    delay_us(2);
		if(I2C_SDA_READ)dat++;
		IIC_SCL_L;
		delay_us(2);
	}
	if(ack == True)IIC_Ack();
	else IIC_nAck();
	return dat;
}







void AT24CXX_Init(void)
{
	IIC_Init();
}
u8 AT24CXX_Read_one_dByte(u16 ReadAddr,u8 data)
{
	IIC_Start();
	IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0xa0,写数据
	IIC_Wait_Ack();
	IIC_Send_Byte(ReadAddr%256);   //发送低地址
	IIC_Wait_Ack();	
	IIC_Start();  	 	   
	IIC_Send_Byte(0XA1);           //进入接收模式,从IIC器件读取数据			   
	IIC_Wait_Ack();	 
    temp=IIC_Read_Byte(0);		   
    IIC_Stop();    
	return temp;

}
u8 AT24XX_Write_one_Byte(u16 WriteAddr,u8 data)
{
	IIC_Start();  
	IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));    
	IIC_Wait_Ack();	   
    IIC_Send_Byte(WriteAddr%256);  ·
	IIC_Wait_Ack(); 	 						
					  		   
	IIC_Send_Byte(data);    						   
	IIC_Wait_Ack();  		    	   
    IIC_Stop();
	delay_ms(10);	 


}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小嵌_SDY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值