STM32_IIC协议编程

有关SPI协议编程:SPI协议

目录                                                                                                

前言

IIC子函数

IIC_Start

IIC_Stop

IIC_Wait_Ack

IIC_ACK

IIC_NACK

IIC_Send_Byte

IIC_Read_Byte

AT24C02子函数

WriteOneByte

ReadOneByte

AT24C02_Check


前言                                                                                                

I2C 总线在传送数据过程中共有三种类型信号:开始信号、结束信号和应答信号

开始信号: SCL 高, SDA 由高向低跳变,开始传送数据。

结束信号: SCL 高, SDA 由低向高跳变,结束传送数据。

应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。

SCL空闲状态为高,当为低时,开始数据传输

SDA为低-ACK(开始,高-NACK(停止

IIC子函数                                                                                        

void IIC_Init(void); //初始化 IIC 的 IO 口
void IIC_Start(void); //开始信号
void IIC_Stop(void); //停止信号
u8 IIC_Wait_Ack(void); //IIC 等待 ACK 信号
void IIC_Ack(void); //发送 ACK 信号
void IIC_NAck(void); //不发送 ACK 信号
void IIC_Send_Byte(u8 txd); //IIC 发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC 读取一个字节

IIC开始与结束时序图

START CONDITION: A high-to-low transition of SDA with SCL high is a start condition
which must precede any other command 

开始条件: SCL高和SDA从高到低的转换是一个启动条件,必须在任何其他命令之前

IIC_Start                                                                                                  

SCL高,SDA由高向低跳变,开始传送数据
void IIC_Start(void) //发送 IIC 开始信号
{
	SDA_OUT();//SDA设为输出,因为我们告诉从机,我们要开始传输
	IIC_SDA=1;
	IIC_SCL=1;//拉高,一般SCL在高电平的时候都是指示信号,只有低电平的时候是传输数据
	delay_us(4);
	IIC_SDA=0;
	IIC_SCL=0;//因为空闲状态是高电平,故拉低接收数据
}

STOP CONDITION: A low-to-high transition of SDA with SCL high is a stop condition.
After a read sequence, the stop command will place the EEPROM in a standby power
mode。
停止条件:SDA在SCL高时从低到高的转变是一个停止条件。在读取序列之后,停止命令将使EEPROM处于备用电源模式

IIC_Stop                                                                                                  

//SCL高,SDA由低向高跳变,结束传送数据
void IIC_Stop(void) //发送 IIC 停止信号
{
	SDA_OUT();
	IIC_SDA=0;
	IIC_SCL=0;
	delay_us(4);
	IIC_SCL=1;//SCL为高
	IIC_SDA=1;//SDA从低到高,结束传送
}

IIC_Wait_Ack                                                                                          

ACKNOWLEDGE: All addresses and data words are serially transmitted to and from
the EEPROM in 8-bit words. The EEPROM sends a “0” to acknowledge that it has
received each word. This happens during the ninth clock cycle.
ACKNOWLEDGE:所有地址和数据字以8位字串行地与EEPROM进行传输。EEPROM在第九个时钟周期发送一个0表示它已经接收到每个字。
等待应答信号
等待应答信号
返回值:1.接收应答失败
       0.接收应答成功
u8 IIC_Wait_Ack(void) //IIC 等待 ACK 信号
{
	u8 ucErrTime=0;
	SDA_IN();//SDA设置输入
	IIC_SDA=1;
	IIC_SCL=1;
	while(READ_SDA)	//在第九个周期时,若收到数据,E2PROM会发送一个0
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();//未接收到应答则停止IIC信号
			return 1;
		}
	}
	IIC_SCL=0;
	return 0;
}

 ACK与NACK信号 

ACKNOWLEDGE: All addresses and data words are serially transmitted to and from
the EEPROM in 8-bit words. The EEPROM sends a “0” to acknowledge that it has
received each word. This happens during the ninth clock cycle.
ACKNOWLEDGE:所有地址和数据字以8位字串行地与EEPROM进行传输。EEPROM在第九个时钟周期发送一个0表示它已经接收到每个字。
SCL从低到高,SDA低-ACK,SDA高-NACK 
等待应答信号
第九个周期接收应答

IIC_ACK                                                                                                

void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0; //SDA-低
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

IIC_NACK                                                                                               

void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1; //SDA-高
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}

IIC_Send_Byte                                                                                       

