单片机学习之IIC协议用24C02连续保存读取数据

刚学单片机C语言,记录学习IIC协议用24C02连续保存读取数据成功:

1、根据24C02的数据手册先画流程图,如下:

2、在.H头文件中进行 GPIO脚位定义与初始化:

sbit	IO_SDA		=P1^0;        //数据线
sbit	IO_SCL		=P1^1;        //时钟线

#define    IO_SDA_L		IO_SDA=0;		// 数据线SDA输出低
#define    IO_SDA_H		IO_SDA=1;		// 数据线SDA输出高

#define    IO_SCL_L		IO_SCL=0;		// 时钟线SCL输出低
#define    IO_SCL_H		IO_SCL=1;		// 时钟线SCL输出高

#define    IO_SDA_inport	P1M0=0x68;		//引脚输入模式
#define    IO_SDA_outport	P1M0=0xC0;		//引脚输出模式
#define    IIC_IO_INIT		{P1M0=0xC0; P1M1=0xC0;IO_SCL_H; IO_SDA_H; }	//IO口初始化

        

3、对着流程图和数据手册开始写代码,一步步的分解:

        2.1、先来起始信号,IIC协议的起始信号定义 ::时钟线保持高电平期间 数据线电平从高到低的跳变作为 I 2 C 总线的起始信号。.C文件中的代码如下:

void   IIC_start()		//起始信号:SCK高电平时,SDA由高变低
{
	IIC_IO_INIT;		//io口初始化 SDA输出高 SCK输出高
	delay5us();
	IO_SDA_L;			
	delay5us();
}

   2.2、延时子程序的代码如下,会多次调用,先写出来。

//========================================================================
// 描述: 延迟5微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay5us()		//@16.000MHz
{
	unsigned char i;

	i = 26;
	while (--i);
}

2.3、有了起始信号,就有停止信号,IIC协议的停止信号定义 :时钟线保持高电平期间 数据线电平从低到高的跳变作为 I 2 C 总线的停止信号。代码如下:

/************************************************************************
函 数:停止信号
返 回:
说 明:读写取完数据后主机发送停止信号
*************************************************************************/
void   IIC_stop()		//停止信号:SCK高电平时,SDA由低变高
{
	IO_SDA_outport;
	IO_SDA_L;
	delay5us();				
	IO_SCL_H;			
	delay5us();
	IO_SDA_H;			
	delay5us();		
}

2.4、再来应答信号,根据IIC协议的应答信号定义:I 2 C 总线数据传送时 每成功地传送一个字节数据后 接收器都必须产生一个应答信号 应答的器件在第 9 个时钟周期时将 SDA 线拉低 表示其已收到一个 8 位数据。 代码如下:

/************************************************************************
函 数:接收方发送应答信号
返 回:
说 明:连续读数据时,接收方要发送应答信号,从机才发送下一个数据
*************************************************************************/
void   IIC_ACK()		//	发送应答信号
{
	IO_SCL_L;
	delay5us();	
	IO_SDA_outport;
	IO_SDA_L;
	IO_SCL_H;	
	delay5us();
	IO_SCL_L;
	IO_SDA_inport;
}

2.5、有了应答信号, 就会有等待应答信号(也就是接收应答信号),有返回值的子函数,用于判断24C02是否在空闲状态,代码如下:

/************************************************************************
函 数:unsigned char   Waite_ASK()  等待IIC的应答信号
返 回:0 无应答,1 有应答
说 明:等待从机的应答信号
*************************************************************************/
unsigned char   Waite_ASK()		// 等待IIC的应答信号
{
	IO_SCL_L;
	IO_SDA_inport;					//SDA脚输入模式
	delay5us();
	IO_SCL_H;
	delay5us();	
	if (IO_SDA) 					
	{
		IO_SCL_L;
		IO_SDA_outport;
		IO_SDA_L;			
		IO_SCL_L;
		return 0;				//无应答,返回0
	}
	else
	{
		IO_SCL_L;				 
		IO_SDA_outport;
		IO_SDA_L;			
		IO_SCL_L;
		return 1;			//被拉低,有应答 返回1
	}
}

3、 接下来就是读写数据了。

        3.1、先写发送一个字节的子函数,注意,是高位先发,代码如下:

/************************************************************************
函 数:主机MCU发送一个字节
输 入:r_data  要发送的数据
说 明:高位先发
1、发送完后要等待从机的应答信号
*************************************************************************/
void	IIC_SendByte(unsigned char r_data)
{
	unsigned char r_cnt=0;
	IO_SDA_outport;						// SDA脚输出模式
	for (r_cnt=0; r_cnt<8; r_cnt++ ) 
	{
		IO_SCL_L;
		delay5us();
		if (r_data & 0x80) 
		{
			IO_SDA_H;		//发送1
		}
		else
		{
			IO_SDA_L;		// 发送0
		}
		delay5us();
		IO_SCL_H;				
		delay5us();
		r_data<<=1;
	}

	IO_SCL_L;
	
}

        3.2、有发送,也有接收数据,注意,是高位先收,再来一个接收数据的代码如下:

/************************************************************************
函 数:主机MCU接收一个字节
返 回:r_data  接收到的数据
说 明:高位先收
1、
*************************************************************************/
unsigned char IIC_ReceiveByte()
{
	unsigned char r_cnt=0;
	unsigned char r_data=0;
	
	IO_SDA_inport;
	for (r_cnt=0; r_cnt<8; r_cnt++) 
	{
		IO_SCL_L;
		delay5us();
		IO_SCL_H;
		r_data<<=1;				//左移1位		
		if (IO_SDA) 				// 高为1(逻辑或置1),低为0(移位就是0)
		{
			r_data |= 0x01;		//最低位置1
		}
	}
	IO_SCL_L;	
	return	r_data;					//返回数据
}