void IIC_Send_Byte(u8 txd)
{
	u8 t;
	SDA_OUT();
	IIC_SCL=0;//拉低时钟开始数据传输
	for(t=0;t<8;t++)
	{
		if(txd&0x80) //比较最高位,结果1000 0000(非0值为真)或0000 0000
			IIC_SDA=1;
		else
			IIC_SDA=0;
		txd<<=1;//左移 	   
		delay_us(2);
		IIC_SCL=1;
		delay_us(2);
		IIC_SCL=0;
		delay_us(2);
	}
}
写数据时序图

测试IIC串口是否应答
IIC_Start();
IIC_Send_Byte(0XA0);//设备地址
tmp=IIC_Wait_Ack();
IIC_Stop(); 
printf("tmp:%d\r\n",tmp);

IIC_Read_Byte                                                                                       

读数据时序图

//读1个字节,ack=1时,发送ACK,ack=0,发送nack
u8 IIC_Read_Byte(u8 ack)//IIC 读取一个字节
{
	u8 receive=0,i;
	SDA_IN();
	for(i=0;i<8;i++)
	{
		IIC_SCL=0;  //时钟线拉低,告诉从机,主机需要数据
		delay_us(2); 
		IIC_SCL=1;  //时钟线拉高,告诉从机,主机现在正在读取数据
		receive<<=1;
		if(READ_SDA)
			receive++;
		delay_us(1);
	}
	if(ack)
		IIC_Ack();
	else
		IIC_NAck();
	return receive;
}


AT24C02子函数                                                                             

void AT24C02_Init(void); //初始化 IIC
void AT24C02_WriteOneByte(u16 WriteAddr,u8 DataToWrite); //写入一个字节
u8 AT24C02_ReadOneByte(u16 ReadAddr); //读取一个字节
void AT24C02_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);//写入指定长度的数据
void AT24C02_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);//从读出指定长度的数据
u8 AT24C02_Check(void); //检查器件

WriteOneByte                                                                                        

写时序

在 AT24C02 指定地址写入一个数据
WriteAddr :写入数据的目的地址
DataToWrite:要写入的数据
void AT24C02_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
	IIC_Start();
	IIC_Send_Byte(0xA0);//总线寻址:向总线发送IIC设备地址0XA0
	IIC_Wait_Ack();
	IIC_Send_Byte(WriteAddr);//向设备发送要操作的地址	
	IIC_Wait_Ack();
	IIC_Send_Byte(DataToWrite);//发送一个字节
	IIC_Wait_Ack();
	IIC_Stop();
	delay_ms(10);//必须加延时
}

写入指定长度的数据 

在AT24C02里面的指定地址开始写入指定个数的数据
WriteAddr :开始写入的地址 对24c02为0~255
pBuffer   :数据数组首地址
NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	while(NumToWrite--)
	{
		AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
		WriteAddr++;
		pBuffer++;
	}
}

ReadOneByte                                                                                        

读时序

在 AT24C02 指定地址读出一个数据
ReadAddr:开始读数的地址
返回值 :读到的数据 
u8 AT24C02_ReadOneByte(u16 ReadAddr) //指定地址读取一个字节
{
	u8 receive = 0;
	IIC_Start();
	IIC_Send_Byte(0XA0);//设备地址
	IIC_Wait_Ack();
	IIC_Send_Byte(ReadAddr);//指定字节地址
	IIC_Wait_Ack();
	IIC_Start();	//读写方向改变时,需重新发送起始信号
	IIC_Send_Byte(0XA1);	//读写方向为1读数据	
	IIC_Wait_Ack();
	receive =IIC_Read_Byte(0);//接收一个字节,发送非应答信号	
	IIC_Stop();
	return receive;
}

读取指定长度的数据

在 AT24C02 里面的指定地址开始读出指定个数的数据
ReadAddr :开始读出的地址 对 24c02 为 0~255
pBuffer :数据数组首地址
NumToRead:要读出数据的个数,开始读取指定长度数据
void AT24C02_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	while(NumToWrite--)
	{
		AT24C02_WriteOneByte(WriteAddr,*pBuffer);
		WriteAddr++;
		pBuffer++;
	}
}

AT24C02_Check                                                                                    

检测硬件上是否有AT24C02或是否可读写,一般放在程序开头

u8 AT24C02_Check(void)//检查AT24C02是否可读写
{
	AT24C02_WriteOneByte(255,0XFF);//AT24C02存储容量为256个字节,往最后一个地址写入一个字节0xFF
	u8 tmp = AT24C02_ReadOneByte(255);
	if(tmp == 0XFF)
		return 0;
	else 
		return 1;
}

测试AT24C02是否可读写
AT24C02_WriteOneByte(0x55,122); //向0X55地址写入数据122
tmp = AT24C02_ReadOneByte(0x55);//读取0X55地址的数据
printf("tmp:%d\r\n",tmp);//串口打印测试

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值