4、到这里子函数都写完了,下一步就是按照上图的流程进行组合,完成一个完整的数据读取和保存。

4.1、先来个写数据保存的程序,有保存才能读取到数据, 先定义全局的两个数组,下面是连续保存4个字节的数据,保存的起始地址是0x10 ,  用指针很好玩哦,多多使用指针,让逻辑结构更加清晰,第1次使用goto语句(goto语句有使用限制,最好使用在函数内哦)代码如下:

/***************** 函数的变量与位定义 ***********************************/

unsigned char data arr_IIC_RecevieData[4]={0};	//接收数组
unsigned char data arr_IIC_SendData[4]={0};		//发送数组


/************************************************************************
函 数:IIC 写操作
输 入:*Pw -->要保存的数据, r_Sendcnt---> 保存数据的次数
返 回:无
说 明:
1、发送起始信号和从器件地址  addr =0xA0
2、发送要写入数据的地址单元 write_addr 从0x00 开始到0xFF
3、发送要写的数据 r_data
4、查询应答信号,有继续发送,无就退出循环
4、如继续写入数据,继续发送数据,否则就发送停止信号
*************************************************************************/
void   EEPROM_WriteByte(unsigned char data *Pw, unsigned char r_Sendcnt)
{	//定义指向data区的无符号字符型指针变量
	unsigned char cnt;
	IIC_start();							//起始信号
	IIC_SendByte(0xA0);				//发送从器件地址
	if (!(Waite_ASK())) 					//查询应答信号
	{
		P06=0;						//测试指示灯
		goto IIC_Write_Quit;			// 无应答退出
	}
	IIC_SendByte(0x10);				//发送写保存数据的地址
	Waite_ASK();						//发送完一个字节要等待应答信号		
	for(cnt=0; cnt<r_Sendcnt;cnt++)	//连续发送
	{
		IIC_SendByte(*Pw);				//发送要保存的数据
		Waite_ASK();					//发送完一个字节要等待应答信号		
		Pw++;							//坑点-->连续存储的数据个数(r_Sendcnt)必须是2的N次方。
	}									//24C02 连续个数不能超16个
	
IIC_Write_Quit:	
	IIC_stop();							//停止信号
}

4.2、存储完数据后,再进行读取,注意,保存数据后,最少要过5MS后才能读取哦,这里也使用了指针和goto语句。读取代码如下:

/************************************************************************
函 数:IIC 读操作
输 入:r_Readcnt--> 读取数据的次数
返 回:unsigned char
说 明:
1、发送起始信号和从器件伪写操作地址 24C02  addr =0xA0 
2、发送要读取数据的地址 write_addr 从0x00 开始到0xFF
3、再次发送起始信号,发送从器件读操作 	24C02  addr =0xA1
4、查询从器件应答信号
5、如继续读取数据,应答。
6、不继续读取数据,不应答, 再发送停止信号。
7、保存数据
*************************************************************************/
void EEPROM_ReadByte(unsigned char r_Readcnt)
{	
	unsigned char cnt;
	unsigned char data *Pr=arr_IIC_RecevieData;		//读取数据保存的地址
	IIC_start();
	IIC_SendByte(0xA0);				//发送从器件伪写操作地址
	if (!(Waite_ASK())) 					//查询应答信号
	{
		goto IIC_Read_Quit;			// 无应答退出
	}
		
	IIC_SendByte(0x10);				//发送要读取数据的地址
	Waite_ASK();						//发送完一个字节要等待应答信号		
	IIC_start();			
	IIC_SendByte(0xA1);				//发送读操作地址
	Waite_ASK();						//发送完一个字节要等待应答信号
				
	for(cnt=0; cnt<r_Readcnt;cnt++)	//连续接收
	{	
		 *Pr= IIC_ReceiveByte();
		  Pr++;
		IIC_ACK();						// 连续接收需发送应答信号后才能接收下一个数据
	}
	
IIC_Read_Quit:		
	IIC_stop();							//停止信号
}

5、 到这里就写完了, 下面到主循环里面去验证一下吧,要保存的数据初始化=0,每200ms 加1,并存入24C02, 然后每过230ms就去读取一次, 读取到的数据通过串口发送出去。

void main()
{

	CLKSWR = 0x51;		//选择内部高频RC为系统时钟,2分频,Fosc=16MHz
	CLKDIV = 0x01;		//1分频得到Fcpu=16MHz  指令周期Tcpu=1/16us = 0.0625us

	WDTC = B00010011;	//看门狗初始化,
	WDTCCR = 0xFF;

	timer0_int();			//定时器0初始化;
	gpio_init();				//IO口初始化;
	P06=1;

	while(1)
	{	
		WDTC |= 0x10;			//看门狗清0 按位或

		if (F_200ms) 
		{
			P04=~P04;			//状态指示灯
			F_200ms=0;							//200ms保存一次
			arr_IIC_SendData[0]++;					//4个数据自动加1,验证保存的有效性
			arr_IIC_SendData[1]++;
			arr_IIC_SendData[2]++;
			arr_IIC_SendData[3]++;			
			EEPROM_WriteByte(&arr_IIC_SendData,4);	//保存4个数据
			
		}

		if(F_230ms)
		{
			P05=~P05;			//状态指示灯
			F_230ms=0;							//间隔230ms 读取和发送串口数据
			EEPROM_ReadByte(4);						//读出数据4个数据
			cont_uart_TxD(&arr_IIC_RecevieData,4);		//串口发送4个数据
		}
		
	 }
}

6、 看看串口发送出来的数据, 完全是对的上的。哦耶。享受小小成功的喜悦。

  加油,加油,越努力越,,,,,,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值